2017-02-22 13:09:39 -05:00
|
|
|
@title
|
|
|
|
Internationalization (i18n)
|
|
|
|
|
|
|
|
@intro
|
|
|
|
Translate the app's template text into multiple languages.
|
|
|
|
|
|
|
|
@description
|
|
|
|
|
|
|
|
|
|
|
|
{@a top}
|
|
|
|
Angular's _internationalization_ (_i18n_) tools help make your app available in multiple languages.
|
|
|
|
|
|
|
|
## Table of contents
|
|
|
|
|
2017-03-11 10:36:40 -05:00
|
|
|
* [Angular and i18n template translation](guide/i18n#angular-i18n)
|
|
|
|
* [Mark text with the _i18n_ attribute](guide/i18n#i18n-attribute)
|
|
|
|
* [Add _i18n-..._ translation attributes](guide/i18n#translate-attributes)
|
|
|
|
* [Handle singular and plural](guide/i18n#cardinality)
|
|
|
|
* [Select among alternative texts](guide/i18n#select)
|
|
|
|
* [Create a translation source file with the **_ng-xi18n_ extraction tool**](guide/i18n#ng-xi18n)
|
|
|
|
* [Translate text messages](guide/i18n#translate)
|
|
|
|
* [Merge the completed translation file into the app](guide/i18n#merge)
|
|
|
|
* [Merge with the JIT compiler](guide/i18n#jit)
|
|
|
|
* [Internationalization with the AOT compiler](guide/i18n#aot)
|
|
|
|
* [Translation file maintenance and _id_ changes](guide/i18n#maintenance)
|
2017-02-22 13:09:39 -05:00
|
|
|
**Try this** <live-example name="cb-i18n" title="i18n Example in Spanish">live example</live-example>
|
|
|
|
of a JIT-compiled app, translated into Spanish.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{@a angular-i18n}
|
|
|
|
|
|
|
|
## 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 available to assist translation of component template text
|
|
|
|
into multiple languages.
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
~~~ {.l-sub-section}
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
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_".
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
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 need to build and deploy a separate version of the application for each supported language.
|
|
|
|
|
|
|
|
|
|
|
|
{@a i18n-attribute}
|
|
|
|
|
|
|
|
## 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}
|
|
|
|
|
|
|
|
`i18n` is not an Angular _directive_.
|
|
|
|
It's a custom _attribute_, recognized by Angular tools and compilers.
|
|
|
|
After translation, the compiler removes it.
|
|
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
In the accompanying sample, an `<h1>` tag displays a simple English language greeting
|
|
|
|
that you translate into Spanish:
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.1.html" region="greeting" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
Add the `i18n` attribute to the tag to mark it for translation.
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.1.html" region="i18n-attribute" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
### Help the translator with a _description_ and _intent_
|
|
|
|
|
|
|
|
In order to translate it accurately, the translator may
|
|
|
|
need a description of the message.
|
|
|
|
Assign a description to the i18n attribute:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.1.html" region="i18n-attribute-desc" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
In order to deliver a correct translation, the translator may need to
|
|
|
|
know your _intent_—the true _meaning_ of the text
|
|
|
|
within _this particular_ application context.
|
|
|
|
In front of the description, add some contextual meaning to the assigned string,
|
|
|
|
separating it from the description with the `|` character (`<meaning>|<description>`):
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.html" region="i18n-attribute-meaning" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
While all appearances of a message with the _same_ meaning have the _same_ translation,
|
|
|
|
a message with *a variety of possible 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 translations.
|
|
|
|
|
|
|
|
### Translate text without creating an element
|
|
|
|
|
|
|
|
Suppose there is a stretch of text that you'd like to translate.
|
|
|
|
You could wrap it in a `<span>` tag but for some reason (CSS comes to mind)
|
|
|
|
you don't want to create a new DOM element merely to facilitate translation.
|
|
|
|
|
|
|
|
Here are two techniques to try.
|
|
|
|
|
|
|
|
(1) Wrap the text in an `<ng-container>` element. The `<ng-container>` is never renderered:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.html" region="i18n-ng-container" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
(2) Wrap the text in a pair of HTML comments:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.html" region="i18n-with-comment" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{@a translate-attributes}
|
|
|
|
## Add _i18n-..._ translation attributes
|
|
|
|
You've added an image to your template. You care about accessibility too so you add a `title` attribute:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.1.html" region="i18n-title" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
The `title` attribute needs to be translated.
|
|
|
|
Angular i18n support has more translation attributes in the form,`i18n-x`, where `x` is the
|
|
|
|
name of the attribute to translate.
|
|
|
|
|
|
|
|
To translate the `title` on the `img` tag from the previous example, write:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.html" region="i18n-title-translate" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
You can also assign a meaning and a description with the `i18n-x="<meaning>|<description>"` syntax.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{@a cardinality}
|
|
|
|
## Handle singular and plural
|
|
|
|
|
|
|
|
Different languages have different pluralization rules.
|
|
|
|
|
|
|
|
Suppose your application says something about a collection of wolves.
|
|
|
|
In English, depending upon the number of wolves, you could display "no wolves", "one wolf", "two wolves", or "a wolf pack".
|
|
|
|
Other languages might express the _cardinality_ differently.
|
|
|
|
|
|
|
|
Here's how you could mark up the component template to display the phrase appropriate to the number of wolves:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.html" region="i18n-plural" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
* The first parameter is the key. It is bound to the component property (`wolves`)
|
|
|
|
that determines the number of wolves.
|
|
|
|
* The second parameter identifies this as a `plural` translation type.
|
|
|
|
* The third parameter defines a pluralization pattern consisting of pluralization
|
|
|
|
categories and their matching values.
|
|
|
|
|
|
|
|
Pluralization categories include:
|
|
|
|
* =0
|
|
|
|
* =1
|
|
|
|
* =5
|
|
|
|
* few
|
|
|
|
* other
|
|
|
|
|
|
|
|
Put the default _English_ translation in braces (`{}`) next to the pluralization category.
|
|
|
|
* When you're talking about one wolf, you could write `=1 {one wolf}`.
|
|
|
|
* For zero wolves, you could write `=0 {no wolves}`.
|
|
|
|
* For two wolves, you could write `=2 {two wolves}`.
|
|
|
|
|
|
|
|
You could keep this up for three, four, and every other number of wolves.
|
|
|
|
Or you could specify the **`other`** category as a catch-all for any unmatched cardinality
|
|
|
|
and write something like: `other {a wolf pack}`.
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
~~~ {.l-sub-section}
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
This syntax conforms to the
|
|
|
|
<a href="http://userguide.icu-project.org/formatparse/messages" target="_blank" title="ICU Message Format">ICU Message Format</a>
|
|
|
|
that derives from the
|
|
|
|
<a href="http://cldr.unicode.org/" target="_blank" title="CLDR">Common Locale Data Repository (CLDR),</a>
|
|
|
|
which specifies the
|
|
|
|
<a href="http://unicode.org/reports/tr35/tr35-numbers.html#Language_Plural_Rules" target="_blank" title="Pluralization Rules">pluralization rules</a>.
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
~~~
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
{@a select}
|
|
|
|
## Select among alternative texts
|
|
|
|
The application displays different text depending upon whether the hero is male or female.
|
|
|
|
These text alternatives require translation too.
|
|
|
|
|
|
|
|
You can handle this with a `select` translation.
|
|
|
|
A `select` also follows the
|
|
|
|
<a href="http://userguide.icu-project.org/formatparse/messages" target="_blank" title="ICU Message Format">ICU message syntax</a>.
|
|
|
|
You choose among alternative translation based on a string value instead of a number.
|
|
|
|
|
|
|
|
The following format message in the component template binds to the component's `gender`
|
|
|
|
property, which outputs either an "m" or an "f".
|
|
|
|
The message maps those values to the appropriate translation:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.html" region="i18n-select" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{@a ng-xi18n}
|
|
|
|
|
|
|
|
## Create a translation source file with the _ng-xi18n_ tool
|
|
|
|
|
|
|
|
Use the **_ng-xi18n_ extraction tool** to extract the `i18n`-marked texts
|
|
|
|
into a translation source file in an industry standard format.
|
|
|
|
|
|
|
|
This is an Angular CLI tool 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
|
|
|
|
|
|
|
|
</code-example>
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
</code-example>
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
~~~ {.l-sub-section}
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
Windows users may have to quote the command like this: `"./node_modules/.bin/ng-xi18n"`
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
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>.
|
|
|
|
|
|
|
|
|
|
|
|
{@a other-formats}
|
|
|
|
### 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` flag.
|
|
|
|
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
|
|
./node_modules/.bin/ng-xi18n --i18nFormat=xmb
|
|
|
|
|
|
|
|
</code-example>
|
|
|
|
|
|
|
|
This sample sticks with the _XLIFF_ format.
|
|
|
|
|
|
|
|
|
|
|
|
{@a ng-xi18n-options}
|
|
|
|
### Other options
|
|
|
|
You may have to specify additional options.
|
|
|
|
For example, if the `tsconfig.json` TypeScript configuration
|
|
|
|
file is located somewhere other than in the root folder,
|
|
|
|
you must identify the path to it with the `-p` option:
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
|
|
./node_modules/.bin/ng-xi18n -p path/to/tsconfig.json
|
|
|
|
./node_modules/.bin/ng-xi18n --i18nFormat=xmb -p path/to/tsconfig.json
|
|
|
|
|
|
|
|
|
|
|
|
</code-example>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{@a npm-i18n-script}
|
|
|
|
### Add an _npm_ script for convenience
|
|
|
|
|
|
|
|
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='.' language='sh'>
|
|
|
|
"scripts": {
|
|
|
|
"i18n": "ng-xi18n",
|
|
|
|
...
|
|
|
|
}
|
|
|
|
</code-example>
|
|
|
|
|
|
|
|
Now you can issue command variations such as these:
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
|
|
npm run i18n
|
|
|
|
npm run i18n -- -p path/to/tsconfig.json
|
|
|
|
npm run i18n -- --i18nFormat=xmb -p path/to/tsconfig.json
|
|
|
|
</code-example>
|
|
|
|
|
|
|
|
Note the `--` flag before the options.
|
|
|
|
It tells _npm_ to pass every flag thereafter to `ng-xi18n`.
|
|
|
|
|
|
|
|
|
|
|
|
{@a translate}
|
|
|
|
|
|
|
|
## Translate text messages
|
|
|
|
|
|
|
|
The `ng-xi18n` command generates 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 Spanish translation file.
|
|
|
|
|
|
|
|
|
|
|
|
{@a localization-folder}
|
|
|
|
### Create a localization folder
|
|
|
|
|
|
|
|
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 dedicate a folder to localization and store related assets
|
|
|
|
(for example, internationalization files) there.
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
~~~ {.l-sub-section}
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
Localization and internationalization are
|
2017-03-27 11:08:53 -04:00
|
|
|
<a href="https://en.wikipedia.org/wiki/Internationalization_and_localization" target="_blank">different but closely related terms</a>.
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
This cookbook follows that suggestion. It has a `locale` folder under the `src/`.
|
2017-02-22 13:09:39 -05:00
|
|
|
Assets within the folder carry a filename extension that matches a language-culture code from a
|
|
|
|
<a href="https://msdn.microsoft.com/en-us/library/ee825488(v=cs.20).aspx" target="_blank">well-known codeset</a>.
|
|
|
|
|
|
|
|
Make a copy of the `messages.xlf` file, put it in the `locale` folder and
|
|
|
|
rename it `messages.es.xlf`for the Spanish language translation.
|
|
|
|
Do the same for each target language.
|
|
|
|
|
|
|
|
### Translate text nodes
|
|
|
|
In the real world, you send the `messages.es.xlf` file to a Spanish translator who fills 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 Spanish.
|
|
|
|
Open `messages.es.xlf` and find the first `<trans-unit>` section:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/locale/messages.es.xlf.html" region="translated-hello" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
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 Spanish greeting:
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/locale/messages.es.xlf.html" region="translated-hello" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
~~~ {.alert.is-important}
|
|
|
|
|
|
|
|
Note that the tool generates the `id`. **Don't touch it.**
|
|
|
|
Its value depends on the content of the message and its assigned meaning.
|
|
|
|
Change either factor and the `id` changes as well.
|
2017-03-11 10:36:40 -05:00
|
|
|
See the **[translation file maintenance discussion](guide/i18n#maintenance)**.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
~~~
|
|
|
|
|
|
|
|
Translate the other text nodes the same way:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/locale/messages.es.xlf.html" region="translated-other-nodes" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{@a translate-plural-select}
|
|
|
|
## Translate _plural_ and _select_
|
|
|
|
Translating _plural_ and _select_ messages is a little tricky.
|
|
|
|
|
|
|
|
The `<source>` tag is empty for `plural` and `select` translation
|
|
|
|
units, which makes them hard to correlate with the original template.
|
|
|
|
The `XLIFF` format doesn't yet support the ICU rules; it soon will.
|
|
|
|
However, the `XMB` format does support the ICU rules.
|
|
|
|
|
|
|
|
You'll just have to look for them in relation to other translation units that you recognize from elsewhere in the source template.
|
|
|
|
In this example, you know the translation unit for the `select` must be just below the translation unit for the logo.
|
|
|
|
### Translate _plural_
|
|
|
|
To translate a `plural`, translate its ICU format match values:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/locale/messages.es.xlf.html" region="translated-plural" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
### Translate _select_
|
|
|
|
The `select` behaves a little differently. Here again is the ICU format message in the component template:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/app.component.html" region="i18n-select" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
The extraction tool broke that into _two_ translation units.
|
|
|
|
|
|
|
|
The first unit contains the text that was _outside_ the `select`.
|
|
|
|
In place of the `select` is a placeholder, `<x id="ICU">`, that represents the `select` message.
|
|
|
|
Translate the text and leave the placeholder where it is.
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/locale/messages.es.xlf.html" region="translate-select-1" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
The second translation unit, immediately below the first one, contains the `select` message. Translate that.
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/locale/messages.es.xlf.html" region="translate-select-2" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
Here they are together, after translation:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/locale/messages.es.xlf.html" region="translated-select" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
<div class='l-main-content'>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
The entire template translation is complete. It's
|
|
|
|
time to incorporate that translation into the application.
|
|
|
|
|
|
|
|
<div id='app-pre-translation'>
|
|
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
### The app before translation
|
|
|
|
|
|
|
|
When the previous steps finish, the sample app _and_ its translation file are as follows:
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-tabs>
|
|
|
|
|
|
|
|
<code-pane title="src/app/app.component.html" path="cb-i18n/src/app/app.component.html">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-pane>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-pane title="src/app/app.component.ts" path="cb-i18n/src/app/app.component.ts">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-pane>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-pane title="src/app/app.module.ts" path="cb-i18n/src/app/app.module.ts">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-pane>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-pane title="src/main.ts" path="cb-i18n/src/main.1.ts">
|
2017-02-22 13:09:39 -05:00
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
</code-pane>
|
|
|
|
|
|
|
|
|
|
|
|
<code-pane title="src/locale/messages.es.xlf" path="cb-i18n/src/locale/messages.es.xlf.html">
|
|
|
|
|
|
|
|
</code-pane>
|
|
|
|
|
|
|
|
|
|
|
|
</code-tabs>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{@a merge}
|
|
|
|
|
|
|
|
## Merge the completed translation file into the app
|
|
|
|
|
|
|
|
To merge the translated text into component templates,
|
|
|
|
compile the application with the completed translation file.
|
|
|
|
The process is the same whether the file is in `.xlf` format or
|
|
|
|
in another format (`.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 <a href="https://en.wikipedia.org/wiki/XLIFF" target="_blank">_Locale ID_</a>
|
|
|
|
(`es` or `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.
|
|
|
|
|
2017-03-11 10:36:40 -05:00
|
|
|
* With [JIT](guide/i18n#jit), you provide the information at bootstrap time.
|
|
|
|
* With [AOT](guide/i18n#aot), you pass the information as `ngc` options.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
|
|
|
|
{@a jit}
|
|
|
|
|
|
|
|
### Merge with the JIT compiler
|
|
|
|
|
|
|
|
The JIT 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 follows:
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/index.html" region="i18n" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
In this sample, the user's language is hardcoded as a global `document.locale` variable
|
|
|
|
in the `index.html`.
|
|
|
|
|
|
|
|
|
|
|
|
{@a text-plugin}
|
|
|
|
### SystemJS Text plugin
|
|
|
|
|
|
|
|
Notice the SystemJS mapping of `text` to a `systemjs-text-plugin.js`.
|
|
|
|
With the help of a text plugin, 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 `src/` folder:
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/systemjs-text-plugin.js" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
### 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 `src/app/i18n-providers.ts`
|
|
|
|
creates those providers based on the user's _locale_
|
|
|
|
and the corresponding translation file:
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/app/i18n-providers.ts">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
1. It gets the locale from the global `document.locale` variable that was set in `index.html`.
|
|
|
|
|
|
|
|
1. If there is no locale or the language is U.S. English (`en-US`), 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.
|
|
|
|
|
|
|
|
1. It creates a transaction filename from the locale according to the name and location convention
|
2017-03-11 10:36:40 -05:00
|
|
|
[described earlier](guide/i18n#localization-folder).
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
1. The `getTranslationsWithSystemJs` method reads the translation and returns the contents as a string.
|
2017-03-11 10:36:40 -05:00
|
|
|
Notice that it appends `!text` to the filename, telling SystemJS to use the [text plugin](guide/i18n#text-plugin).
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
1. The callback composes a providers array with the three translation providers.
|
|
|
|
|
|
|
|
1. 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 `src/main.ts` and modify the bootstrap code as follows:
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
<code-example path="cb-i18n/src/main.ts" linenums="false">
|
|
|
|
|
|
|
|
</code-example>
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
Notice that it waits for the `getTranslationProviders` promise to resolve before
|
|
|
|
bootstrapping the app.
|
|
|
|
|
|
|
|
The app is now _internationalized_ for English and Spanish and there is a clear path for adding
|
|
|
|
more languages.
|
|
|
|
|
|
|
|
|
|
|
|
{@a aot}
|
|
|
|
|
|
|
|
### _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 compiler to apply a translations file.
|
|
|
|
|
|
|
|
Internationalization with the AOT compiler requires
|
|
|
|
some setup specifically for AOT compilation.
|
|
|
|
Start with the application project as shown
|
2017-03-11 10:36:40 -05:00
|
|
|
[just before merging the translation file](guide/i18n#app-pre-translation)
|
|
|
|
and refer to the [AOT cookbook](guide/aot-compiler) to make it _AOT-ready_.
|
2017-02-22 13:09:39 -05:00
|
|
|
|
|
|
|
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 Spanish language command would be
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
|
|
./node_modules/.bin/ngc --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf
|
|
|
|
|
|
|
|
</code-example>
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
|
|
|
|
~~~ {.l-sub-section}
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
Windows users may have to quote the command:
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
|
|
"./node_modules/.bin/ngc" --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf
|
|
|
|
|
|
|
|
</code-example>
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-03-27 11:08:53 -04:00
|
|
|
~~~
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-02-22 13:09:39 -05:00
|
|
|
{@a maintenance}
|
|
|
|
## Translation file maintenance and _id_ changes
|
|
|
|
|
|
|
|
As the application evolves, you will change the _i18n_ markup
|
|
|
|
and re-run the `ng-xi18n` extraction tool many times.
|
|
|
|
The _new_ markup that you add is not a problem;
|
|
|
|
but _most_ changes to _existing_ markup trigger
|
|
|
|
generation of _new_ `id`s for the affected translation units.
|
|
|
|
|
|
|
|
After an `id` changes, the translation files are no longer in-sync.
|
|
|
|
**All translated versions of the application will fail** during re-compilation.
|
|
|
|
The error messages identify the old `id`s that are no longer valid but
|
|
|
|
they don't tell you what the new `id`s should be.
|
|
|
|
|
|
|
|
**Commit all translation message files to source control**,
|
|
|
|
especially the English source `messages.xlf`.
|
|
|
|
The difference between the old and the new `messages.xlf` file
|
|
|
|
help you find and update `id` changes across your translation files.
|