Ceci est une ancienne révision du document !
Table des matières
@angular/localize
Présentation
Le système de traduction natif intégré à Angular.
Avantages :
- Pas de dépendances externes,
- Le texte est traduit en dur dans le code généré, pas de pipe,
- On compile une fois mais on génère un site par langue.
Inconvénient :
- On ne peut pas traduire des librairies, i18n Support in Angular Library Archive du 27/03/2019 le 22/08/2021
- On génère un site par langue. Cela duplique les
assets
. Localizing your app Archive du 12.2.3 le 22/08/2021 - Il n'est que possible de générer la liste des textes à traduire. Il n'est pas possible de mettre à jour une liste des traductions. ng-xi18n: Merge/Update Existing Translations File (XLIFF) Archive du 02/06/2017 le 23/08/2021
- Il n'est pas possible de changer la langue sans changer de page HTML,
Initialisation
Installation
npm i --save @angular/localize
Configuration
Il faut activer les options localize
et aot
. Voir la i18n d'Angular.
Dans le code source, on met une langue par défaut (anglais par exemple) et la traduction dans le fichier .xlf
.
Ajouter l'action extract-i18n
dans la librairie qu'on souhaite traduire. ng xi18n not working for library Archive du 03/03/2020 le 23/08/2021
- angular.json
{ "projects": { "lib-library": { "architect": { "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "angular-i18n:build" } } } }, "app-main": { "i18n": { "sourceLocale": "en-US", "locales": { "fr": "projects/app-main/src/locale/messages.fr.xlf" } }, "architect": { "build": { "options": { "localize": true, "aot": true } } } } } }
Sources
- Librairie
Il faut ajouter au fichier test.ts
:
- test.ts
/****************************************************************************** * Load `$localize` onto the global scope - used if i18n tags appear in Angular * templates. */ import '@angular/localize/init';
- Application
Il faut ajouter la même chose au fichier polyfills.ts
:
- polyfills.ts
/****************************************************************************** * Load `$localize` onto the global scope - used if i18n tags appear in Angular * templates. */ import '@angular/localize/init';
Traduction
.html
Il suffit d'ajouter un attribut i18n
. Il est possible d'ajouter des catégories aux textes descriptifs.
<label for="width" i18n="input form|Foundation strip width">Width: </label>
- Extraction des données
ng extract-i18n --output-path ./projects/app-main/src/locale
S'il y a une librairie et une application, la traduction fusionne les textes de la librairie et de l'application.
- Traduire la langue
Copier le fichier généré dans ./projects/app-main/src/locale/messages.xlf
.
En dessous de chaque <source>…</source>
, ajouter la traduction <target>…</target>
.
<source>Width: </source> <target>Largeur : </target>
La traduction peut aussi gérer le binding
:
<pre i18n="output form|Output of Meyerhof calculation"> Form Values: {{ result | json }}</pre>
<source>Form Values: <x id="INTERPOLATION"/></source> <target>Résultats : <x id="INTERPOLATION"/></target>
@ngx-translate/core
Présentation
L'inverse de @angular/localize
. C'est donc une dépendance externe à Angular.
Avantages :
- Un seul site dont la langue est changeable sans recharger,
- On peut avoir un fichier de traduction distinct par librairie et par application Loading Multiple file from a directory Archive du 16/08/2016 le 24/08/2021
Inconvénient :
- Comme c'est une dépendance externe, on ne profite pas d'une intégration profonde des avantages du compilateur,
- Dépendance externe,
- Le texte est traduit à la volée. Avant la conversion, le texte est manquant. Cela peut donc réduire l'expérience utilisateur,
- Nécessite de définir l'utilisation d'un pipe pour chaque composant.
Initialisation
Installation
npm i --save @ngx-translate/core
Configuration
Il n'y a besoin de rien.
Sources
Exemple bien détaillé avec une librairie et une application: Translate Angular >=4 with ngx-translate and multiple modules Archive du 09/08/2017 le 24/08/2021
- Librairie
Il faut exporter le module de traduction. @ngx-translate/core - SharedModule Archive du 28/05/2021 le 24/08/2021
- lib-jessica/src/lib/lib-jessica.module.ts
import { TranslateModule } from '@ngx-translate/core'; @NgModule({ imports: [..., TranslateModule], exports: [ ..., TranslateModule ] })
- Application
- app-main/src/app/app.component.spec.ts
import { TranslateService } from '@ngx-translate/core'; export class AppComponent { ... constructor(public translate: TranslateService) { translate.addLangs(['en', 'fr']); translate.setDefaultLang('en'); } }
- app-main/src/app/util/translate/multi-translate-http-loader.ts
import { HttpClient } from '@angular/common/http'; import { TranslateLoader } from '@ngx-translate/core'; import { forkJoin, Observable } from 'rxjs'; import { map } from 'rxjs/operators'; export class MultiTranslateHttpLoader implements TranslateLoader { constructor( private http: HttpClient, public resources: { prefix: string; suffix: string }[] = [ { prefix: './assets/i18n/', suffix: '.json' } ] ) {} public getTranslation(lang: string): Observable<unknown> { return forkJoin( this.resources.map((config) => { return this.http.get(`${config.prefix}${lang}${config.suffix}`); }) ).pipe( map((response) => { return response.reduce((a, b) => { return Object.assign(a, b); }); }) ); } }
- app-main/src/app/app.module.ts
import { HttpClient, HttpClientModule } from '@angular/common/http'; import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; import { MultiTranslateHttpLoader } from './util/translate/multi-translate-http-loader'; export function createTranslateLoader(http: HttpClient): TranslateLoader { return new MultiTranslateHttpLoader(http, [ { prefix: './assets/i18n/', suffix: '.json' }, { prefix: './assets/i18n/library-', suffix: '.json' } ]); } @NgModule({ ..., imports: [ ..., HttpClientModule, TranslateModule.forRoot({ loader: { provide: TranslateLoader, useFactory: createTranslateLoader, deps: [HttpClient] }, defaultLanguage: 'en' }) ], ... }) ...
Traduction
- HTML
{{ 'HOME.TITLE' | translate }}
- Traduction
- app-main/src/assets/i18n/en.json
{ "HOME": { "TITLE": "Calculator for Meherhof foundation!" } }
Tests
ngx-translate how to test components Archive du 09/11/2019 le 24/08/2021
How to fix ngx-translate error when running tests Archive du 02/10/2019 le 24/08/2021
Pour les tests unitaires (pas end-to-end), il n'est généralement pas nécessaire de charger la librairie. Avantage : gain de temps. Inconvénient, l'aspect graphique ne sera pas conforme.
Dans le composant principal de l'application :
- app-main/src/app/app.component.spec.ts
import { TranslateFakeLoader, TranslateLoader, TranslateModule } from '@ngx-translate/core'; describe('AppComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ ..., TranslateModule.forRoot({ loader: { provide: TranslateLoader, useClass: TranslateFakeLoader } }) ], ...
Dans chaque composant de l'application, on utilise le pipe de traduction de la librairie :
- app-main/src/app/ui/main/main.component.spec.ts
import { TranslateMockPipe } from 'lib-library'; describe('MainComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ ..., TranslateMockPipe ] }).compileComponents(); });
Dans chaque composant de la librairie, on utilise le même pipe de traduction :
- lib-jessica/src/lib/xxx.component.spec.ts
import { TranslateMockPipe } from '../../../util/translation/translate-mock.pipe'; describe('FoundationStripFormComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ ..., declarations: [..., TranslateMockPipe] }).compileComponents(); });
- lib-library/src/lib/translate-mock.pipe.ts
import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'translate' }) export class TranslateMockPipe implements PipeTransform { public name = 'translate'; public transform(query: string): string { return query; } }
- projects/lib-jessica/src/public-api.ts
export * from './lib/util/translation/translate-mock.pipe';