Categorías
Desarrollo

Internacionalización de aplicaciones Angular (i18N)

La internacionalización y localización de aplicaciones es el proceso que permite la adaptación de las mismas a diferentes regiones. Desde el cambio del idioma o moneda, al formato de fechas, decimales, etc.

Internacionalización de aplicaciones Angular (i18N)

Internacionalización, o i18n, es el proceso de preparar una aplicación para usar distintos idiomas.

Localización, es el proceso de construir versiones para diferentes ‘locales’

Locale, identifica una región donde se habla un idioma específico.

Antes de empezar es necesario instalar el paquete ‘@angular/localize’ desde nuestro CLI de angular. Con el siguiente comando se actualizarán los ficheros del sistema package.json y polyfills.ts

ng add @angular/localize

Configuración de ficheros

Tras la instalación, crearemos dos nuevos archivos localized.component.ts y locale-helper.ts.

En el fichero localized.component.ts configuraremos el constructor para llamar al método ‘getCurrentLocale’ que hace referencia al otro fichero comentado anteriormente y que veremos a continuación con detalle.

import { Resources } from './resources';
import { LocaleHelper } from './locale-helper';

export class LocalizedComponent {
  public resources = Resources;
  public localeId: string = null;

  constructor () {
    this.localeId = LocaleHelper.getCurrentLocale();
  }
}

En el fichero locale-helper.ts encontramos distintos métodos que comentaremos ahora con más detenimiento.

‘setCurrentLocale’

public static setCurrentLocale(localeId: string) {
  // Set the new locale. Assume localeId is valid.
  const urlLocaleId = LocaleHelper.getCultureFromCurrentUrl();
  if (urlLocaleId) {
    // Replace current locale in url if any.
    if (localeId !== LocaleHelper.defaultLocaleId) {
      window.location.href = window.location.href.replace(`/${urlLocaleId}/`, `/${localeId.toLowerCase()}/`);
    } else {
      window.location.href = window.location.href.replace(`/${urlLocaleId}/`, '/');
    }

  } else {
    // If there is no locale in the url, add one.
    // Do not add one if it is the default locale.
    if (localeId !== LocaleHelper.defaultLocaleId) {
      const newUrl = window.location.href.replace(window.location.pathname, `/${localeId}` + window.location.pathname);
      if (newUrl !== window.location.href) {
        window.location.href = newUrl;
      }
    }
  }
}

Este sirve para setear el código del idioma en la url.

En nuestro caso no utilizaremos este método y definiremos una variable en el archivo environment.ts con el código del idioma llamada ‘language

export const environment = {
   production: false,
   apiTokenFromCookie: false,
   language: 'en',
   DTSize: 25,
   DTRoomSize: 10,
   DTDrawingSize: 10,
   ...

Siendo ‘en’ y ‘es’ los códigos de idioma válidos para nuestras apps.

Volviendo al fichero anterior, vemos la llamada a la variable del idioma definida:

export abstrat class LocaleHelper {
  public language = environment.language;
  ...

Y el método ‘getCurrentLocale

public static getCurrentLocale(): string {
  return environment.language;
}

En el cual solo devolveremos la variable definida en environment.ts.

Ficheros de traducción

Tras haber realizado la configuración inicial, veremos los ficheros de traducción y cómo usarlos en los archivos html de nuestro proyecto.

Primero debe haber un fichero, llamada resources.ts, con las definiciones de todas las variables que procederemos a traducir en los ficheros de traducción, este archivo debe estar localizado en la raíz del proyecto, a la misma altura que el app-module.ts

En este fichero estarán todas las definiciones de las variables que traduciremos en los siguientes puntos, ejemplo del fichero resources.ts:

export abstract class Resources {

  // HEADER APP
  public static workCentersTab: string = null;
  public static providersTab: string = null;
  public static changeApp: string = null;
  public static closeSession: string = null;

  // WORK CENTER FILTER
  public static filterHeader: string = null;
  public static newWorkCenterButton: string = null;
  public static centerLabel: string = null;
  public static provinceLabel: string = null;
  public static entityLabel: string = null;
  public static statusLabel: string = null;
  public static generalDocumentSpace: string = null;
  public static activeRadio: string = null;
  public static inactiveRadio: string = null;
  public static allRadio: string = null;
  public static searchButton: string = null;
  public static cleanButton: string = null;
  public static workCenterNamePlaceholder: string = null;
  ...

Los ficheros de traducción deben ir definidos en la ruta ‘../assets/translation’ y dentro de esta carpeta albergar todos los ficheros de traducción de nuestra aplicación. Todos con la misma nomenclatura en el nombre solo cambiando los códigos del idioma.

resources.en.ts

export const resources = {

  // HEADER APP
  'workCentersTab': 'Work Centers Management',
  'providersTab': 'Provider Management',
  'changeApp': 'Change Application',
  'closeSession': 'Close Session',

  // WORK CENTER FILTER
  'filterHeader': 'Work center filter',
  'newWorkCenterButton': 'New work center',
  'centerLabel': 'Center',
  'provinceLabel': 'Province',
  'entityLabel':'Entity',
  'statusLabel':'Status',
  'activeRadio': 'Actives',
  'inactiveRadio': 'Inactives',
  'allRadio': 'All',
  'searchButton': 'Search',
  'cleanButton': 'Clean',
  'workCenterNamePlaceholder': 'Search by name',
  ...

resources.es.ts

export const resources = {

  // HEADER APP
  'workCentersTab': 'Gestión de centros',
  'providersTab': 'Gestión de proveedores',
  'changeApp': 'Cambiar aplicación',
  'closeSession': 'Cerrar sesión',

  // WORK CENTER FILTER
  'filterHeader': 'Filtro de centros',
  'newWorkCenterButton': 'Nuevo centro',
  'centerLabel': 'Centro',
  'provinceLabel': 'Provincia',
  'entityLabel':'Entidad',
  'statusLabel':'Estado',
  'activeRadio': 'Activos',
  'inactiveRadio': 'Inactivos',
  'allRadio': 'Todos',
  'searchButton': 'Buscar',
  'cleanButton': 'Limpiar',
  'workCenterNamePlaceholder': 'Búsqueda por nombre',
  ...

Sólo se necesita el nombre de la variable definida en el archivo resources.ts y el texto que se va a mostrar en la aplicación.

Podemos ver ejemplos de los ficheros de inglés y español y comparar los nombres de las variables con el fichero de resources.ts.

Uso de las traducciones

Para darle uso los textos introducidos en los ficheros de traducción en nuestra aplicación lo haremos de la siguiente manera:

<div class="col-6">
  {{resources.providerFilterHeader}}
</div>

En los archivos html debemos hacer referencia al fichero resources.ts y al nombre de la variable que queremos mostrar entre llaves.

Detección de lenguaje

Después de la creación de los ficheros de traducción hay que configurar el sistema para que sepa cuál escoger en cada momento.

Esto se le indica a la aplicación en el fichero app.module.ts

export class AppModule {

  constructor() {
    // Pre-load all the needed locales.
    registerLocaleData(localeEs, 'es', localeEsExtra);

    // There are other ways to load a module dynamically.
    import('../assets/translation/resources.${LocaleHelper.getCurrentLocale().toLowerCase()}.js').then((r) => {

      // Load 'Resources' whith values.
      for (const key in r.resources) {
        if (r.resources.hasOwnProperty(key)){
          Resources[key] = r.resources[key];
        }
      }
    });
  }

}

Vemos como utiliza el método ‘getCurrentLocale’ para obtener la variable que definimos en nuestro environment.ts y así cargar el archivo de traducción correcto desde la ruta que especificamos antes.