En mis artículos anteriores cubrí los diversos aspectos de Elixir, un moderno lenguaje de programación funcional. Hoy, sin embargo, me gustaría alejarme del lenguaje en sí y discutir un marco MVC muy rápido y confiable llamado Phoenix que está escrito en Elixir.
Este marco surgió hace casi cinco años y ha recibido cierta tracción desde entonces. Por supuesto, todavía no es tan popular como Rails o Django, pero tiene un gran potencial y me gusta mucho..
En este artículo vamos a ver cómo introducir I18n en las aplicaciones de Phoenix. Que es I18n, ¿usted pregunta? Bueno, es un numeronimo que significa "internacionalización", ya que hay exactamente 18 caracteres entre la primera letra "i" y la última "n". Probablemente, también has conocido a un L10n numeronimo que significa "localización". Los desarrolladores en estos días son tan perezosos que ni siquiera pueden escribir un par de caracteres adicionales, eh?
La internacionalización es un proceso muy importante, especialmente si prevé que la aplicación sea utilizada por personas de todo el mundo. Después de todo, no todos saben inglés bien, y hacer que la aplicación se traduzca al idioma nativo de un usuario da una buena impresión.
Parece que el proceso de traducir las aplicaciones de Phoenix es algo diferente de, por ejemplo, la traducción de las aplicaciones de Rails (pero bastante similar al mismo proceso en Django). Para traducir las aplicaciones de Phoenix, utilizamos una solución bastante popular llamada Gettext, que ya existe desde hace más de 25 años. Gettext funciona con tipos especiales de archivos, a saber, PO y POT, y admite funciones como el alcance, la pluralización y otras funciones..
Entonces, en esta publicación, les explicaré qué es Gettext, en qué se diferencia el PO del POT, cómo localizar los mensajes en Phoenix y dónde almacenar las traducciones. También veremos cómo cambiar la configuración regional de la aplicación y cómo trabajar con reglas de pluralización y dominios..
Empezamos?
Gettext es una herramienta de internacionalización de código abierto probada en la batalla que Sun Microsystems introdujo inicialmente en 1990. En 1995, GNU lanzó su propia versión de Gettext, que ahora se considera la más popular (la última versión fue 0.19.8 en El momento de escribir este artículo). Gettext se puede utilizar para crear sistemas multilingües de cualquier tamaño y tipo, desde aplicaciones web hasta sistemas operativos. Esta solución es bastante compleja, y no vamos a discutir todas sus características, por supuesto. La documentación completa de Gettext se puede encontrar en gnu.org.
Gettext le proporciona todas las herramientas necesarias para realizar la localización y presenta algunos requisitos sobre cómo deben nombrarse y organizarse los archivos de traducción. Se utilizan dos tipos de archivos para alojar traducciones: correos y mes.
correos (Objeto Portátil) los archivos almacenan las traducciones de las cadenas dadas, así como las reglas de pluralización y los metadatos. Estos archivos tienen una estructura bastante simple y pueden ser fácilmente editados por un humano, por lo que en este artículo los mantendremos. Cada archivo PO contiene traducciones (o parte de las traducciones) para un solo idioma y debe almacenarse en un directorio que lleva el nombre de este idioma: en, fr, Delaware, etc.
mes (Objeto de máquina) los archivos contienen datos binarios que no deben ser editados directamente por un humano. Es más difícil trabajar con ellos, y discutirlos está fuera del alcance de este artículo..
Para hacer las cosas más complejas, también hay POT (Plantilla de Objeto Portátil) archivos. Aloja solo cadenas de datos para traducir, pero no las traducciones en sí. Básicamente, los archivos POT se usan solo como planos para crear archivos PO para varias configuraciones regionales.
Bien, ahora vamos a practicar! Si desea seguir adelante, asegúrese de haber instalado lo siguiente:
Cree una nueva aplicación de muestra sin una base de datos ejecutando:
mezcla phx.new i18ndemo --no-ecto
--no-ecto
dice que la base de datos no debe ser utilizada por la aplicación (Ecto es una herramienta para comunicarse con la base de datos en sí). Tenga en cuenta que el generador puede requerir un par de minutos para preparar todo.
Ahora usa discos compactos
ir a la recién creada i18ndemo
Carpeta y ejecute el siguiente comando para arrancar el servidor:
mezclar phx.server
A continuación, abra el navegador y navegue hasta http: // localhost: 4000
, donde deberías ver un "¡Bienvenido a Phoenix!" mensaje.
Lo interesante de nuestra aplicación Phoenix y, específicamente, el mensaje de bienvenida es que Gettext ya se está utilizando de forma predeterminada. Sigue adelante y abre el demo / lib / demo_web / templates / page / index.html.eex
Archivo que actúa como página de inicio por defecto. Eliminar todo excepto este código:
<%= gettext "Welcome to %name!", name: "Phoenix" %>
Este mensaje de bienvenida utiliza un gettext
Función que acepta una cadena para traducir como el primer argumento. Esta cadena puede ser considerada como una clave de traducción, aunque es algo diferente de las claves utilizadas en Rails I18n y algunos otros marcos. En Rails habríamos utilizado una llave como page.welcome
, mientras que aquí la cadena traducida es una clave sí mismo. Entonces, si no se puede encontrar la traducción, podemos mostrar esta cadena directamente. Incluso un usuario que sabe poco de inglés puede tener al menos un sentido básico de lo que está pasando.
Este enfoque es bastante útil en realidad, pare por un segundo y piénselo. Tienes una aplicación donde todos los mensajes están en inglés. Si desea internacionalizarlo, en el caso más simple, todo lo que tiene que hacer es envolver sus mensajes con el gettext
funciona y proporciona traducciones para ellos (más adelante veremos que el proceso de extracción de las claves se puede automatizar fácilmente, lo que acelera aún más las cosas).
Bien, volvamos a nuestro pequeño fragmento de código y echemos un vistazo al segundo argumento pasado a gettext
: nombre: "fénix"
. Este es un llamado Unión-un parámetro envuelto con %
que nos gustaría interpolar en la traducción dada. En este ejemplo, solo hay un parámetro llamado nombre
.
También podemos agregar un mensaje más a esta página para fines de demostración:
<%= gettext "Welcome to %name!", name: "Phoenix" %>
<%= gettext "We are using version %version", version: "1.3" %>
Ahora que tenemos dos mensajes en la página raíz, ¿dónde deberíamos agregar traducciones para ellos? Parece que todas las traducciones están almacenadas bajo la priv / gettext
carpeta, que tiene una estructura predefinida. Tomemos un momento para discutir cómo se deben organizar los archivos Gettext (esto se aplica no solo a Phoenix sino a cualquier aplicación que use Gettext).
En primer lugar, debemos crear una carpeta con el nombre de la configuración regional para la que se almacenarán las traducciones. Dentro, debería haber una carpeta llamada LC_MESSAGES
que contiene uno o múltiples .correos
archivos con las traducciones reales. En el caso más simple, tendrías uno default.po
archivo por localidad. defecto
Aquí está el nombre del dominio (o alcance). Los dominios se utilizan para dividir las traducciones en varios grupos: por ejemplo, puede tener dominios con nombre administración
, wysiwig
, carro
, y otra. Esto es conveniente cuando tiene una aplicación grande con cientos de mensajes. Para aplicaciones más pequeñas, sin embargo, tener una suela defecto
dominio es suficiente.
Así que nuestra estructura de archivos podría verse así:
Para comenzar a crear archivos PO, primero necesitamos la plantilla correspondiente (POT). Podemos crearlo manualmente, pero soy demasiado perezoso para hacerlo de esta manera. Vamos a ejecutar el siguiente comando en su lugar:
mezclar gettext.extract
Es una herramienta muy útil que escanea los archivos del proyecto y verifica si Gettext se usa en algún lugar. Después de que el guión termina su trabajo, un nuevo priv / gettext / default.pot
Se creará un archivo que contiene cadenas para traducir..
Como ya hemos aprendido, los archivos POT son plantillas, por lo que almacenan solo las claves, no las traducciones, por lo que no modifique dichos archivos manualmente. Abra un archivo recién creado y eche un vistazo a su contenido:
## Este archivo es un archivo de plantilla PO. ## ## 'msgstr' s aquí se extraen a menudo del código fuente. ## Agregue nuevas traducciones manualmente solo si son ## traducciones dinámicas que no se pueden extraer de forma estática. ## ## Ejecute 'mix gettext.extract' para llevar este archivo hasta la fecha ##. Deje 'msgstr' 'vacío' ', ya que los está cambiando aquí como efecto ##: edítelos en archivos PO (' .po ') en su lugar. msgstr "" msgstr "" #: lib / demo_web / templates / page / index.html.eex: 3 msgstr "Estamos usando la versión% version" msgstr "" #: lib / demo_web / templates / page / index.html msgstr "¡Bienvenido a% name!" msgstr ""
Conveniente, ¿no es así? Todos nuestros mensajes se insertaron automáticamente, y podemos ver fácilmente dónde están ubicados. msgstr
, como habrás adivinado, es la clave, mientras que msgstr
va a contener una traducción.
El siguiente paso es, por supuesto, generar un archivo PO. Correr:
mezclar gettext.merge priv / gettext
Este guión va a utilizar el default.pot
plantilla y crear una default.po
archivo en el priv / gettext / es / LC_MESSAGES
carpeta. Por ahora, solo tenemos una configuración regional en inglés, pero también se agregará soporte para otro idioma en la siguiente sección.
Por cierto, es posible crear o actualizar la plantilla POT y todos los archivos PO de una sola vez con el siguiente comando:
mezcla gettext.extract --merge
Ahora vamos a abrir el priv / gettext / es / LC_MESSAGES / default.po
archivo, que tiene los siguientes contenidos:
msgstr "en este archivo provienen de archivos POT (.pot). ## ## No agregue, cambie ni elimine los msgstr. Aquí manualmente, ya que ## están vinculados a los del archivo POT correspondiente ## (con el mismo dominio). ## ## Use 'mix gettext.extract --merge' o 'mix gettext.merge' ## para fusionar archivos POT en archivos PO. msgstr "" msgstr "" "Idioma: en \ n" #: lib / demo_web / templates / page / index.html.eex: 3 msgstr "Estamos usando la versión% version" msgstr "" #: lib / demo_web / msgstr "¡Bienvenido a% nombre!" msgstr ""
Este es el archivo donde debemos realizar la traducción real. Por supuesto, tiene poco sentido hacerlo porque los mensajes ya están en inglés, por lo que vamos a la siguiente sección y agregamos soporte para un segundo idioma.
Naturalmente, la configuración regional predeterminada para las aplicaciones de Phoenix es el inglés, pero esta configuración se puede cambiar fácilmente al ajustar la config / config.exs
expediente. Por ejemplo, establezcamos la configuración regional predeterminada en ruso (siéntase libre de quedarse con cualquier otro idioma de su elección):
config: demo, I18ndemoWeb.Gettext, default_locale: "ru"
También es una buena idea especificar la lista completa de todas las configuraciones regionales compatibles:
config: demo, I18ndemoWeb.Gettext, default_locale: "ru", locales: ~ w (en ru)
Ahora, lo que debemos hacer es generar un nuevo archivo de pedido que contenga las traducciones para la configuración regional de Rusia. Se puede hacer ejecutando el gettext.merge
guión de nuevo, pero con una --lugar
cambiar:
mezclar gettext.merge priv / gettext --locale ru
Obviamente un priv / gettext / ru / LC_MESSAGES
carpeta con el .correos
Se generarán archivos en el interior. Tenga en cuenta, por cierto, que aparte de la default.po
archivo, también tenemos errores.po
. Este es un lugar predeterminado para traducir mensajes de error, pero en este artículo lo ignoraremos..
Ahora pellizque el priv / gettext / ru / LC_MESSAGES / default.po
añadiendo algunas traducciones:
#: lib / demo_web / templates / page / index.html.eex: 3 msgstr "Estamos usando la versión% version" msgstr "Используется версия% version" #: lib / demo_web / templates / page / index.html msgstr "¡Bienvenido a% name!" msgstr "Добро пожаловать в приложение% name!"
Ahora, según la configuración regional elegida, Phoenix traducirá las traducciones en inglés o ruso. ¡Pero espera! ¿Cómo podemos realmente cambiar entre las configuraciones regionales en nuestra aplicación? Vayamos a la siguiente sección y averigüemos.!
Ahora que algunas traducciones están presentes, necesitamos permitir que nuestros usuarios cambien entre las configuraciones regionales. Parece que hay un conector de terceros para el llamado set_locale. Funciona extrayendo la configuración regional elegida de la URL o Aceptar-lenguaje
Encabezado HTTP Por lo tanto, para especificar una configuración regional en la URL, debe escribir http: // localhost: 4000 / es / some_path
. Si no se especifica la configuración regional (o si se solicitó un idioma no compatible), sucederá una de estas dos cosas:
Aceptar-lenguaje
El encabezado HTTP y esta configuración regional son compatibles, el usuario será redirigido a una página con la configuración regional correspondiente.Abre el mix.exs
archivar y soltar set_locale
al deps
función:
defp deps do [#… : set_locale, "~> 0.2.1"] final
También debemos añadirlo a la solicitud
función:
def application do [mod: Demo.Application, [], extra_applications: [: logger,: runtime_tools,: set_locale]] end
A continuación, instale todo:
mezclar deps.get
Nuestro enrutador ubicado en lib / demo_web / router.ex
Requiere algunos cambios también. Específicamente, necesitamos agregar un nuevo enchufe al :navegador
tubería:
pipeline: browser do #… plug SetLocale, gettext: DemoWeb.Gettext, default_locale: "ru" end
Además, crea un nuevo ámbito:
alcance "/: locale", DemoWeb do pipe_through: browser get "/", PageController,: index end
¡Y eso es! Puede arrancar el servidor y navegar a http: // localhost: 4000 / ru
y http: // localhost: 4000 / es
. Tenga en cuenta que los mensajes se traducen correctamente, que es exactamente lo que necesitamos!
Alternativamente, usted mismo puede codificar una característica similar utilizando un conector de Módulo. Un pequeño ejemplo se puede encontrar en la guía oficial de Phoenix..
Una última cosa que mencionar es que, en algunos casos, es posible que necesite imponer una configuración regional específica. Para hacer eso, simplemente utiliza un with_locale
función:
Gettext.with_locale I18ndemoWeb.Gettext, "en", fn -> MyApp.I18ndemoWeb.gettext ("test") fin
Hemos aprendido los fundamentos de usar Gettext con Phoenix, así que ha llegado el momento de discutir cosas un poco más complejas.. Pluralización es uno de ellos. Básicamente, trabajar con formas plurales y singulares es una tarea muy común aunque potencialmente compleja. Las cosas son más o menos obvias en inglés ya que tiene "1 manzana", "2 manzanas", "9000 manzanas", etc. (aunque "1 buey", "2 bueyes"!).
Desafortunadamente, en algunos otros idiomas como el ruso o el polaco, las reglas son más complejas. Por ejemplo, en el caso de las manzanas, dirías "1 яблоко", "2 яблока", "9000 яблок". Pero por suerte para nosotros, Phoenix tiene un Gettext.Plural
Comportamiento (puede ver el comportamiento en acción en uno de mis artículos anteriores) que admite muchos idiomas diferentes. Por lo tanto, todo lo que tenemos que hacer es aprovechar la ngettext
función.
Esta función acepta tres argumentos obligatorios: una cadena en forma singular, una cadena en forma plural y cuenta. El cuarto argumento es opcional y puede contener enlaces que deben interpolarse en la traducción..
Veamos ngettext
en acción diciendo cuánto dinero tiene el usuario modificando el demo / lib / demo_web / templates / page / index.html.eex
expediente:
<%= ngettext "You have one buck. Ow :(", "You have %count bucks", 540 %>
%contar
es una interpolación que será reemplazada por un número (540
en este caso). No olvide actualizar la plantilla y todos los archivos PO después de agregar la cadena anterior:
mezcla gettext.extract --merge
Verás que se ha añadido un nuevo bloque a ambos. default.po
archivos:
msgstr "Tiene un dólar. Ow :(" msgstr_plural "Tiene% count bucks" msgstr [0] "" msgstr [1] ""
Aquí no tenemos una sino dos claves a la vez: en singular y en plural.. msgstr [0]
contendrá algún texto para mostrar cuando hay un solo mensaje. msgstr [1]
, por supuesto, contiene el texto para mostrar cuando hay varios mensajes. Esto está bien para el inglés, pero no lo suficiente para el ruso, donde necesitamos presentar un tercer caso:
msgstr "Usted tiene un dólar. Ow :(" msgstr_plural "Usted tiene% count bucks" msgstr [0] "У 1 доллар. ] "У вас% count долларов"
Caso 0
se usa para 1 buck, y estuche 1
Por cero o pocos dólares. Caso 2
se usa de otra manera.
Otro tema que quería discutir en este artículo está dedicado a dominios. Como ya sabemos, los dominios se utilizan para las traducciones de alcance, principalmente en aplicaciones grandes. Básicamente, actúan como espacios de nombres.
Después de todo, puede terminar en una situación en la que la misma clave se usa en varios lugares, pero debería traducirse de manera un poco diferente. O cuando tienes demasiadas traducciones en una sola default.po
archivo y me gustaría dividirlos de alguna manera. Ahí es cuando los dominios pueden ser realmente útiles..
Gettext soporta múltiples dominios fuera de la caja. Todo lo que tienes que hacer es utilizar el dgettext
función, que funciona casi igual que gettext
. La única diferencia es que acepta el nombre de dominio como primer argumento. Por ejemplo, introduzcamos un dominio de notificación para, bueno, mostrar notificaciones. Agrega tres líneas más de código a la demo / lib / demo_web / templates / page / index.html.eex
expediente:
<%= dgettext "notifications", "Heads up: %msg", msg: "something has happened!" %>
Ahora necesitamos crear nuevos archivos POT y PO:
mezcla gettext.extract --merge
Después de que el script termina de hacer su trabajo., notificaciones.pot
así como dos notificaciones.po
Se crearán archivos. Tenga en cuenta una vez más que se nombran después del dominio. Todo lo que tiene que hacer ahora es agregar la traducción al idioma ruso modificando el priv / ru / LC_MESSAGES / notifications.po
expediente:
msgstr "Heads up:% msg" msgstr "Внимание:% msg"
¿Qué sucede si desea pluralizar un mensaje almacenado en un dominio determinado? Esto es tan simple como utilizar un dngettext
función. Funciona igual que ngettext
pero también acepta el nombre de un dominio como primer argumento:
dgettext "dominio", "cadena singular% msg", "cadena plural% msg", 10, msg: "demo"
En este artículo, hemos visto cómo introducir la internacionalización en una aplicación de Phoenix con la ayuda de Gettext. Has aprendido qué es Gettext y con qué tipo de archivos funciona. Tenemos esta solución en acción, hemos trabajado con archivos PO y POT, y hemos utilizado varias funciones Gettext.
También hemos visto una forma de agregar soporte para múltiples locales y una forma de cambiar fácilmente entre ellos. Por último, hemos visto cómo emplear reglas de pluralización y cómo realizar el alcance de las traducciones con la ayuda de dominios..
Esperemos que este artículo te haya sido útil! Si desea obtener más información sobre Gettext en el marco de Phoenix, puede consultar la guía oficial, que proporciona ejemplos útiles y referencias de API para todas las funciones disponibles..
Te agradezco por estar conmigo y hasta pronto.!