Cómo mantener las traducciones de una app Angular con i18n

Translation into Spanish of an interesting article by Michael Karén, master of science, computer systems networking and telecommunications. Senior consultant at jPro.

ANGULARlocalizacionspanishtraduccion
19 May, 2022 Traducción y localización de Apps Angular
19 May, 2022 Traducción y localización de Apps Angular

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

* * *

Descubre el potencial de Angular para internacionalizar (i18n) y localizar (l10n) una App

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.

Internacionalización y localización

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.

Cómo funciona la localización con Ivy

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:

  • Inline en tiempo de compilación: la etiqueta $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.
  • Evaluación en tiempo de ejecución: la etiqueta $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.

Puede leer más sobre esto en Localización angular con Ivy,de donde se obtiene esta imagen.

Ahora que conocemos el proceso de creación de la aplicación, podemos comprender lo que implica.

El bueno y el malo

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 servees 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.

Transloco

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!

Agregar localización al proyecto Angular

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:

  • Actualizar package.jsone instalar el paquete.
  • Y actualizar polyfills.tspara 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.

Traducción de plantillas

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.

Traducir archivos TypeScript

¡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.

Extracción de textos

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.xlfde 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. ides un identificador de traducción que extract-i18ngenera, ¡así que no lo modifiques!
  • sourcecontiene el texto fuente de la traducción.
  • context-groupespecifica 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?

Crear archivos de traducción

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.

Traducir archivos manualmente

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 targety 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.

Traducir archivos con un editor

Antes de usar un editor, hay que proporcionar el idioma de traducción. Podemos hacer esto agregando el atributotarget-languagea 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 translatedneeds-translationfinal. 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”.

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-i18nde 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>
  • Ahora hay un par de etiquetasnote que proporcionan la descripción y el significado de la traducción, y la idya 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”:

Contexto en archivos TypeScript

Al igual que con las plantillas de Angular, puedes proporcionar más contexto a los traductores proporcionando archivos meaningdescriptioniden 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 idy un descriptional 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:`;

Casos de uso especializados

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 pluralpara marcar los usos de plurales y selectpara marcar opciones de texto alternativas.

Atributos

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 altsiempre 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.

Plurales

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>
  • itemCountes una propiedad con el número de artículos encontrados.
  • plural identifica el tipo de traducción.
  • El tercer parámetro enumera todos los casos posibles (0, 1, otro) y el texto correspondiente a mostrar. Los casos no coincidentes son capturados por 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.

Suplentes

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:

Interpolación

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!

Configuración de entornos locales

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óni18nlocales, 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 sourceLocalees 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ónlocalesque definimos previamente.

Para usar su definición de configuración regional en la configuración de compilación, use la opción"localize" enangular.jsonpara decirle a la CLI qué configuraciones regionales debe generar para la configuración de compilación:

  • Configura"localize"en truepara todas las configuraciones regionales previamente definidas en la configuración de compilación.
  • Establece"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 trueprovocará un error al usar ng servesi 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 serveen 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.jsonde 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 nba 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 localizeaoten “true” y listo.

Ejecución de varios idiomas localmente

Por motivos de rendimiento, la ejecución ng servesolo 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?

Múltiples idiomas

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.

Nginx

Para poner en marcha nuestra aplicación necesitamos:

  1. Instalar Nginx
  2. Agregar configuración de Angular Docs aconf/nginx.conf
  3. Construir nuestras aplicaciones
  4. Copie las aplicaciones a la carpeta definida en rooten nginx.conf.
  5. Abrir navegador enlocalhost

El puerto está configurado enlisteny 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.

Implementar la producción

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.

Mantenimiento de la aplicació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.

Generar los archivos de traducción

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, peerDependenciesdebemos usarla --legacy-peer-depssi 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/toolingpaquete:

npm install -D @ngx -i18nsupport/tooling --legacy-peer-deps

Tenga en cuenta que -Dse 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.jsonen 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!

Traducciones incompletas

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.

Dar formato a los datos según la configuración regional

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 buildo ejecutamos el indicador --configurationcon ng serve, Angular CLI incluye automáticamente los datos de configuración regional y establece el valor LOCALE_ID.

Con el LOCALE_IDconjunto 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 DatePipepara 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.

Traducciones en tiempo de ejecución

Cuando ejecutamos ng serve --configuration=xxng 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/localizepuede 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.tsusando una dinámica import(...)para el módulo.

Aquí hay un ejemplo de uso deloadTranslationsen 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 loadTranslationsy $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 .

Conclusión

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.

Recursos

Valora este artículo