=====@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, [[https://github.com/angular/angular/issues/29536|i18n Support in Angular Library]] {{ :lang:angular:traduction:i18n_support_in_angular_library_issue_29536_angular_angular_github_2021-08-22_23_58_04_.html |Archive du 27/03/2019 le 22/08/2021}} * On génère un site par langue. Cela duplique les ''assets''. [[https://angular.io/guide/i18n|Localizing your app]] {{ :lang:angular:traduction:angular_-_localizing_your_app_2021-08-22_00_24_04_.html |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. [[https://github.com/angular/angular-cli/issues/6552|ng-xi18n: Merge/Update Existing Translations File (XLIFF)]] {{ :lang:angular:traduction:ng-xi18n_merge_update_existing_translations_file_xliff_issue_6552_angular_angular-cli_github_2021-08-22_00_29_07_.html |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 [[https://angular.io/guide/i18n|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. [[https://github.com/angular/angular-cli/issues/17140|ng xi18n not working for library]] {{ :lang:angular:traduction:ng_xi18n_not_working_for_library_issue_17140_angular_angular-cli_2021-08-22_01_17_44_.html |Archive du 03/03/2020 le 23/08/2021}} { "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'': /****************************************************************************** * 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'': /****************************************************************************** * 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. * 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 ''...'', ajouter la traduction ''...''. Width: Largeur : La traduction peut aussi gérer le ''binding'' :
Form Values: {{ result | json }}
Form Values: Résultats : =====@ngx-translate/core===== [[https://github.com/ngx-translate/core|Site web]] ====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 [[https://github.com/ngx-translate/core/issues/199#issuecomment-339084987|Loading Multiple file from a directory]] {{ :lang:angular:traduction:loading_multiple_file_from_a_directory._issue_199_ngx-translate_core_github_2021-08-24_20_45_19_.html |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=== Un exemple simple : [[https://blog.angulartraining.com/how-to-internationalize-i18n-your-angular-application-tutorial-dee2c6984bc1|How to internationalize (i18n) your Angular application?]] {{ :lang:angular:traduction:how_to_internationalize_i18n_your_angular_application_tutorial_by_alain_chautard_angular_training_2021-10-09_22_38_52_.html |Archive du 02/04/2019 le 09/10/2021}} Un autre exemple plus complet avec uniquement une application: [[https://blog.briebug.com/blog/internationalizing-your-angular-app|Internationalizing your Angular app]] {{ :lang:angular:traduction:internationalizing_your_angular_app_2021-10-02_09_46_07_.html |Archive du 20/08/2019 le 02/10/2021}} Exemple bien détaillé avec une librairie et une application: [[https://medium.com/@lopesgon/translate-angular-4-with-ngx-translate-and-multiple-modules-7d9f0252f139|Translate Angular >=4 with ngx-translate and multiple modules]] {{ :lang:angular:traduction:translate_angular_4_with_ngx-translate_and_multiple_modules_by_frederic_lopes_medium_2021-08-24_20_55_45_.html |Archive du 09/08/2017 le 24/08/2021}} * Librairie Il faut exporter le module de traduction. [[https://github.com/ngx-translate/core/blob/master/README.md#sharedmodule|@ngx-translate/core - SharedModule]] {{ :lang:angular:traduction:core_readme.md_at_master_ngx-translate_core_github_2021-08-24_23_54_17_.html |Archive du 28/05/2021 le 24/08/2021}} import { TranslateModule } from '@ngx-translate/core'; @NgModule({ imports: [..., TranslateModule], exports: [ ..., TranslateModule ] }) * Application import { TranslateService } from '@ngx-translate/core'; export class AppComponent { ... constructor(public translate: TranslateService) { translate.addLangs(['en', 'fr']); translate.setDefaultLang('en'); } } 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 { 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); }); }) ); } } 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' }) ], ... }) ... ===Lazy load=== Pour éviter de devoir charger toutes les langues possibles, il faut charger dynamiquement les locales. import { registerLocaleData } from '@angular/common'; const locale = await import( /* webpackInclude: /(en|fr)\.js$/ */ '@angular/common/locales/' + selectedLang ); registerLocaleData(locale.default, selectedLang); translate.use(selectedLang); Ici, translate est ''TranslateService''. L'utilisation de ''webpackInclude'' permet de ne pas charger toutes les langues mais uniquement celles supportées. [[https://medium.com/angular-in-depth/dynamic-import-of-locales-in-angular-b994d3c07197|Dynamic Import of Locales in Angular]] {{ :lang:angular:traduction:dynamic_import_of_locales_in_angular_by_michael_karen_angular_in_depth_medium_2021-10-10_18_22_30_.html |Archive du 14/11/2018 le 10/10/2021}} ====Traduction==== * HTML {{ 'HOME.TITLE' | translate }} * Traduction { "HOME": { "TITLE": "Calculator for Meherhof foundation!" } } ====Tests==== [[https://stackoverflow.com/questions/53370590/ngx-translate-how-to-test-components|ngx-translate how to test components]] {{ :lang:angular:traduction:angular_-_ngx-translate_how_to_test_components_-_stack_overflow_2021-08-24_21_09_41_.html |Archive du 09/11/2019 le 24/08/2021}} [[https://dev.to/rmuhlfeldner/how-to-fix-ngx-translate-error-when-running-tests-5ado|How to fix ngx-translate error when running tests]] {{ :lang:angular:traduction:how_to_fix_ngx-translate_error_when_running_tests_-_dev_community_2021-08-24_23_50_51_.html |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 : 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 : 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 : import { TranslateMockPipe } from '../../../util/translation/translate-mock.pipe'; describe('FoundationStripFormComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ ..., declarations: [..., TranslateMockPipe] }).compileComponents(); }); import { Pipe, PipeTransform } from '@angular/core'; @Pipe({ name: 'translate' }) export class TranslateMockPipe implements PipeTransform { public name = 'translate'; public transform(query: string): string { return query; } } export * from './lib/util/translation/translate-mock.pipe'; =====globalize.js===== ====Présentation==== [[https://github.com/globalizejs/globalize|Site web]] C'est une librairie JavaScript (compatible TypeScript via ''@types'') pour convertir un nombre en texte et un texte en nombre en respectant des locales précises. Les données de localisation viennent d'un paquet npm ''cldr-data'' qui utilise les données du consortium [[https://cldr.unicode.org/|Unicode]]. Ces données viennent en doublon avec le pipe "nombre" de ''@ngx-translate'' mais il faudra l'accepter. ====Utilisation==== La librairie est simple à utiliser. Ci-dessous, un exemple pour convertir un nombre dans une certaine langue vers une autre langue. La particularité ici est l'utilisation du lazy load pour ne charger dynamiquement que les deux langues nécessaire. Il est nécessaire d'installer les paquets ''globalize'' et ''@types/globalize''. { "compilerOptions": { "paths": { "cldr": ["./projects/app-main/node_modules/cldrjs/dist/cldr"], "cldr/*": ["./projects/app-main/node_modules/cldrjs/dist/cldr/*"], "globalize/*": [ "./projects/app-main/node_modules/globalize/dist/globalize/*" ], ... } }, ... } import likelySubtags from 'cldr-data/supplemental/likelySubtags.json'; import numberingSystems from 'cldr-data/supplemental/numberingSystems.json'; import * as globalize from 'globalize'; import 'globalize/number'; globalize.load([likelySubtags, numberingSystems]); const cldrLocale = await import( /* webpackInclude: /main.(en|fr).numbers.json/ */ 'cldr-data/main/' + selectedLang + '/numbers.json' ); globalize.load(cldrLocale.default); let parserFrom = globalize.locale(from).numberParser(); let parserTo = globalize.locale(to).numberFormatter(); [[https://medium.com/@penghuili/how-to-use-globalizejs-4a30d3919c8f|How to use Globalizejs]] {{ :lang:angular:traduction:how_to_use_globalizejs._at_ginmon_our_frontend_supports_3_by_penghui_li_medium_2021-10-10_18_19_28_.html |Archive du 05/04/2019 le 10/10/2021}} L'utilisation du commentaire ''webpackInclude'' permet à Angular de n'inclure dans la version finale du site que quelques locales.