From fa90659fe09f12ae9254eda8e04e2b4957621097 Mon Sep 17 00:00:00 2001 From: Olivier Combe Date: Sun, 11 Sep 2016 21:09:22 +0200 Subject: [PATCH 1/2] docs(i18n): add internationalization (i18n) guide --- gulpfile.js | 4 +- public/docs/_examples/cb-i18n/e2e-spec.ts | 13 + public/docs/_examples/cb-i18n/ts/.gitignore | 6 + .../cb-i18n/ts/app/app.component.1.html | 11 + .../cb-i18n/ts/app/app.component.html | 4 + .../_examples/cb-i18n/ts/app/app.component.ts | 10 + .../_examples/cb-i18n/ts/app/app.module.ts | 13 + .../_examples/cb-i18n/ts/app/i18n/fr/main.ts | 33 ++ .../cb-i18n/ts/app/i18n/fr/messages.fr.1.ts | 5 + .../cb-i18n/ts/app/i18n/fr/messages.fr.ts | 17 + .../cb-i18n/ts/app/i18n/fr/messages.fr.xlf | 13 + .../ts/app/i18n/fr/messages.fr.xlf.html | 17 + .../cb-i18n/ts/app/i18n/trans-unit.html | 7 + public/docs/_examples/cb-i18n/ts/app/main.ts | 7 + .../_examples/cb-i18n/ts/example-config.json | 0 public/docs/_examples/cb-i18n/ts/index.html | 45 +++ public/docs/_examples/cb-i18n/ts/plnkr.json | 10 + public/docs/_examples/package.json | 3 +- public/docs/dart/latest/cookbook/_data.json | 6 + public/docs/dart/latest/cookbook/i18n.jade | 1 + public/docs/dart/latest/guide/i18n.jade | 1 + public/docs/js/latest/cookbook/_data.json | 6 + public/docs/js/latest/cookbook/i18n.jade | 1 + public/docs/js/latest/guide/i18n.jade | 1 + public/docs/ts/latest/cookbook/_data.json | 5 + public/docs/ts/latest/cookbook/i18n.jade | 319 ++++++++++++++++++ public/docs/ts/latest/guide/_data.json | 4 +- 27 files changed, 557 insertions(+), 5 deletions(-) create mode 100644 public/docs/_examples/cb-i18n/e2e-spec.ts create mode 100644 public/docs/_examples/cb-i18n/ts/.gitignore create mode 100644 public/docs/_examples/cb-i18n/ts/app/app.component.1.html create mode 100644 public/docs/_examples/cb-i18n/ts/app/app.component.html create mode 100644 public/docs/_examples/cb-i18n/ts/app/app.component.ts create mode 100644 public/docs/_examples/cb-i18n/ts/app/app.module.ts create mode 100644 public/docs/_examples/cb-i18n/ts/app/i18n/fr/main.ts create mode 100644 public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.1.ts create mode 100644 public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.ts create mode 100644 public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf create mode 100644 public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf.html create mode 100644 public/docs/_examples/cb-i18n/ts/app/i18n/trans-unit.html create mode 100644 public/docs/_examples/cb-i18n/ts/app/main.ts create mode 100644 public/docs/_examples/cb-i18n/ts/example-config.json create mode 100644 public/docs/_examples/cb-i18n/ts/index.html create mode 100644 public/docs/_examples/cb-i18n/ts/plnkr.json create mode 100644 public/docs/dart/latest/cookbook/i18n.jade create mode 100644 public/docs/dart/latest/guide/i18n.jade create mode 100644 public/docs/js/latest/cookbook/i18n.jade create mode 100644 public/docs/js/latest/guide/i18n.jade create mode 100644 public/docs/ts/latest/cookbook/i18n.jade diff --git a/gulpfile.js b/gulpfile.js index ac3ee61bac..899c401d54 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -297,7 +297,7 @@ function runE2eTsTests(appDir, outputFile) { } catch (e) { exampleConfig = {}; } - + var config = { build: exampleConfig.build || 'tsc', run: exampleConfig.run || 'http-server:e2e' @@ -1263,7 +1263,7 @@ function apiExamplesWatch(postShredAction) { } function devGuideExamplesWatch(shredOptions, postShredAction, focus) { - var watchPattern = focus ? '**/' + focus + '/**/*.*' : '**/*.*'; + var watchPattern = focus ? '**/{' + focus + ',cb-' + focus+ '}/**/*.*' : '**/*.*'; var includePattern = path.join(shredOptions.examplesDir, watchPattern); // removed this version because gulp.watch has the same glob issue that dgeni has. // var excludePattern = '!' + path.join(shredOptions.examplesDir, '**/node_modules/**/*.*'); diff --git a/public/docs/_examples/cb-i18n/e2e-spec.ts b/public/docs/_examples/cb-i18n/e2e-spec.ts new file mode 100644 index 0000000000..6606ca8878 --- /dev/null +++ b/public/docs/_examples/cb-i18n/e2e-spec.ts @@ -0,0 +1,13 @@ +/// +'use strict'; +describe('i18n E2E Tests', () => { + + beforeEach(function () { + browser.get(''); + }); + + it('should display i18n translated welcome: Bonjour i18n!', function () { + expect(element(by.css('h1')).getText()).toEqual('Bonjour i18n!'); + }); + +}); diff --git a/public/docs/_examples/cb-i18n/ts/.gitignore b/public/docs/_examples/cb-i18n/ts/.gitignore new file mode 100644 index 0000000000..8357331dc7 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/.gitignore @@ -0,0 +1,6 @@ +**/*.ngfactory.ts +**/*.metadata.json +**/messages.xlf +dist +!app/tsconfig.json +!rollup.js \ No newline at end of file diff --git a/public/docs/_examples/cb-i18n/ts/app/app.component.1.html b/public/docs/_examples/cb-i18n/ts/app/app.component.1.html new file mode 100644 index 0000000000..7813de7d31 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/app.component.1.html @@ -0,0 +1,11 @@ + +

Hello i18n!

+ + + +

Hello i18n!

+ + + +

Hello i18n!

+ diff --git a/public/docs/_examples/cb-i18n/ts/app/app.component.html b/public/docs/_examples/cb-i18n/ts/app/app.component.html new file mode 100644 index 0000000000..3469b42e86 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/app.component.html @@ -0,0 +1,4 @@ + + +

Hello i18n!

+ \ No newline at end of file diff --git a/public/docs/_examples/cb-i18n/ts/app/app.component.ts b/public/docs/_examples/cb-i18n/ts/app/app.component.ts new file mode 100644 index 0000000000..e065c38917 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/app.component.ts @@ -0,0 +1,10 @@ +// #docregion +import { Component } from '@angular/core'; + +@Component({ + moduleId: module.id, + selector: 'my-app', + templateUrl: 'app.component.html' +}) +export class AppComponent { } + diff --git a/public/docs/_examples/cb-i18n/ts/app/app.module.ts b/public/docs/_examples/cb-i18n/ts/app/app.module.ts new file mode 100644 index 0000000000..64ad44075b --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/app.module.ts @@ -0,0 +1,13 @@ +// #docregion +import { NgModule } from '@angular/core'; +import { BrowserModule } from '@angular/platform-browser'; + +import { AppComponent } from './app.component'; + +@NgModule({ + imports: [ BrowserModule ], + declarations: [ AppComponent ], + bootstrap: [ AppComponent ] +}) + +export class AppModule { } diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/main.ts b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/main.ts new file mode 100644 index 0000000000..53054d4d6a --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/main.ts @@ -0,0 +1,33 @@ +// #docplaster +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID } from '@angular/core'; + +import { AppModule } from '../../app.module'; +// #docregion translation-import +import { translations } from './messages.fr'; +// #enddocregion translation-import + +// #enddocregion +/* + // Webpack users don't need to create + // They simply define `translations` here and let webpack load it: +// #docregion webpack + const translations = require("raw!./cb-i18n/messages.fr.xlf"); +// #enddocregion webpack +*/ + +// #docregion +// Compile using french translations +const platform = platformBrowserDynamic(); + +platform.bootstrapModule( + AppModule, + { + providers: [ + {provide: TRANSLATIONS, useValue: translations}, + {provide: TRANSLATIONS_FORMAT, useValue: 'xlf'}, + {provide: LOCALE_ID, useValue: 'fr'} + ] + } +); diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.1.ts b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.1.ts new file mode 100644 index 0000000000..33d43e2bc2 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.1.ts @@ -0,0 +1,5 @@ +// #docregion +export const translation = ` + PASTE HERE +`; + diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.ts b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.ts new file mode 100644 index 0000000000..35fd9f2f6e --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.ts @@ -0,0 +1,17 @@ +// #docregion +export const translations = ` + + + + + + Hello i18n! + Bonjour i18n! + An introduction header for this sample + User welcome + + + + +`; + diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf new file mode 100644 index 0000000000..f6b0094bd9 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf @@ -0,0 +1,13 @@ + + + + + + Hello i18n! + + An introduction header for this sample + User welcome + + + + \ No newline at end of file diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf.html b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf.html new file mode 100644 index 0000000000..2130c25275 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf.html @@ -0,0 +1,17 @@ + + + + + + + + + Hello i18n! + Bonjour i18n! + An introduction header for this sample + User welcome + + + + + diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/trans-unit.html b/public/docs/_examples/cb-i18n/ts/app/i18n/trans-unit.html new file mode 100644 index 0000000000..6cb66ca12d --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/i18n/trans-unit.html @@ -0,0 +1,7 @@ + + + Hello i18n! + + An introduction header for this sample + User welcome + diff --git a/public/docs/_examples/cb-i18n/ts/app/main.ts b/public/docs/_examples/cb-i18n/ts/app/main.ts new file mode 100644 index 0000000000..e11324f519 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/main.ts @@ -0,0 +1,7 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app.module'; + +const platform = platformBrowserDynamic(); +platform.bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-i18n/ts/example-config.json b/public/docs/_examples/cb-i18n/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/cb-i18n/ts/index.html b/public/docs/_examples/cb-i18n/ts/index.html new file mode 100644 index 0000000000..f6414770c8 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/index.html @@ -0,0 +1,45 @@ + + + + + Angular i18n example + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Loading... + + + diff --git a/public/docs/_examples/cb-i18n/ts/plnkr.json b/public/docs/_examples/cb-i18n/ts/plnkr.json new file mode 100644 index 0000000000..9886709b1e --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/plnkr.json @@ -0,0 +1,10 @@ +{ + "description": "i18n", + "files": [ + "!**/*.d.ts", + "!**/*.js", + "!**/*.[1].*", + "!**/*.metadata.json" + ], + "tags": ["i18n"] +} \ No newline at end of file diff --git a/public/docs/_examples/package.json b/public/docs/_examples/package.json index 238bfd53a1..a02f6f022a 100644 --- a/public/docs/_examples/package.json +++ b/public/docs/_examples/package.json @@ -20,7 +20,8 @@ "test:webpack": "karma start karma.webpack.conf.js", "build:webpack": "rimraf dist && webpack --config config/webpack.prod.js --bail", "build:cli": "ng build", - "build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup.js" + "build:aot": "ngc -p tsconfig-aot.json && rollup -c rollup.js", + "extract": "ng-xi18n" }, "keywords": [], "author": "", diff --git a/public/docs/dart/latest/cookbook/_data.json b/public/docs/dart/latest/cookbook/_data.json index f0c0dad0d4..e12d383b14 100644 --- a/public/docs/dart/latest/cookbook/_data.json +++ b/public/docs/dart/latest/cookbook/_data.json @@ -47,6 +47,12 @@ "hide": true }, + "i18n": { + "title": "Internationalization (i18n)", + "intro": "Translate the app's template text into multiple languages", + "hide": true + }, + "rc4-to-rc5": { "title": "RC4 to RC5 Migration", "intro": "Migrate your RC4 app to RC5 in minutes.", diff --git a/public/docs/dart/latest/cookbook/i18n.jade b/public/docs/dart/latest/cookbook/i18n.jade new file mode 100644 index 0000000000..c743361ac8 --- /dev/null +++ b/public/docs/dart/latest/cookbook/i18n.jade @@ -0,0 +1 @@ +include ../../../_includes/_ts-temp diff --git a/public/docs/dart/latest/guide/i18n.jade b/public/docs/dart/latest/guide/i18n.jade new file mode 100644 index 0000000000..6778b6af28 --- /dev/null +++ b/public/docs/dart/latest/guide/i18n.jade @@ -0,0 +1 @@ +!= partial("../../../_includes/_ts-temp") diff --git a/public/docs/js/latest/cookbook/_data.json b/public/docs/js/latest/cookbook/_data.json index a5e0ca3011..5660152bd5 100644 --- a/public/docs/js/latest/cookbook/_data.json +++ b/public/docs/js/latest/cookbook/_data.json @@ -42,6 +42,12 @@ "intro": "Validate user's form entries" }, + "i18n": { + "title": "Internationalization (i18n)", + "intro": "Translate the app's template text into multiple languages", + "hide": true + }, + "rc4-to-rc5": { "title": "RC4 to RC5 Migration", "intro": "Migrate your RC4 app to RC5 in minutes.", diff --git a/public/docs/js/latest/cookbook/i18n.jade b/public/docs/js/latest/cookbook/i18n.jade new file mode 100644 index 0000000000..c743361ac8 --- /dev/null +++ b/public/docs/js/latest/cookbook/i18n.jade @@ -0,0 +1 @@ +include ../../../_includes/_ts-temp diff --git a/public/docs/js/latest/guide/i18n.jade b/public/docs/js/latest/guide/i18n.jade new file mode 100644 index 0000000000..6778b6af28 --- /dev/null +++ b/public/docs/js/latest/guide/i18n.jade @@ -0,0 +1 @@ +!= partial("../../../_includes/_ts-temp") diff --git a/public/docs/ts/latest/cookbook/_data.json b/public/docs/ts/latest/cookbook/_data.json index d5c3a60bc4..10c8792d5b 100644 --- a/public/docs/ts/latest/cookbook/_data.json +++ b/public/docs/ts/latest/cookbook/_data.json @@ -46,6 +46,11 @@ "intro": "Validate user's form entries" }, + "i18n": { + "title": "Internationalization (i18n)", + "intro": "Translate the app's template text into multiple languages" + }, + "rc4-to-rc5": { "title": "RC4 to RC5 Migration", "intro": "Migrate your RC4 app to RC5 in minutes." diff --git a/public/docs/ts/latest/cookbook/i18n.jade b/public/docs/ts/latest/cookbook/i18n.jade new file mode 100644 index 0000000000..06d4fb7798 --- /dev/null +++ b/public/docs/ts/latest/cookbook/i18n.jade @@ -0,0 +1,319 @@ +include ../_util-fns + +:marked + Angular's _internationalization_ ("_i18n_") tools help make your app availble in multiple languages. + + + ## Table of contents + + * [Angular and i18n template translation](#angular-i18n) + * [Mark text with the _i18n_ attribute](#i18n-attribute) + * [Extract text with ng-xi18n](#ng-xi18n) + * [Translate](#translate) + * [Merge the translation file into the app](#merge) + * [JiT configuration](#jit) + * [AoT configuration](#aot) + +:marked + **Try this** live example of a JiT-compiled app, translated into French. + + +a#angular-i18n +.l-main-section +:marked + ## Angular and _i18n_ template translation + + Application internationalization is a challenging, many-faceted effort that + takes dedication and enduring commitment. + Angular's _i18n_ internationalization facilities can help. + + This page describes the _i18n_ tools to assist translation of component template text + into multiple languages. + +.l-sub-section + :marked + Practitioners of _internationalization_ refer to a translatable text as a "_message_". + This page uses the words "_text_" and "_message_" interchangably and in the combination, "_text message_". + +:marked + The _i18n_ template translation process has four phases: + + 1. Mark static text messages in your component templates for translation. + + 1. An angular _i18n_ tool extracts the marked messages into an industry standard translation source file. + + 1. A translator edits that file, translating the extracted text messages into the target language, + and returns the file to you. + + 1. The Angular compiler imports the completed translation files, + replaces the original messages with translated text, and generates a new version of the application + in the target language. + + You build and deploy a separate version of the application for each supported language. + +a#i18n-attribute +.l-main-section +:marked + ## Mark text with the _i18n_ attribute + + The Angular `i18n` attribute is a marker for translatable content. + Place it on every element tag whose fixed text should be translated. + +.alert.is-helpful + :marked + `i18n` is not an Angular _directive_. It's a custom _attribute_, recognized by Angular tools and compilers. + +:marked + In the accompanying sample, an `

` tag displays a simple English language greeting which you will translate to French: ++makeExample('cb-i18n/ts/app/app.component.1.html', 'greeting', 'app/app.component.html')(format=".") +:marked + Add the `i18n` attribute to the tag to mark it for translation. + ++makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-attribute', 'app/app.component.html')(format=".") + +:marked + The translator may need a description of the message to translate it accurately. + Assign a description to the i18n attribute: + ++makeExample('cb-i18n/ts/app/app.component.1.html', 'i18n-attribute-desc', 'app/app.component.html')(format=".") + +:marked + The true _meaning_ of the text may require some application context. + Add a contextual meaning to the assigned string, separating it from the description with the `|` character: + ++makeExample('cb-i18n/ts/app/app.component.html', 'i18n-attribute-meaning', 'app/app.component.html')(format=".") + +:marked + While all appearance of a message with the _same_ meaning should have the _same_ translation, + a message with *different meanings* could have different translations. + The Angular extraction tool preserves both the _meaning_ and the _description_ in the translation source file + to facilitiate contextually-specific transations. + +a#ng-xi18n +.l-main-section +:marked + ## Extract translatable text with the _ng-xi18n_ command + + Use the `ng-xi18n` extraction tool to generate a translation source file in an industry standard format. + + This is an Angular CLI tool based on the `ngc` compiler in the `@angular/compiler-cli` npm package. + If you haven't already installed the CLI and its `platform-server` peer dependency, do so now: + +code-example(language="sh" class="code-shell"). + npm install @angular/compiler-cli @angular/platform-server --save + +:marked + Open a terminal window at the root of the application project and enter the `ng-xi18n` command: + +code-example(language="sh" class="code-shell"). + ./node_modules/.bin/ng-xi18n + +:marked + By default the tool generates a translation file named **`messages.xlf`** in the + XML Localisation Interchange File Format (XLIFF, version 1.2). + +code-example(language="sh" class="code-shell"). + ./node_modules/.bin/ng-xi18n --i18nFormat=xmb + +.l-sub-section + :marked + Windows users may have to quote the command: + code-example(language="sh"). + "./node_modules/.bin/ng-xi18n" + :marked + Consider adding a convenience shortcut to the `scripts` section of the `package.json` + to make the command easier to remember and run: + code-example(format='.'). + "scripts": { + "i18n": "ng-xi18n", + ... + } + :marked + Now you can enter: + code-example(language="sh" class="code-shell"). + npm run i18n + +:marked + ### Other translation formats + + You can generate a file named **`messages.xmb`** in the + XML Message Bundle (XMB) format + by adding the `--i18nFormat=xmb` switch. + + This sample sticks with the _XLIFF_ format. + +a#translate +.l-main-section +:marked + ## Translate _le text + + The `ng-xi18n` command generated a translation source file in the project root folder named `messages.xlf`. + + ### Create an i18n project structure + + You're probably translating into multiple languages so it's a good idea + for the project structure to reflect your entire internationalization effort. + + One approach is to create an `i18n` folder with subfolders for each language or locale, e.g. `i18n/fr` for French. + This sample puts `i18n/fr` under the `app` folder but you can adjust to suit your preferences. + + Move the `messages.xlf` under `i18n` where it will become the source for all language-specific translations. + Then copy `messages.xlf` into `i18n/fr` and rename it as `messages.fr.xlf` . + + ### Translate + In the real world, you send this file to a French translator who would fill in the translations + using one of the + many XLIFF file editors. + + This sample file is easy to translate without a special editor or knowledge of French. + Open `messages.fr.xlf` and find the `` section: + ++makeExample('cb-i18n/ts/app/i18n/trans-unit.html', '', 'app/i18n/messages.fr.xlf ()')(format=".") +:marked + This XML element represents the translation of the `

` greeting tag you marked with the `i18n` attribute. + The `id` may be different. + Its value depends on the content of the message, its meaning, and its description. + Change any of these factors and the `id` changes as well. + + Replace the `` tag with the French greeting: ++makeExample('cb-i18n/ts/app/i18n/fr/messages.fr.xlf.html', 'trans-unit', 'app/i18n/fr/messages.fr.xlf (, after translation)')(format=".") +:marked +.alert.is-helpful + :marked + Repeat the extraction process whenever you add new app messages or edit existing ones. + Be careful not to lose the previous translations. + Specialized software can help manage the change process. + +#app-pre-translation +:marked + ### The app before translation + + After the previous steps, the sample app _and_ its translation file are as follows: + ++makeTabs(` + cb-i18n/ts/app/app.component.html, + cb-i18n/ts/app/app.component.ts, + cb-i18n/ts/app/app.module.ts, + cb-i18n/ts/app/main.ts, + cb-i18n/ts/app/i18n/fr/messages.fr.xlf.html +`, '', ` + app/app.component.html, + app/app.component.ts, + app/app.module.ts, + app/main.ts, + app/i18n/fr/messages.fr.xlf +`) + +a#merge +.l-main-section +:marked + ## Merge the translation file + + To merge the translated text into component templates, + you compile the application with the completed translation file. + The process is the same whether the file is in `.xlf` format or + in one of the other formats (`.xlif` and `.xtb`) that Angular understands. + + You provide the Angular compiler with three new pieces of information: + * the translation file + * the translation file format + * the _Locale ID_ (`en-US` for instance) + + _How_ you provide this information depends upon whether you compile with + the JiT (_Just-in-Time_) compiler or the AoT (_Ahead-of-Time_) compiler. + + * With [JiT](#jit), you provide the information at bootstrap time. + * With [AoT](#aot), you pass the information as `ngc` options. + + The next two sections cover the details. + + +a#jit +.l-main-section +:marked + ### Merge with the JiT compiler + + Copy `app/main.ts` into the `app/i18n/fr` folder. + + Open this copy and add a second, _options_ argument to the bootstrap method. + The _options_ has one property, `providers`. + Give it an array of three translation providers: + * `TRANSLATIONS` is a string containing the content of the translation file. + * `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlif` or `xtb` + * `LOCALE_ID` is the locale of the target language. + + Adjust the `AppModule` import statement which now is two levels up the folder tree. + + Here is the revised `app/i18n/fr/main.ts` for this sample: + ++makeExample('cb-i18n/ts/app/i18n/fr/main.ts', null, 'app/i18n/fr/main.ts')(format=".") + +:marked + ### Convert the translation file to a string constant + + Notice that the translation is imported from a TypeScript file, not the translation file. ++makeExample('cb-i18n/ts/app/i18n/fr/main.ts', 'translation-import')(format=".") +:marked + Angular cannot import the translation file directly at this time. + You have to give it a little help by converting the file contents into a string constant. + + **Webpack users** can skip that import statement + and use the [raw loader](https://github.com/webpack/raw-loader) to import the translations + file directly into the variable by adding this line: ++makeExample('cb-i18n/ts/app/i18n/fr/main.ts', 'webpack', 'app/i18n/fr/main.ts')(format=".") +:marked + **SystemJS users** have to create the variable manually which is best done in a + separate TypeScript file. + For this sample, create an `app/messages.fr.ts` in the `app` folder with a placeholder string constant: + ++makeExample('cb-i18n/ts/app/i18n/fr/messages.fr.1.ts', null, 'app/i18n/fr/messages.fr.ts (placeholder)')(format=".") + +:marked + Now copy and paste the contents of `message.fr.xlf` over the placeholder ... + ++makeExample('cb-i18n/ts/app/i18n/fr/messages.fr.ts', null, 'app/i18n/fr/messages.fr.ts (finished)')(format=".") + +:marked + ... and import the constant as shown above. + + ### Update the web page to launch in French + + The application is now internationalized! + + You have to decide how to serve the appropriate language version to the user. + This sample takes an approach unsuitable for production but fine for this demo. + It updates the `index.html` launch script as follows: + ++makeExample('cb-i18n/ts/index.html', 'main', 'index.html ("import main" script)')(format=".") + +a#aot +.l-main-section +:marked + ### Merge with the AoT compiler + + Internationalization with the AoT compiler requires some setup specifically for AoT. + Start with application project as shown [just before merging the translation file](#app-pre-translationStart) + and refer to the [AoT cookbook](aot-compiler.html) to make it _AoT-ready_. + + Next, issue a separate `ngc` compile command for each supported language (including English). + The result is a separate version of the application for each language. + + Determine the language by adding three options to the `ngc` command: + * `--i18nFile`: the path to the translation file + * `--locale`: the name of the locale + * `--i18nFormat`: the format of the localization file + + For this sample, the French language command would be +code-example(language="sh" class="code-shell"). + ./node_modules/.bin/ngc --i18nFile=./app/i18n/fr/messages.fr.xlf --locale=fr --i18nFormat=xlf + +.l-sub-section + :marked + Windows users may have to quote the command: + code-example(language="sh" class="code-shell"). + "./node_modules/.bin/ngc" --i18nFile=./app/i18n/fr/messages.fr.xlf --locale=fr --i18nFormat=xlf + :marked + Consider using gulp or a similar tool to ease this repetitive process. + +:marked + As with the JiT approach, you must decide how to serve the appropriate language version to the user. diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json index 25cb193874..cbcf39767e 100644 --- a/public/docs/ts/latest/guide/_data.json +++ b/public/docs/ts/latest/guide/_data.json @@ -147,11 +147,11 @@ "upgrade": { "title": "Upgrading from 1.x", - "intro": "Angular 1 applications can be incrementally upgraded to Angular 2." + "intro": "Incrementally upgrade an Angular 1 application to Angular 2." }, "webpack": { "title": "Webpack: an introduction", - "intro": "Create your Angular applications with a Webpack based tooling" + "intro": "Create Angular applications with a Webpack based tooling" } } From 3ee377863dec18bf31473a72df2a12d390909405 Mon Sep 17 00:00:00 2001 From: Ward Bell Date: Thu, 29 Sep 2016 04:18:18 -0700 Subject: [PATCH 2/2] docs(cb-i18n): revamped to System.import the translation file --- .../cb-i18n/ts/app/i18n-providers.ts | 33 ++++ .../_examples/cb-i18n/ts/app/i18n/fr/main.ts | 33 ---- .../cb-i18n/ts/app/i18n/fr/messages.fr.1.ts | 5 - .../cb-i18n/ts/app/i18n/fr/messages.fr.ts | 17 -- .../docs/_examples/cb-i18n/ts/app/main.1.ts | 6 + public/docs/_examples/cb-i18n/ts/app/main.ts | 9 +- .../ts/{app => }/i18n/fr/messages.fr.xlf | 4 +- .../ts/{app => }/i18n/fr/messages.fr.xlf.html | 0 .../cb-i18n/ts/{app => }/i18n/trans-unit.html | 0 public/docs/_examples/cb-i18n/ts/index.html | 36 ++-- public/docs/_examples/cb-i18n/ts/plnkr.json | 15 +- .../cb-i18n/ts/systemjs-text-plugin.js | 14 ++ public/docs/ts/latest/cookbook/i18n.jade | 169 +++++++++++------- 13 files changed, 187 insertions(+), 154 deletions(-) create mode 100644 public/docs/_examples/cb-i18n/ts/app/i18n-providers.ts delete mode 100644 public/docs/_examples/cb-i18n/ts/app/i18n/fr/main.ts delete mode 100644 public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.1.ts delete mode 100644 public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.ts create mode 100644 public/docs/_examples/cb-i18n/ts/app/main.1.ts rename public/docs/_examples/cb-i18n/ts/{app => }/i18n/fr/messages.fr.xlf (91%) rename public/docs/_examples/cb-i18n/ts/{app => }/i18n/fr/messages.fr.xlf.html (100%) rename public/docs/_examples/cb-i18n/ts/{app => }/i18n/trans-unit.html (100%) create mode 100644 public/docs/_examples/cb-i18n/ts/systemjs-text-plugin.js diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n-providers.ts b/public/docs/_examples/cb-i18n/ts/app/i18n-providers.ts new file mode 100644 index 0000000000..c27afc88d7 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/i18n-providers.ts @@ -0,0 +1,33 @@ +// #docregion +import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID } from '@angular/core'; + +export function getTranslationProviders(): Promise { + + // Get the locale id from the global + const locale = document['locale'] as string; + + // return no providers if fail to get translation file for locale + const noProviders: Object[] = []; + + // No locale or English: no translation providers + if (!locale || locale === 'en') { + return Promise.resolve(noProviders); + } + + // Ex: 'i18n/fr/messages.fr.xlf` + const translationFile = `./i18n/${locale}/messages.${locale}.xlf`; + + return getTranslationsWithSystemJs(translationFile) + .then( (translations: string ) => [ + { provide: TRANSLATIONS, useValue: translations }, + { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }, + { provide: LOCALE_ID, useValue: locale } + ]) + .catch(() => noProviders); // ignore if file not found +} + +declare var System: any; + +function getTranslationsWithSystemJs(file: string) { + return System.import(file + '!text'); // relies on text plugin +} diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/main.ts b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/main.ts deleted file mode 100644 index 53054d4d6a..0000000000 --- a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/main.ts +++ /dev/null @@ -1,33 +0,0 @@ -// #docplaster -// #docregion -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; -import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID } from '@angular/core'; - -import { AppModule } from '../../app.module'; -// #docregion translation-import -import { translations } from './messages.fr'; -// #enddocregion translation-import - -// #enddocregion -/* - // Webpack users don't need to create - // They simply define `translations` here and let webpack load it: -// #docregion webpack - const translations = require("raw!./cb-i18n/messages.fr.xlf"); -// #enddocregion webpack -*/ - -// #docregion -// Compile using french translations -const platform = platformBrowserDynamic(); - -platform.bootstrapModule( - AppModule, - { - providers: [ - {provide: TRANSLATIONS, useValue: translations}, - {provide: TRANSLATIONS_FORMAT, useValue: 'xlf'}, - {provide: LOCALE_ID, useValue: 'fr'} - ] - } -); diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.1.ts b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.1.ts deleted file mode 100644 index 33d43e2bc2..0000000000 --- a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.1.ts +++ /dev/null @@ -1,5 +0,0 @@ -// #docregion -export const translation = ` - PASTE HERE -`; - diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.ts b/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.ts deleted file mode 100644 index 35fd9f2f6e..0000000000 --- a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.ts +++ /dev/null @@ -1,17 +0,0 @@ -// #docregion -export const translations = ` - - - - - - Hello i18n! - Bonjour i18n! - An introduction header for this sample - User welcome - - - - -`; - diff --git a/public/docs/_examples/cb-i18n/ts/app/main.1.ts b/public/docs/_examples/cb-i18n/ts/app/main.1.ts new file mode 100644 index 0000000000..961a226688 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/app/main.1.ts @@ -0,0 +1,6 @@ +// #docregion +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app.module'; + +platformBrowserDynamic().bootstrapModule(AppModule); diff --git a/public/docs/_examples/cb-i18n/ts/app/main.ts b/public/docs/_examples/cb-i18n/ts/app/main.ts index e11324f519..79d5fa0b48 100644 --- a/public/docs/_examples/cb-i18n/ts/app/main.ts +++ b/public/docs/_examples/cb-i18n/ts/app/main.ts @@ -1,7 +1,10 @@ // #docregion -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { getTranslationProviders } from './i18n-providers'; import { AppModule } from './app.module'; -const platform = platformBrowserDynamic(); -platform.bootstrapModule(AppModule); +getTranslationProviders().then(providers => { + const options = { providers }; + platformBrowserDynamic().bootstrapModule(AppModule, options); +}); diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf b/public/docs/_examples/cb-i18n/ts/i18n/fr/messages.fr.xlf similarity index 91% rename from public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf rename to public/docs/_examples/cb-i18n/ts/i18n/fr/messages.fr.xlf index f6b0094bd9..005b98ba73 100644 --- a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf +++ b/public/docs/_examples/cb-i18n/ts/i18n/fr/messages.fr.xlf @@ -4,10 +4,10 @@ Hello i18n! - + Bonjour i18n! An introduction header for this sample User welcome - \ No newline at end of file + diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf.html b/public/docs/_examples/cb-i18n/ts/i18n/fr/messages.fr.xlf.html similarity index 100% rename from public/docs/_examples/cb-i18n/ts/app/i18n/fr/messages.fr.xlf.html rename to public/docs/_examples/cb-i18n/ts/i18n/fr/messages.fr.xlf.html diff --git a/public/docs/_examples/cb-i18n/ts/app/i18n/trans-unit.html b/public/docs/_examples/cb-i18n/ts/i18n/trans-unit.html similarity index 100% rename from public/docs/_examples/cb-i18n/ts/app/i18n/trans-unit.html rename to public/docs/_examples/cb-i18n/ts/i18n/trans-unit.html diff --git a/public/docs/_examples/cb-i18n/ts/index.html b/public/docs/_examples/cb-i18n/ts/index.html index f6414770c8..fc88d9284e 100644 --- a/public/docs/_examples/cb-i18n/ts/index.html +++ b/public/docs/_examples/cb-i18n/ts/index.html @@ -7,39 +7,33 @@ - - - - - - - - - + + - - + - - Loading... - diff --git a/public/docs/_examples/cb-i18n/ts/plnkr.json b/public/docs/_examples/cb-i18n/ts/plnkr.json index 9886709b1e..aa6421b303 100644 --- a/public/docs/_examples/cb-i18n/ts/plnkr.json +++ b/public/docs/_examples/cb-i18n/ts/plnkr.json @@ -1,10 +1,17 @@ { "description": "i18n", "files": [ - "!**/*.d.ts", - "!**/*.js", + "app/**/*.css", + "app/**/*.html", + "app/**/*.ts", + "i18n/messages.xlf", + "i18n/fr/messages.fr.xlf", + "!**/*.[1].*", - "!**/*.metadata.json" + + "styles.css", + "systemjs-text-plugin.js", + "index.html" ], "tags": ["i18n"] -} \ No newline at end of file +} diff --git a/public/docs/_examples/cb-i18n/ts/systemjs-text-plugin.js b/public/docs/_examples/cb-i18n/ts/systemjs-text-plugin.js new file mode 100644 index 0000000000..d5ca508fe0 --- /dev/null +++ b/public/docs/_examples/cb-i18n/ts/systemjs-text-plugin.js @@ -0,0 +1,14 @@ +// #docregion +/* + SystemJS Text plugin from + https://github.com/systemjs/plugin-text/blob/master/text.js +*/ +exports.translate = function(load) { + if (this.builder && this.transpiler) { + load.metadata.format = 'esm'; + return 'exp' + 'ort var __useDefault = true; exp' + 'ort default ' + JSON.stringify(load.source) + ';'; + } + + load.metadata.format = 'amd'; + return 'def' + 'ine(function() {\nreturn ' + JSON.stringify(load.source) + ';\n});'; +} diff --git a/public/docs/ts/latest/cookbook/i18n.jade b/public/docs/ts/latest/cookbook/i18n.jade index 06d4fb7798..8f58098f9d 100644 --- a/public/docs/ts/latest/cookbook/i18n.jade +++ b/public/docs/ts/latest/cookbook/i18n.jade @@ -145,39 +145,46 @@ code-example(language="sh" class="code-shell"). a#translate .l-main-section :marked - ## Translate _le text + ## Translate _le message textuel_ The `ng-xi18n` command generated a translation source file in the project root folder named `messages.xlf`. + The next step is to translate the English language template text into the specific language translation + files. The cookbook sample creates a French translation file. +a#i18n-file-structure +:marked ### Create an i18n project structure - You're probably translating into multiple languages so it's a good idea + You will probably translate into more than one other language so it's a good idea for the project structure to reflect your entire internationalization effort. One approach is to create an `i18n` folder with subfolders for each language or locale, e.g. `i18n/fr` for French. - This sample puts `i18n/fr` under the `app` folder but you can adjust to suit your preferences. + This sample puts `i18n/fr` under the project root. - Move the `messages.xlf` under `i18n` where it will become the source for all language-specific translations. + Move the `messages.xlf` into the `i18n` folder where it will become the source for all language-specific translations. Then copy `messages.xlf` into `i18n/fr` and rename it as `messages.fr.xlf` . + Follow the same convention for each target language. + ### Translate - In the real world, you send this file to a French translator who would fill in the translations + In the real world, you send the `messages.fr.xlf` file to a French translator who would fill in the translations using one of the many XLIFF file editors. This sample file is easy to translate without a special editor or knowledge of French. Open `messages.fr.xlf` and find the `` section: -+makeExample('cb-i18n/ts/app/i18n/trans-unit.html', '', 'app/i18n/messages.fr.xlf ()')(format=".") ++makeExample('cb-i18n/ts/i18n/trans-unit.html', '', 'i18n/messages.fr.xlf ()')(format=".") :marked This XML element represents the translation of the `

` greeting tag you marked with the `i18n` attribute. - The `id` may be different. + + Using the _source_, _description_, and _meaning_ elements to guide your translation, + replace the `` tag with the French greeting: ++makeExample('cb-i18n/ts/i18n/fr/messages.fr.xlf.html', 'trans-unit', 'i18n/fr/messages.fr.xlf (, after translation)')(format=".") +:marked + Note that the `id` is generated by the tool. Don't touch it. Its value depends on the content of the message, its meaning, and its description. Change any of these factors and the `id` changes as well. - - Replace the `` tag with the French greeting: -+makeExample('cb-i18n/ts/app/i18n/fr/messages.fr.xlf.html', 'trans-unit', 'app/i18n/fr/messages.fr.xlf (, after translation)')(format=".") -:marked .alert.is-helpful :marked Repeat the extraction process whenever you add new app messages or edit existing ones. @@ -194,14 +201,14 @@ a#translate cb-i18n/ts/app/app.component.html, cb-i18n/ts/app/app.component.ts, cb-i18n/ts/app/app.module.ts, - cb-i18n/ts/app/main.ts, - cb-i18n/ts/app/i18n/fr/messages.fr.xlf.html + cb-i18n/ts/app/main.1.ts, + cb-i18n/ts/i18n/fr/messages.fr.xlf.html `, '', ` app/app.component.html, app/app.component.ts, app/app.module.ts, app/main.ts, - app/i18n/fr/messages.fr.xlf + i18n/fr/messages.fr.xlf `) a#merge @@ -222,98 +229,122 @@ a#merge _How_ you provide this information depends upon whether you compile with the JiT (_Just-in-Time_) compiler or the AoT (_Ahead-of-Time_) compiler. - * With [JiT](#jit), you provide the information at bootstrap time. - * With [AoT](#aot), you pass the information as `ngc` options. - - The next two sections cover the details. - + * with [JiT](#jit), you provide the information at bootstrap time. + * with [AoT](#aot), you pass the information as `ngc` options. a#jit .l-main-section :marked ### Merge with the JiT compiler - Copy `app/main.ts` into the `app/i18n/fr` folder. - - Open this copy and add a second, _options_ argument to the bootstrap method. - The _options_ has one property, `providers`. - Give it an array of three translation providers: - * `TRANSLATIONS` is a string containing the content of the translation file. - * `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlif` or `xtb` - * `LOCALE_ID` is the locale of the target language. - - Adjust the `AppModule` import statement which now is two levels up the folder tree. - - Here is the revised `app/i18n/fr/main.ts` for this sample: - -+makeExample('cb-i18n/ts/app/i18n/fr/main.ts', null, 'app/i18n/fr/main.ts')(format=".") + The JiT (_Just-in-Time_) compiler compiles the application in the browser as the application loads. + Translation with the JiT compiler is a dynamic process of ... + 1. determining the language version for the current user, + 2. importing the appropriate language translation file as a string constant, + 3. creating corresponding translation providers to guide the JiT compiler, + 4. bootstrapping the application with those providers. + + Open `index.html` and revise the launch script as shown here: ++makeExample('cb-i18n/ts/index.html', 'i18n', 'index.html (launch script)')(format='.') :marked - ### Convert the translation file to a string constant - - Notice that the translation is imported from a TypeScript file, not the translation file. -+makeExample('cb-i18n/ts/app/i18n/fr/main.ts', 'translation-import')(format=".") -:marked - Angular cannot import the translation file directly at this time. - You have to give it a little help by converting the file contents into a string constant. - - **Webpack users** can skip that import statement - and use the [raw loader](https://github.com/webpack/raw-loader) to import the translations - file directly into the variable by adding this line: -+makeExample('cb-i18n/ts/app/i18n/fr/main.ts', 'webpack', 'app/i18n/fr/main.ts')(format=".") + In this sample, the user's language is hardcoded as a global `document.locale` variable + in the `index.html`. + +a#text-plugin :marked - **SystemJS users** have to create the variable manually which is best done in a - separate TypeScript file. - For this sample, create an `app/messages.fr.ts` in the `app` folder with a placeholder string constant: + ### SystemJS Text plugin -+makeExample('cb-i18n/ts/app/i18n/fr/messages.fr.1.ts', null, 'app/i18n/fr/messages.fr.ts (placeholder)')(format=".") + Notice the SystemJS mapping of `text` to a `systemjs-text-plugin.js`. + With the help of a text pluglin, SystemJS can read any file as raw text and + return the contents as a string. + You'll need it to import the language translation file. + SystemJS doesn't ship with a raw text plugin but it's easy to add. + Create the following `systemjs-text-plugin.js` in the root folder: ++makeExample('cb-i18n/ts/systemjs-text-plugin.js', null, 'systemjs-text-plugin.js')(format='.') :marked - Now copy and paste the contents of `message.fr.xlf` over the placeholder ... + ### Create translation providers -+makeExample('cb-i18n/ts/app/i18n/fr/messages.fr.ts', null, 'app/i18n/fr/messages.fr.ts (finished)')(format=".") + Three providers tell the JiT compiler how to translate the template texts for a particular language + while compiling the application: + * `TRANSLATIONS` is a string containing the content of the translation file. + * `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlif` or `xtb` + * `LOCALE_ID` is the locale of the target language. + + The `getTranslationProviders` function in the following `app/i18n-providers.ts` + creates those providers based on the user's _locale_ + and the corresponding translation file: ++makeExample('cb-i18n/ts/app/i18n-providers.ts', null, 'app/i18n-providers.ts') :marked - ... and import the constant as shown above. + * It gets the locale from the global `document.locale` variable that was set in `index.html`. - ### Update the web page to launch in French + * If there is no locale or the language is English, there is no need to translate. + The function returns an empty `noProviders` array as a `Promise`. + It must return a `Promise` because this function could read a translation file asynchronously from the server. - The application is now internationalized! - - You have to decide how to serve the appropriate language version to the user. - This sample takes an approach unsuitable for production but fine for this demo. - It updates the `index.html` launch script as follows: + * It creates a transaction filename from the locale according to the name and location convention + [described earlier](#i18n-file-structure). + + * The `getTranslationsWithSystemJs` method reads the translation and returns the contents as a string. + Notice that it appends `!text` to the filename, telling SystemJS to use the [text plugin](#text-plugin). + + * The callback composes a providers array with the three translation providers. -+makeExample('cb-i18n/ts/index.html', 'main', 'index.html ("import main" script)')(format=".") + * Finally, `getTranslationProviders` returns the entire effort as a promise. + + ### Bootstrap the app with translation providers + + The Angular `bootstrapModule` method has a second, _options_ parameter + that can influence the behavior of the compiler. + + You'll create an _options_ object with the translation providers from `getTranslationProviders` + and pass it to `bootstrapModule`. + Open the `app/main.ts` and modify the bootstrap code as follows: ++makeExample('cb-i18n/ts/app/main.ts', null, 'app/main.ts')(format=".") +:marked + Notice that it waits for the `getTranslationProviders` promise to resolve before + bootstrapping the app. + + The app is now _internationalized_ for English and French and there is a clear path for adding + more languages. a#aot .l-main-section :marked - ### Merge with the AoT compiler + ### _Internationalize_ with the AoT compiler + + The JiT compiler translates the application into the target language while compiling dynamically in the browser. + That's flexible but may not be fast enough for your users. + The AoT (_Ahead-of-Time_) compiler is part of a build process that produces a small, fast, ready-to-run application package. + When you internationalize with the AoT compiler, you pre-build a separate application package for each + language. Then in the host web page (`index.html`), you determine which language the user needs + and serve the appropriate application package. + + This cookbook doesn't cover how to build multiple application packages and + serve them according to the user's language preference. + It does explain the few steps necessary to tell the AoT to apply a translations file. + Internationalization with the AoT compiler requires some setup specifically for AoT. Start with application project as shown [just before merging the translation file](#app-pre-translationStart) and refer to the [AoT cookbook](aot-compiler.html) to make it _AoT-ready_. - Next, issue a separate `ngc` compile command for each supported language (including English). + Next, issue an `ngc` compile command for each supported language (including English). The result is a separate version of the application for each language. - Determine the language by adding three options to the `ngc` command: + Tell AoT how to translate by adding three options to the `ngc` command: * `--i18nFile`: the path to the translation file * `--locale`: the name of the locale * `--i18nFormat`: the format of the localization file For this sample, the French language command would be code-example(language="sh" class="code-shell"). - ./node_modules/.bin/ngc --i18nFile=./app/i18n/fr/messages.fr.xlf --locale=fr --i18nFormat=xlf + ./node_modules/.bin/ngc --i18nFile=./i18n/fr/messages.fr.xlf --locale=fr --i18nFormat=xlf .l-sub-section :marked Windows users may have to quote the command: code-example(language="sh" class="code-shell"). - "./node_modules/.bin/ngc" --i18nFile=./app/i18n/fr/messages.fr.xlf --locale=fr --i18nFormat=xlf - :marked - Consider using gulp or a similar tool to ease this repetitive process. - -:marked - As with the JiT approach, you must decide how to serve the appropriate language version to the user. + "./node_modules/.bin/ngc" --i18nFile=./i18n/fr/messages.fr.xlf --locale=fr --i18nFormat=xlf