Translation into Spanish of an interesting article by Michael Karén, master of science, computer systems networking and telecommunications. Senior consultant at jPro.
A free translation by Chema, a Spain-based translation student specializing in English to Spanish translations
An original text written by Michael Karén, originally published in
https://medium.com/dailyjs/maintaining-multi-language-angular-applications-26b74df8d085
* * *
La traducción y localización de aplicaciones Angular mejoró mucho con la versión 9 (v9)y su nuevo motor de renderizado Ivy. En este artículo, analizaremos cómo funciona este paquete de internacionalización y localización integrado en Angular, señalando tanto las ventajas como las desventajas que vayamos encontrando.
Luego, configuraremos una aplicación con internacionalización Angular realizando todo el proceso completo: marcar textos para traducir, extraerlos en archivos de traducción, y administrar estos archivos para implementar las traducciones y actualizar la aplicación mientras mantenemos contentos a los usuarios de todo el mundo.
Es fácil confundirse con los términos internacionalización (i18n) y localización (i10n), y difícil saber dónde trazar la línea que los separa. La internacionalización es el proceso de diseñar una aplicación para que pueda adaptarse a diferentes mercados en todo el mundo, mientras que la localización es el proceso de crear las distintas versiones de la aplicación para esos distintos mercados, considerando tanto el país como el idioma.
La internacionalización y la localización permiten adaptar el software a diferentes idiomas y variaciones locales, encajando así con las diferentes expectativas del público.
El nuevo proceso de localización de Angular Ivy se basa en el concepto de plantillas etiquetadas. Las etiquetas permiten analizar literales de plantilla con una función. La etiqueta utilizada aquí es el identificador global $localize
. En lugar de traducir las cadenas, el compilador de plantillas de Ivy convierte todo el texto de plantilla marcado con atributos i18n
en cadenas etiquetadas $localize
.
Entonces, cuando añadimos:
<h1 i18n>¡Hola mundo!</h1>
Se compilará con la forma $localize
y en algún lugar del código compilado encontraremos:
$localize`¡Hola mundo!`
La plantilla etiquetada coloca la función que se quiere ejecutar en la cadena antes de la plantilla. En lugar de function()
, aparece function``
o como en este caso $localize``
.
Una vez realizado este paso, tenemos dos opciones:
$localize
se transforma en tiempo de compilación mediante un transpilador, eliminando la etiqueta y reemplazando la cadena literal de la plantilla con la traducción.$localize
es una función en tiempo de ejecución que reemplaza la cadena literal de plantilla con traducciones cargadas en tiempo de ejecución.En este artículo, usamos la inserción en tiempo de compilación para lograr nuestros objetivos. Al final del proceso de compilación, ejecutamos un paso para los archivos de traducción proporcionando un indicador de opción para obtener una aplicación localizada para los idiomas. Dado que estamos haciendo las traducciones en tiempo de compilación, obtenemos una aplicación por configuración regional.
Al final del artículo, analizaremos la evaluación en tiempo de ejecución .
Debido a que no es necesario volver a compilar la aplicación para cada configuración regional, el proceso de compilación es mucho más rápido que antes de la v9 de Angular.
Ahora que conocemos el proceso de creación de la aplicación, podemos comprender lo que implica.
La internacionalización y localización estándar de Angular están diseñadas para producir una aplicación compilada por idioma. Al hacer esto, el rendimiento es óptimo ya que no hay sobrecarga de archivos de traducción que haya que compilar durante el tiempo de ejecución. Pero esto también significa que cada idioma debe implementarse en una URL separada. Así, encontramos, por ejemplo:
www.midominio.com/en
www.midominio.com/nb
www.midominio.com/fi
Por esta razón, debemos configurar un poco más nuestro servidor web. Una limitación deng serve
es que solo funciona con un idioma a la vez, por lo que para ejecutar diferentes idiomas también necesita alguna reconfiguración. Para ejecutar todos los idiomas localmente, necesitamos usar un servidor web local. Analizaremos cómo hacer todo esto en este artículo.
Angular i18n usa formatos XLIFF y XMB que se basan en XML y son más detallados que JSON. Pero eso no importa, dado que estos archivos se usan en tiempo de compilación. Tiene sentido usar JSON cuando cargamos los archivos de traducción en tiempo de ejecución para mantener el tamaño de los archivos más pequeño. Los formatos elegidos para el i18n incorporado son utilizados por el software de traducción que nos ayuda con nuestras traducciones, como veremos más adelante.
El principal inconveniente que se suele encontrar con esta solución es que necesita volver a cargar la aplicación cuando cambia de idioma. Pero, ¿es esto realmente un problema? La gente suele cambiar de idioma una vez, si es que alguna vez lo hace. Y ese par de segundos que tarda en recargar las aplicaciones no será un problema.
Tener un paquete por idioma no es un problema para un SPA web, aparte de tener que configurar el servidor web para ello. Pero para las aplicaciones independientes, esto significa que debe hacer que el usuario descargue cada paquete traducido o distribuya una aplicación diferente para cada versión.
Es importante comprender los requisitos antes de decidir qué ruta tomar.
Si el Angular i18n estándar no te funciona como desearías, la mejor alternativa en mi opinión es Transloco. Se mantiene de manera constante y tiene una comunidad activa. Te permitirá ponerte en funcionamiento más rápido y es más flexible que la solución integrada. Dado que Transloco es una traducción en tiempo de ejecución, solo tienes que acceder a www.mydomain.com y puedes cambiar la localización sobre la marcha.
Por lo tanto, antes de tomar una decisión, consulta Transloco para ver si se adapta a lo que buscas.
Pero suficientes tecnicismos, ¡veamos algo de código!
El paquete @angular/localize
se lanzó con Angular 9 y admite i18n en aplicaciones Ivy. Este paquete requiere un símbolo global $localize
para existir. El símbolo se carga importando el módulo@angular/localize/init
Para agregar las funciones de localización proporcionadas por Angular, hay que agregar el paquete @angular/localize
al proyecto:
ng add @angular/localize
Este comando permite:
package.json
e instalar el paquete.polyfills.ts
para importar el paquete@angular/localize
.Si intentas usar i18n sin agregar este paquete, obtendrá un mensaje de error que se explica por sí mismo y nos recuerda que ejecutemos ng add @angular/localize
.
Para traducir plantillas en nuestra aplicación, primero debemos preparar los textos marcándolos con el atributoi18n
.
i18n es un atributo personalizado de la API de WebExtensions. Es reconocido por las herramientas y compiladores de Angular. Durante la compilación, se elimina y el contenido de la etiqueta se reemplaza con las traducciones.
Marcamos el texto así:
<span i18n>Welcome</span>
Esta etiqueta <span>
ahora está marcada y lista para el siguiente paso en el proceso de traducción.
¡IMPORTANTE! Es necesaria la versión Angular 10.1 o posterior para extraer cadenas de archivos de código fuente (.ts).
No son solo las plantillas las que necesitan traducirse. A veces encontraremos código en archivos TypeScript que también necesitan una traducción. Para localizar una cadena en el código fuente, se usa el literal de plantilla $localize
:
title = $localize`My page`;
Hay que tener en cuenta que los literales de plantilla usan el carácter de acento grave (“` ) en lugar de comillas simples o dobles.
Cuando nuestra aplicación esté preparada para ser traducida, podemos usar el comando extract-i18n para extraer los textos marcados en un archivo de idioma de origen llamado messages.xlf
.
Las opciones de comando que podemos usar son:
--output-path
: cambia la ubicación del archivo de idioma de origen.--outFile
: cambia el nombre del archivo.--format
: cambia el formato de archivo. Los formatos posibles son XLIFF 1.2 (predeterminado), XLIFF 2 y XML Message Bundle (XMB) .Ejecutando el siguiente comando desde el directorio raíz del proyecto:
ng extract-i18n
se obtiene el archivomessages.xlf
de la siguiente forma:
<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en-US" datatype="plaintext" riginal="ng2.template">
<body>
<trans-unit id="3492007542396725315" datatype="html">
<source>Welcome</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">7</context>
</context-group>
</trans-unit>
<trans-unit id="5513198529962479337" datatype="html">
<source>My page</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>
Podemos ver que aparecen los términos “Welcome” y “My page” en el archivo, pero ¿qué significa?
trans-unit
es la etiqueta que contiene una sola traducción. id
es un identificador de traducción que extract-i18n
genera, ¡así que no lo modifiques!source
contiene el texto fuente de la traducción.context-group
especifica dónde se puede encontrar la traducción dada.context-type="sourcefile"
muestra el archivo de donde proviene la traducción.context-type="linenumber"
indica la línea de código de la traducción.Ahora que hemos extraído el archivo fuente, ¿cómo obtenemos archivos con los idiomas que queremos traducir?
Después de haber generado el archivomessages.xlf
, podemos agregar nuevos idiomas copiándolo y nombrando el nuevo archivo de acuerdo con la configuración regional asociada.
Para almacenar las traducciones de noruego, cambiamos el nombre del archivo copiado a messages.nb.xlf
. Luego enviamos este archivo al traductor para que haga las traducciones con un editor XLIFF. Pero no nos adelantemos, hagamos una traducción manual para obtener una mejor comprensión de los archivos de traducción.
Abre el archivo y busca el elemento <trans-unit>
que representa la traducción de la etiqueta de saludo <h1>
que se marcó previamente con el atributo i18n
. Duplica el elemento <source>...</source>
en el nodo de texto, ponle el nombre target
y luego remplaza su contenido con el texto en noruego:
<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en-US" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="3492007542396725315" datatype="html">
<source>Welcome</source>
<target>Velkommen</target>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">7</context>
</context-group>
</trans-unit>
<trans-unit id="5513198529962479337" datatype="html">
<source>my page</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.ts</context>
<context context-type="linenumber">9</context>
</context-group>
</trans-unit>
</body>
</file>
</xliff>
Esto es todo lo que hay que hacer para agregar las traducciones a los archivos. Veamos cómo lo hacemos con un editor.
Antes de usar un editor, hay que proporcionar el idioma de traducción. Podemos hacer esto agregando el atributotarget-language
a la etiqueta del archivo para que el software de traducción pueda detectar la configuración regional:
<file source-language="en-US" datatype="plaintext" original="ng2.template" target-language="nb">
Entonces abrimos este archivo en una herramienta de traducción para ver con qué estamos trabajando. Yo uso la versión gratuita de PoEdit en este artículo:
Esto parece mucho más sencillo que la forma manual. Incluso recibimos algunas sugerencias de traducción. Ahora traduzcamos “My page” y guardemos el archivo. Si luego abrimos messages.nb.xlf
, podemos ver que ha agregado la traducción en un bloque de destino como cuando lo hicimos manualmente:
<source>My page</source>
<target state="translated">min side</target>
También se agregó state="translated"
a la etiqueta de destino. Este es un atributo opcional que puede tener los valores translated
, needs-translation
o final
. Esto nos ayuda a la hora de usar el editor para encontrar los textos que aún no están traducidos.
Este es un gran comienzo, pero antes de probar las traducciones en nuestra aplicación, veamos qué más podemos hacer agregando más información en el cuadro de la captura de pantalla llamado “Notas para traductores”.
A veces el traductor necesita más información sobre lo que está traduciendo. Podemos agregar una descripción de la traducción como el valor del atributo i18n:
<span i18n ="Mensaje de bienvenida">Bienvenido</span>
Podemos agregar aún más contexto al traductor agregando el significado del mensaje de texto. Podemos agregar el significado junto con la descripción y separarlos con el caracter |
: <meaning>|<description>
. En este ejemplo, podríamos querer que el traductor sepa que este mensaje de bienvenida se encuentra en la barra de herramientas:
<span i18n ="encabezado de la barra de herramientas|Mensaje de bienvenida">Bienvenido</span>
La última parte que podemos agregar al valor del atributoi18n
es una ID usando @@
. Asegúrese de definir ID personalizados únicos. Si usa la misma identificación para dos mensajes de texto diferentes, solo se extrae el primero y se usa su traducción en lugar de los dos mensajes de texto originales.
Aquí añadimos el ID toolbarHeader
:
<span i18n ="encabezado de la barra de herramientas|Mensaje de bienvenida@@toolbarHeader">Bienvenido</span>
Si no agregamos una ID para la traducción, Angular generará una ID aleatoria como vimos anteriormente. Al ejecutar ng extract-i18n
de nuevo, podemos ver que la información útil se ha agregado a nuestra unidad de traducción:
<trans-unit id="toolbarHeader" datatype="html">
<source>Welcome</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">7</context>
</context-group>
<note priority="1" from="description">Welcome message</note>
<note priority="1" from="meaning">toolbar header</note>
</trans-unit>
note
que proporcionan la descripción y el significado de la traducción, y la id
ya no es un número aleatorio.Si los copiamos al archivomessages.ng.xlf
y lo abrimos en PoEdit, vemos que todos estos ahora están visibles en “Notas para traductores”:
Al igual que con las plantillas de Angular, puedes proporcionar más contexto a los traductores proporcionando archivos meaning
, description
y id
en TypeScript. El formato es el mismo que se usa para los marcadores i18n en las plantillas. Aquí están las diferentes opciones que se encuentran en Angular Docs :
$localize`:meaning|description@@id:texto del mensaje de origen`;
$localize`:meaning|:texto del mensaje de origen`;
$localizar`:description:texto del mensaje de origen`;
$localizar`:@@id:texto del mensaje de origen`;
Añadir un id
y un description
al título podría resultar de la siguiente forma:
title = $localize`:Encabezado en la primera página@@firstPageTitle:Mi página`;
Si la cadena literal de la plantilla contiene expresiones, puede proporcionar el nombre del marcador de posición entre caracteres “:” directamente después de la expresión:
$localize`Hola ${persona.nombre}:nombre:`;
Hay algunos casos de uso especializados para las traducciones que debemos analizar. Los atributos pueden pasarse por alto fácilmente, pero también es importante traducirlos, sobre todo por su accesibilidad.
Diferentes idiomas tienen diferentes reglas de pluralización y construcciones gramaticales que pueden dificultar la traducción. Para simplificar la traducción, podemos usar plural
para marcar los usos de plurales y select
para marcar opciones de texto alternativas.
Además de los sospechosos habituales de las etiquetas HTML, también debemos ser conscientes de que necesitamos traducir los atributos HTML. Esto es especialmente importante cuando hacemos que nuestras aplicaciones sean accesibles para todas las personas.
Tomemos el ejemplo de una etiquetaimg
. Las personas que usan un lector de pantalla no verían la imagen, pero recibirían el atributoalt.
Por esta y otras razones, es importante proporcionar un valor útil para alt
siempre que sea posible.
<img [src]="logotipo" alt="Logotipo de bienvenida" />
Para marcar un atributo para traducción, se agrega i18n-
seguido del atributo que se está traduciendo. Para marcar el atributo alt
en la etiqueta img,
añadimos i18n-alt
:
<img [src]="logotipo" i18n-alt alt="Logotipo de bienvenida" />
En este caso, se extraerá el texto “Logotipo de bienvenida” para la traducción.
También puede asignar un significado, una descripción y un ID personalizado con la
i18n-attribute="<meaning>|<description>@@<id>"
sintaxis.
Las reglas de pluralización entre idiomas difieren. Es necesario que el programa esté preparado para todos los casos potenciales. Usamos la cláusula plural
para marcar expresiones que queremos traducir dependiendo del número de sujetos.
Por ejemplo, imagina que hacemos una búsqueda y queremos mostrar cuántos resultados se encontraron. Queremos mostrar “no se encontró nada” o la cantidad de resultados adjuntos con “elementos encontrados”. Y por supuesto, no nos olvidemos del caso con un solo resultado.
La siguiente expresión nos permite traducir los diferentes plurales:
<p i18n>
{itemCount, plural, =0 {nothing found} =1 {one item found} other {{{itemCount}} items found}}</p>
itemCount
es una propiedad con el número de artículos encontrados.plural
identifica el tipo de traducción.other
. Angular admite más categoríasenumeradas aquí .Cuando traducimos expresiones en plural tenemos dos unidades trans: una para el texto regular colocado antes del plural y otra para las versiones en plural.
Si su texto depende del valor de una variable, necesita traducir todas las alternativas. Al igual en el caso de los plurales, podemos usar la cláusula select
para marcar opciones de textos alternativos. Te permite elegir una de las traducciones en base a un valor:
<p i18n>Color: {color, seleccione, rojo {rojo} azul {azul} verde {verde}}</p>
Según el valor de color
, mostramos “rojo”, “azul” o “verde”. Al igual que cuando traducimos expresiones en plural, obtenemos dos unidades trans:
<trans-unit id="7195591759695550088" datatype="html">
<source>Color: <x id="ICU" equiv-text="{color, select, red {red} blue {blue} green {green}}"/></source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">12</context>
</context-group>
</trans-unit>
<trans-unit id="3928679011634560837" datatype="html">
<source>{VAR_SELECT, select, red {red} blue {blue} green {green}}</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/app.component.html</context>
<context context-type="linenumber">12</context>
</context-group>
</trans-unit>
Los editores entienden estas unidades y nos ayudan con las traducciones:
Vamos a añadir un mensaje de bienvenida al título:
<h1 i18n >Bienvenido a {{título}}</h1>
Esto coloca el valor de la variable title
que tradujimos anteriormente en el texto. Cuando extraemos este texto vemos cómo se maneja la interpolación:
<translation>Bienvenido a <x id="INTERPOLACIÓN" equiv-text="{{ title }}"/> </source>
Para la traducción, <x.../>
se mantiene igual para el idioma de destino:
<target>Velkommen hasta <x id="INTERPOLATION" equiv-text="{{ title }}"/></target>
Y ese es el último ejemplo de traducciones que estamos viendo. ¡Ahora, veamos cómo podemos hacer que estas aplicaciones funcionen con nuestro nuevo lenguaje!
Para poder ejecutar nuestra aplicación en muchos idiomas, debemos definir las configuraciones regionales en la configuración de compilación. En el archivoangular.json,
podemos definir configuraciones regionales para un proyecto bajo la opcióni18n
y locales
, que asigna identificadores de configuraciones regionales a archivos de traducción:
"projects": {
"i18n-app": {
"i18n": {
"sourceLocale": "en-US",
"locales": {
"nb": "messages.nb.xlf"
}
}
}
Aquí agregamos la configuración para el idioma noruego. Proporcionamos la ruta para el archivo de traducción para la configuración regional "nb"
. En nuestro caso, el archivo todavía está en el directorio raíz.
La etiqueta sourceLocale
es la configuración regional que se usa dentro del código fuente de la aplicación. El valor predeterminado es en-US,
que podemos dejar fuera o cambiarlo a otro idioma. Cualquier valor que usemos aquí también se usa para construir una aplicación junto con la configuraciónlocales
que definimos previamente.
Para usar su definición de configuración regional en la configuración de compilación, use la opción"localize"
enangular.json
para decirle a la CLI qué configuraciones regionales debe generar para la configuración de compilación:
"localize"
en true
para todas las configuraciones regionales previamente definidas en la configuración de compilación."localize"
en una matriz de un subconjunto de los identificadores de configuración regional definidos previamente para crear solo esas versiones de configuración regional.El servidor de desarrollo solo admite la localización de una única configuración regional a la vez. Establecer la opción "localize"
en true
provocará un error al usar ng serve
si se define más de una configuración regional. Establecer la opción en una configuración regional específica, como "localize": ["nb"]
, puede funcionar si se desea desarrollar en una configuración regional específica.
Dado que queremos poder utilizar ng serve
en nuestra aplicación con un solo idioma, creamos una configuración personalizada específica de la configuración regional especificando una única configuración regional de angular.json
de la siguiente manera:
"build": {
"configurations": {
"nb": {
"localize": ["nb"]
}
}
},
"serve": {
"configurations": {
"nb": {
"browserTarget": "ng-i18n:build:nb"
}
}
}
Con este cambio, podemos servir la versión noruega de la aplicación y asegurarnos de que las traducciones funcionen enviando nb
a la opciónconfiguration
:
ng servir --configuration=nb
También podemos compilar la aplicación con una configuración regional específica:
ng build --configuration=producción,nb
O con todos los locales a la vez:
ng construir --prod --localizar
En otras palabras, es más flexible configurarlo de la forma en que lo hicimos, pero también podríamos haberlo establecido localize
y aot
en “true” y listo.
Por motivos de rendimiento, la ejecución ng serve
solo admite una configuración regional a la vez. Como vimos anteriormente, podemos servir los idiomas específicos enviando la configuración regional a la opciónconfiguration
. Pero, ¿cómo podemos ejecutar la aplicación con todos los idiomas configurados?
Para ejecutar todos los idiomas simultáneamente, primero debemos compilar el proyecto. Podemos construir aplicaciones con los locales definidos en la configuración de construcción con la opciónlocalize
:
ng construir --prod --localizar
Cuando la compilación esté localizada y lista, debemos configurar un servidor web local para atender las aplicaciones. Recuerda que tenemos una aplicación por idioma, que es lo que hace que esto sea un poco más complejo.
En Angular Docs, hay un par de ejemplos de código del lado del servidor que podemos usar.
Para poner en marcha nuestra aplicación necesitamos:
conf/nginx.conf
root
en nginx.conf
.localhost
El puerto está configurado enlisten
y normalmente está configurado en 80. Cambia los idiomas cambiando la URL. Ahora deberíamos ver nuestra aplicación noruega en localhost/nb
.
Aquí hay un ejemplo del archivonginx.conf
:
events{}
http {
types {
module;
}
include /etc/nginx/mime.types;
# Expires map for caching resources
map $sent_http_content_type $expires {
default off;
text/html epoch;
text/css max;
application/javascript max;
~image/ max;
}
# Browser preferred language detection
map $http_accept_language $accept_language {
~*^en en;
~*^nb nb;
}
server {
listen 80;
root /usr/share/nginx/html;
# Set cache expires from the map we defined.
expires $expires;
# Security. Don't send nginx version in Server header.
server_tokens off;
# Fallback to default language if no preference defined by browser
if ($accept_language ~ "^$") {
set $accept_language "nb";
}
# Redirect "/" to Angular app in browser's preferred language
rewrite ^/$ /$accept_language permanent;
# Everything under the Angular app is always redirected to Angular in the correct language
location ~ ^/(en|nb) {
try_files $uri /$1/index.html?$args;
# Add security headers from separate file
include /etc/nginx/security-headers.conf;
}
# Proxy for APIs.
location /api {
proxy_pass https://api.address.here;
}
}
}
Si usamos Nginx en producción, tiene sentido probar también nuestra aplicación localmente con él.
Si está utilizando Nginx en producción, entonces ya tiene la configuración de configuración de idioma. De lo contrario, debe averiguar qué cambios necesita para la configuración de su servidor en particular.
Tenemos que tener en cuenta si estamos ejecutando la aplicación localmente o en producción. Podemos hacer esto usando isDevMode
, que devuelve si Angular está en modo de desarrollo:
esDevMode() ? '/' : `/${configuración regional}/`;
Entonces, cuando estamos ejecutando la aplicación localmente ng serve
, no agregamos la configuración regional a la URL como lo hacemos cuando hemos localizado la aplicación en la compilación de producción.
Por lo general, cuando se ha implementado la aplicación, es el momento de finalizar el artículo. Esta vez quería abordar algunas cosas más antes de terminar. Empecemos analizando los desafíos a los que nos enfrentamos al pasar al modo de mantenimiento.
El mayor desafío es el manejo de los archivos de traducción. Necesitamos asegurarnos de que los textos marcados lleguen a los traductores y regresen a la aplicación antes de que se implemente. Para ayudar con esto, necesitamos encontrar una manera de automatizar la generación de archivos de traducción y recibir notificaciones cuando falten traducciones.
No es sostenible seguir fusionando los archivos de traducción manualmente. ¡Necesitamos algo de automatización! Para implementar esto, estoy usando una herramienta gratuita llamada Xliffmerge .
Dado que esta herramienta tiene versiones antiguas de Angular,
peerDependencies
debemos usarla--legacy-peer-deps
si estamos usando una nueva versión de NPM (v7) que, de lo contrario, fallaría en la instalación.
La documentación de Xliffmerge apunta a versiones anteriores de Angular, pero después de algunos experimentos, encontré que era suficiente para instalar el @ngx-i18nsupport/tooling
paquete:
npm install -D @ngx -i18nsupport/tooling --legacy-peer-deps
Tenga en cuenta que -D
se instala en devDependencies
, y para usar en una canalización de CI, debe omitirlo para usarlo en dependencies
.
Luego podemos agregar nuevos idiomas a las configuraciones angular.json
en projects -> projectName -> architect -> xliffmerge
.
"xliffmerge": {
"builder": "@ngx-i18nsupport/tooling:xliffmerge",
"options": {
"xliffmergeOptions": {
"defaultLanguage": "en-US",
"languages": ["nb"]
}
}
}
Después de agregar nuevas traducciones, podemos extraerlas y migrarlas a nuestros archivos de traducción ejecutando este script:
ng extract-i18n && ng ejecutar nombre del proyecto: xliffmerge
Luego recibimos un par de advertencias al ejecutar el script que nos dice que está funcionando.
ADVERTENCIA: se fusionaron 1 unidades trans del maestro a "nb"
ADVERTENCIA: traduzca el archivo "messages.nb.xlf" a target-language="nb"
Después de esto, puedes distribuir los archivos de idioma a los traductores. Y cuando finalicen las traducciones, los archivos deben volver a fusionarse en el repositorio del proyecto.
Solo una advertencia de que esta biblioteca no se estaba manteniendo activamente en el momento de escribir este artículo, por lo que es posible que quieras buscar otras opciones. Hay un problema de Angular al fusionar archivos traducidos . ¡Ve y vota si crees que esto es algo que necesitamos!
Otra forma de asegurarse de que las traducciones sean válidas es hacerse notar si faltan traducciones. De forma predeterminada, la compilación tiene éxito pero genera una advertencia de traducciones faltantes. Podemos configurar el nivel de la advertencia que genera el compilador de Angular:
error
: se muestra un mensaje de error y se cancela el proceso de compilación.warning
(predeterminado): muestra una advertencia de traducción faltante en la consola o shell.ignore
: Hacer nada.Especifique el nivel de advertencia en la sección de opciones para el destino de compilación de su archivo de configuración de Angular CLI, angular.json
. El siguiente ejemplo muestra cómo establecer el nivel de advertencia en error:
"opciones": {
"i18nMissingTranslation": "error"
}
Si ejecuta la aplicación y no se encuentra ninguna traducción, la aplicación muestra el texto del idioma de origen. Aquí tenemos que tomar una decisión sobre la importancia de las traducciones. Si son cruciales, entonces deberíamos interrumpir la compilación para asegurarnos de que se entreguen todas las traducciones.
Los idiomas no son lo único a tener en cuenta al localizar aplicaciones. Un par de cosas más obvias en las que debemos pensar es cómo presentamos fechas y números a nuestros clientes locales.
En Angular, proporcionamos el LOCALE_ID
para establecer la configuración regional de la aplicación y registrar los datos de la configuración regional con registerLocaleData()
. Cuando usamos la opción --localize
con ng build
o ejecutamos el indicador --configuration
con ng serve
, Angular CLI incluye automáticamente los datos de configuración regional y establece el valor LOCALE_ID
.
Con el LOCALE_ID
conjunto en la configuración regional correcta, podemos usar las canalizaciones integradas de Angular para formatear nuestros datos. Angular proporciona los siguientes formatos:
DatePipe
: Da formato a un valor de fecha.CurrencyPipe
: transforma un número en una cadena de moneda.DecimalPipe
: Transforma un número en una cadena de números decimales.PercentPipe
: transforma un número en una cadena de porcentaje.Por ejemplo, {{myDate | date}}
utiliza DatePipe
para mostrar la fecha en el formato correcto. También podemos usar las canalizaciones en archivos de TypeScript siempre que se las proporcionemos al módulo.
Cuando ejecutamos ng serve --configuration=xx
o ng build --localize
, la aplicación se compila y traduce antes de ejecutarla. Sin embargo, si no le decimos a Angular que localice nuestra aplicación, las etiquetas$localize
se dejan en el código y es posible hacer la traducción en tiempo de ejecución.
Esto significa que podemos enviar una sola aplicación y cargar las traducciones que queremos usar antes de que se inicie la aplicación. Hay una función loadTranslations
que@angular/localize
puede usar para cargar traducciones, en forma de pares clave/valor, antes de que se inicie la aplicación.
Dado que las traducciones deben ser llamadas antes de importar cualquier archivo de módulo, podemos ponerlo en formato polyfills.ts
. También puedes utilizar main.ts
usando una dinámica import(...)
para el módulo.
Aquí hay un ejemplo de uso deloadTranslations
en polyfills.ts
:
importar '@angular/localizar/init';
import {loadTranslations} desde '@angular/localize';loadTranslations({
'bienvenido': 'Velkommen'
});
Hay que tener en cuenta que el resultado de esto es el mismo que la traducción en tiempo de compilación. La traducción ocurre solo una vez. Si desea cambiar el idioma en tiempo de ejecución, debes reiniciar toda la aplicación. Dado que los mensajes$localize
solo se procesan en el primer encuentro, no proporcionan un cambio de idioma dinámico sin actualizar el navegador.
El principal beneficio es permitir que el proyecto implemente una sola aplicación con muchos archivos de traducción. Todavía falta la documentación sobre esta parte, pero esperamos obtener documentación oficial sobre cómo trabajar mejor con loadTranslations
y $localize
. Hay bibliotecas de terceros como Soluling que intentan cerrar las brechas.
Si lo que estás buscando es una solución dinámica y favorable para el tiempo de ejecución, entonces te recomiendo que uses Transloco .
Comenzamos este artículo analizando cómo el nuevo motor Ivy cambió el i18n y la localización de aplicaciones con Angular. Analizamos las ventajas y desventajas que esto implica y si debemos usar soluciones alternativas y cuándo.
Luego analizamos cómo agregar el paquete integrado a una solución y cómo marcamos los textos para traducir. Aprendimos a configurar la aplicación para la localización y agregamos herramientas para administrar nuestros archivos de traducción. Cuando usamos un editor para traducir, vimos cómo ayuda agregar contexto a las traducciones.
Finalmente, después de configurar y traducir la aplicación, configuramos un servidor web para servir nuestra aplicación tanto localmente como en producción.
Hay muchas partes para localizar una aplicación y espero que después de leer este artículo, comprendas mejor cómo puedes crear y administrar aplicaciones en varios idiomas utilizando el software de Angular.