docs(i18n): add internationalization (i18n) guide (#2491)
* docs(i18n): add internationalization (i18n) guide * docs(cb-i18n): revamped to System.import the translation file
This commit is contained in:
parent
64d5b3dc23
commit
e6199a8dfb
|
@ -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/**/*.*');
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/// <reference path='../_protractor/e2e.d.ts' />
|
||||
'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!');
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,6 @@
|
|||
**/*.ngfactory.ts
|
||||
**/*.metadata.json
|
||||
**/messages.xlf
|
||||
dist
|
||||
!app/tsconfig.json
|
||||
!rollup.js
|
|
@ -0,0 +1,11 @@
|
|||
<!--#docregion greeting-->
|
||||
<h1>Hello i18n!</h1>
|
||||
<!--#enddocregion greeting-->
|
||||
|
||||
<!--#docregion i18n-attribute-->
|
||||
<h1 i18n>Hello i18n!</h1>
|
||||
<!--#enddocregion i18n-attribute-->
|
||||
|
||||
<!--#docregion i18n-attribute-desc-->
|
||||
<h1 i18n="An introduction header for this sample">Hello i18n!</h1>
|
||||
<!--#enddocregion i18n-attribute-desc-->
|
|
@ -0,0 +1,4 @@
|
|||
<!--#docregion-->
|
||||
<!--#docregion i18n-attribute-meaning-->
|
||||
<h1 i18n="User welcome|An introduction header for this sample">Hello i18n!</h1>
|
||||
<!--#enddocregion i18n-attribute-meaning-->
|
|
@ -0,0 +1,10 @@
|
|||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
selector: 'my-app',
|
||||
templateUrl: 'app.component.html'
|
||||
})
|
||||
export class AppComponent { }
|
||||
|
|
@ -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 { }
|
|
@ -0,0 +1,33 @@
|
|||
// #docregion
|
||||
import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID } from '@angular/core';
|
||||
|
||||
export function getTranslationProviders(): Promise<Object[]> {
|
||||
|
||||
// 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
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
// #docregion
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
|
@ -0,0 +1,10 @@
|
|||
// #docregion
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { getTranslationProviders } from './i18n-providers';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
getTranslationProviders().then(providers => {
|
||||
const options = { providers };
|
||||
platformBrowserDynamic().bootstrapModule(AppModule, options);
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" datatype="plaintext" original="ng2.template">
|
||||
<body>
|
||||
<trans-unit id="af2ccf4b5dba59616e92cf1531505af02da8f6d2" datatype="html">
|
||||
<source>Hello i18n!</source>
|
||||
<target>Bonjour i18n!</target>
|
||||
<note priority="1" from="description">An introduction header for this sample</note>
|
||||
<note priority="1" from="meaning">User welcome</note>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -0,0 +1,17 @@
|
|||
<!-- The `messages.fr.xlf` after translation for documentation purposes -->
|
||||
<!-- #docregion -->
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
|
||||
<file source-language="en" datatype="plaintext" original="ng2.template">
|
||||
<body>
|
||||
<!-- #docregion trans-unit -->
|
||||
<trans-unit id="af2ccf4b5dba59616e92cf1531505af02da8f6d2" datatype="html">
|
||||
<source>Hello i18n!</source>
|
||||
<target>Bonjour i18n!</target>
|
||||
<note priority="1" from="description">An introduction header for this sample</note>
|
||||
<note priority="1" from="meaning">User welcome</note>
|
||||
</trans-unit>
|
||||
<!-- #enddocregion trans-unit -->
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -0,0 +1,7 @@
|
|||
<!-- #docregion -->
|
||||
<trans-unit id="af2ccf4b5dba59616e92cf1531505af02da8f6d2" datatype="html">
|
||||
<source>Hello i18n!</source>
|
||||
<target/>
|
||||
<note priority="1" from="description">An introduction header for this sample</note>
|
||||
<note priority="1" from="meaning">User welcome</note>
|
||||
</trans-unit>
|
|
@ -0,0 +1,39 @@
|
|||
<!DOCTYPE html>
|
||||
<!-- #docregion -->
|
||||
<html>
|
||||
<head>
|
||||
<title>Angular i18n example</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<script src="node_modules/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="node_modules/zone.js/dist/zone.js"></script>
|
||||
<script src="node_modules/reflect-metadata/Reflect.js"></script>
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
|
||||
<script src="systemjs.config.js"></script>
|
||||
|
||||
<!-- #docregion i18n -->
|
||||
<script>
|
||||
// Get the locale id somehow
|
||||
document.locale = 'fr';
|
||||
|
||||
// Map to the text plugin
|
||||
System.config({
|
||||
map: {
|
||||
text: 'systemjs-text-plugin.js'
|
||||
}
|
||||
});
|
||||
|
||||
// Launch the app
|
||||
System.import('app').catch(function(err){ console.error(err); });
|
||||
</script>
|
||||
<!-- #enddocregion i18n -->
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<my-app>Loading...</my-app>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"description": "i18n",
|
||||
"files": [
|
||||
"app/**/*.css",
|
||||
"app/**/*.html",
|
||||
"app/**/*.ts",
|
||||
"i18n/messages.xlf",
|
||||
"i18n/fr/messages.fr.xlf",
|
||||
|
||||
"!**/*.[1].*",
|
||||
|
||||
"styles.css",
|
||||
"systemjs-text-plugin.js",
|
||||
"index.html"
|
||||
],
|
||||
"tags": ["i18n"]
|
||||
}
|
|
@ -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});';
|
||||
}
|
|
@ -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": "",
|
||||
|
|
|
@ -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.",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include ../../../_includes/_ts-temp
|
|
@ -0,0 +1 @@
|
|||
!= partial("../../../_includes/_ts-temp")
|
|
@ -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.",
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include ../../../_includes/_ts-temp
|
|
@ -0,0 +1 @@
|
|||
!= partial("../../../_includes/_ts-temp")
|
|
@ -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."
|
||||
|
|
|
@ -0,0 +1,350 @@
|
|||
include ../_util-fns
|
||||
|
||||
:marked
|
||||
Angular's _internationalization_ ("_i18n_") tools help make your app availble in multiple languages.
|
||||
|
||||
<a id="top"></a>
|
||||
## 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>live example</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 `<h1>` 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
|
||||
<a href="https://en.wikipedia.org/wiki/XLIFF" target="_blank">XML Localisation Interchange File Format (XLIFF, version 1.2)</a>.
|
||||
|
||||
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
|
||||
<a href="http://cldr.unicode.org/development/development-process/design-proposals/xmb" target="_blank">XML Message Bundle (XMB)</a> format
|
||||
by adding the `--i18nFormat=xmb` switch.
|
||||
|
||||
This sample sticks with the _XLIFF_ format.
|
||||
|
||||
a#translate
|
||||
.l-main-section
|
||||
:marked
|
||||
## 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 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 project root.
|
||||
|
||||
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 the `messages.fr.xlf` file to a French translator who would fill in the translations
|
||||
using one of the
|
||||
<a href="https://en.wikipedia.org/wiki/XLIFF#Editors" target="_blank">many XLIFF file editors</a>.
|
||||
|
||||
This sample file is easy to translate without a special editor or knowledge of French.
|
||||
Open `messages.fr.xlf` and find the `<trans-unit>` section:
|
||||
|
||||
+makeExample('cb-i18n/ts/i18n/trans-unit.html', '', 'i18n/messages.fr.xlf (<trans-unit>)')(format=".")
|
||||
:marked
|
||||
This XML element represents the translation of the `<h1>` greeting tag you marked with the `i18n` attribute.
|
||||
|
||||
Using the _source_, _description_, and _meaning_ elements to guide your translation,
|
||||
replace the `<target/>` tag with the French greeting:
|
||||
+makeExample('cb-i18n/ts/i18n/fr/messages.fr.xlf.html', 'trans-unit', 'i18n/fr/messages.fr.xlf (<trans-unit>, 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.
|
||||
.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.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,
|
||||
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.
|
||||
|
||||
a#jit
|
||||
.l-main-section
|
||||
:marked
|
||||
### Merge with the JiT compiler
|
||||
|
||||
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
|
||||
In this sample, the user's language is hardcoded as a global `document.locale` variable
|
||||
in the `index.html`.
|
||||
|
||||
a#text-plugin
|
||||
:marked
|
||||
### SystemJS Text plugin
|
||||
|
||||
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
|
||||
### Create translation providers
|
||||
|
||||
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
|
||||
* It gets the locale from the global `document.locale` variable that was set in `index.html`.
|
||||
|
||||
* 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.
|
||||
|
||||
* 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.
|
||||
|
||||
* 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
|
||||
### _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 an `ngc` compile command for each supported language (including English).
|
||||
The result is a separate version of the application for each language.
|
||||
|
||||
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=./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=./i18n/fr/messages.fr.xlf --locale=fr --i18nFormat=xlf
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue