L’internazionalizzazione delle applicazioni è un’area di sviluppo dalle mille sfaccettature, incentrata sulla messa a disposizione e sulla facilità di utilizzo delle applicazioni per un pubblico mondiale. Questa pagina descrive gli strumenti di internazionalizzazione (i18n), che possono aiutare a rendere l’applicazione disponibile in più lingue.

Configurazione dizionari

Dopo aver configurato il TranslateModule, è possibile inserire le traduzioni in un file json che verrà importato con il TranslateHttpLoader. Le seguenti traduzioni vengono archiviate in due diversi json: en.json (dizionario inglese) e it.json (dizionario italiano). Ma nessuno ci impedisce di creare altri dizionari (ad esempio de.json).

Il TranslateParser accetta oggetti JSON nidificati. Ciò significa che sarà possibile avere traduzioni simili alle seguenti:

it.json

{
  "today": "Oggi",
  "day-labels": {
    "mo": "Lun",
    "tu": "Mar",
    "we": "Mer",
    "th": "Gio",
    "fr": "Ven",
    "sa": "Sab",
    "su": "Dom"
  },
  "month-labels": {
    "1": "Gen",
    "2": "Feb",
    "3": "Mar",
    "4": "Apr",
    "5": "Mag",
    "6": "Giu",
    "7": "Lug",
    "8": "Ago",
    "9": "Set",
    "10": "Ott",
    "11": "Nov",
    "12": "Dic"
  },
  "Yes": "Sì",
  "No": "No",
  "Cancel": "Annulla",
  "Clear": "Pulisci",
  ...
}

en.json

{
  "today": "Today",
  "day-labels": {
    "mo": "Mon",
    "tu": "Tue",
    "we": "Wed",
    "th": "Thu",
    "fr": "Fri",
    "sa": "Sat",
    "su": "Sun"
  },
  "month-labels": {
    "1": "Jan",
    "2": "Feb",
    "3": "Mar",
    "4": "Apr",
    "5": "May",
    "6": "Jun",
    "7": "Jul",
    "8": "Aug",
    "9": "Sep",
    "10": "Oct",
    "11": "Nov",
    "12": "Dec"
  },
  "Yes": "Yes",
  "No": "No",
  "Cancel": "Cancel",
  "Clear": "Clear",
  ...
}

Configurazione dei moduli

Per rendere funzionante il multilingua, è necessario configurare i moduli di base come negli esempi seguenti. Se si è utilizzato lo Scarface per creare il progetto, i seguenti passi non saranno necessari:

Il primo passo per iniziare, è configurare un factory che funga da loader delle traduzioni, come di seguito:

export function TranslateHttpLoaderFactory(http: HttpClient) {
  return new TranslateHttpLoader(http);
}

Nell’esempio sopra viene usato TranslateHttpLoader per caricare le traduzioni da “/assets/i18n/[lang].json ” ([lang] è la lingua corrente, che per inglese potrebbe essere en). E’ necessario importare TranslateModule.forRoot() nell’NgModule principale dell’applicazione. Il metodo statico forRoot è una convenzione che fornisce e configura servizi allo stesso tempo. E’ necessario assicurarsi di chiamare questo metodo solo nel modulo principale dell’applicazione (AppModule). Questo metodo consente di configurare TranslateModule specificando un loader, un parser e/o un gestore di traduzioni.

import { HttpClient } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { LocaleService } from '@ca-webstack/ng-i18n';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';

...

@NgModule({
  declarations: [
      ...
  ],
  imports:[
      ...
      TranslateModule.forRoot({
          loader: {
              provide: TranslateLoader,
              useFactory: TranslateHttpLoaderFactory,
              deps: [HttpClient]
          }
      }),
      ...
  ],
  providers: [
      ...
  ],
  bootstrap: [...]
})
export class AppModule {
  constructor(translate: TranslateService, locale: LocaleService) {
      const lang = navigator.language.substring(0, 2);
      translate.setDefaultLang('it');
      translate.use(lang);
      translate.addLangs(['it', 'en']);
      locale.setLocale(lang);
  }
}

Se si desidera configurare un TranslateLoader personalizzato (ad es. per caricare traduzioni dal server anziché dalle risorse locali), è necessario modificare l’implementazione del factory

...
export class CustomTranslateLoader implements TranslateLoader {
  constructor(private readonly http: HttpClient) { }

  public getTranslation(lang: string): Observable {
      return this.http.get(`${Config.API}/api/i18n/${lang}`);
  }
}

export function TranslateHttpLoaderFactory(http: HttpClient) {
  return new CustomTranslateLoader(http);
}
...

Se si utilizza uno SharedModule che viene importato in altri moduli (ad esempio ComponentsModule), è possibile importare e quindi esportare TranslateModule per assicurarsi di non doverlo importare in ogni modulo.

...
import { TranslateModule } from '@ngx-translate/core';

@NgModule({
  declarations: [],
  imports: [
    ...
    TranslateModule
  ],
  exports: [
    ...
    TranslateModule
  ],
...

Allo stesso modo, se si desidera utilizzare il modulo i18n (servizi e pipe) per tradurre mstring (chiave:valore) è necessario importare ed esportare i18nModule.

...
import { I18nModule } from '@ca-webstack/ng-i18n';

@NgModule({
  declarations: [],
  imports: [
    ...
    I18nModule
  ],
  exports: [
    ...
    I18nModule
  ],
...

Service Injection

E’ possibile sfruttare tutte le funzionalità offerte dal modulo Translate e dal modulo i18n, iniettando ovunque i relativi servizi singleton.

import { TranslateService } from '@ngx-translate/core';
import { I18nService } from '@ca-webstack/ng-i18n';
...
  public constructor( ...
    private _translateService: TranslateService,
    private _i18nService: I18nService ) {
    ...
...

E’ possibile sottoscriversi all’evento di cambio-lingua, come di seguito:

...
this._translateService.onLangChange.subscribe((lang: string) => ...));
...

Verificare qual è la lingua corrente:

...
this._translateService.currentLang
...

Cambiare lingua:

...
this._translateService.use('en');
...

E’ possibile anche definire le traduzioni manualmente con il metodo setTranslation:

...
this._translateService.setTranslation('en', {
  HELLO: 'hello {{value}}'
});
...

Tradurre una chiave direttamente da servizio:

...
await this._translateService.get('localized-string').toPromise()
...

Tradurre oggetti di tipo MString:

...
await this._i18nService.get({ key: 'localized-string', default: 'Localized string' }).toPromise();
await this._i18nService.get('localized-string').toPromise();
...

Pipe

Oltre al TranslateService, è possibile utilizzare la TranslatePipe per ottenere i valori di traduzione:

Questa è una stringa localizzata Questa è una variabile localizzata Ciao world Ciao Mondo Questa è una MString Fallback localized-string-2 Fallback string

Typescript file

...
protected localizedString = 'localized-variable';
protected i18nString = { key: 'i18n-mstring', default: 'Fallback string' };
protected i18nString2 = { key: 'i18n-mstring-2', default: 'Fallback string' };
...

it.json

{
  ...
  "localized-string": "Questa è una stringa localizzata",
  "localized-variable": "Questa è una variabile localizzata",
  "i18n-mstring": "Questa è una MString",
  "hello": "Ciao {{value}}",
  "world": "Mondo"
  ...
}

en.json

{
  ...
  "localized-string": "This is a localized string",
  "localized-variable": "This is a localized variable",
  "i18n-mstring": "This is an MString",
  "hello": "Hello {{value}}",
  "world": "World"
  ...
}

HTML File

<p>{{'localized-string' | translate}}</p>
<p>{{localizedString | translate}}</p>
<p>{{ 'hello' | translate:{value: 'world'} }}</p>
<p>{{ 'hello' | translate:{value: ('world' | translate)} }}</p>
<p>{{i18nString | i18n}}</p>
<br>
<p><b>Fallback</b></p>
<p>{{'localized-string-2' | translate}}</p>
<p>{{i18nString2 | i18n}}</p>

Directive

Oltre al TranslateService ed alla TranslatePipe, è possibile utilizzare la TranslateDirective per ottenere i valori di traduzione:

Questa è una stringa localizzata Questa è una variabile localizzata Ciao world Ciao Mondo

Typescript file

...
protected localizedString = 'localized-variable';
...

it.json

{
  ...
  "localized-string": "Questa è una stringa localizzata",
  "localized-variable": "Questa è una variabile localizzata",
  "hello": "Ciao {{value}}",
  "world": "Mondo",
  ...
}

en.json

{
  ...
  "localized-string": "This is a localized string",
  "localized-variable": "This is a localized variable",
  "i18n-mstring": "This is an MString",
  "hello": "Hello {{value}}",
  "world": "World",
  ...
}

HTML File

<p translate>localized-string</p>
<p translate>{{localizedString}}</p>
<p translate [translateParams]="{value: 'world'}">hello</p>
<p translate [translateParams]="{value: 'world' | translate}">hello</p>