841 lines
34 KiB
Markdown
841 lines
34 KiB
Markdown
# Internationalization (i18n)
|
|
|
|
Application internationalization is a many-faceted area of development, focused on making
|
|
applications available and user-friendly to a worldwide audience. This page describes Angular's
|
|
internationalization (i18n) tools, which can help you make your app available in multiple languages.
|
|
|
|
See the <live-example downloadOnly name="i18n">i18n Example</live-example> for a simple example of
|
|
an AOT-compiled app, translated into French.
|
|
|
|
{@a angular-i18n}
|
|
## Angular and i18n
|
|
|
|
*Internationalization* is the process of designing and preparing your app to be usable in different languages.
|
|
*Localization* is the process of translating your internationalized app into specific languages for particular locales.
|
|
|
|
Angular simplifies the following aspects of internationalization:
|
|
* Displaying dates, number, percentages, and currencies in a local format.
|
|
* Preparing text in component templates for translation.
|
|
* Handling plural forms of words.
|
|
* Handling alternative text.
|
|
|
|
For localization, you can use the [Angular CLI](cli) to generate most of the boilerplate necessary to create files for translators, and to publish your app in multiple languages.
|
|
After you have set up your app to use i18n, the CLI can help you with the following steps:
|
|
* Extracting localizable text into a file that you can send out to be translated.
|
|
* Building and serving the app for a given locale, using the translated text.
|
|
* Creating multiple language versions of your app.
|
|
|
|
|
|
{@a setting-up-locale}
|
|
## Setting up the locale of your app
|
|
|
|
A locale is an identifier (id) that refers to a set of user preferences that tend to be shared
|
|
within a region of the world, such as country. This document refers to a locale identifier as a
|
|
"locale" or "locale id".
|
|
|
|
A Unicode locale identifier is composed of a Unicode language identifier and (optionally) the
|
|
character `-` followed by a locale extension. (For historical reasons the character `_` is supported
|
|
as an alternative to `-`.) For example, in the locale id `fr-CA` the `fr` refers to the French
|
|
language identifier, and the `CA` refers to the locale extension Canada.
|
|
|
|
<div class="alert is-critical">
|
|
|
|
Angular follows the Unicode LDML convention that uses stable identifiers (Unicode locale identifiers)
|
|
based on the norm [BCP47](http://www.rfc-editor.org/rfc/bcp/bcp47.txt). It is very important that
|
|
you follow this convention when you define your locale, because the Angular i18n tools use this
|
|
locale id to find the correct corresponding locale data.
|
|
|
|
</div>
|
|
|
|
By default, Angular uses the locale `en-US`, which is English as spoken in the United States of America.
|
|
|
|
For more information about Unicode locale identifiers, see the
|
|
[CLDR core spec](http://cldr.unicode.org/core-spec#Unicode_Language_and_Locale_Identifiers).
|
|
|
|
For a complete list of locales supported by Angular, see
|
|
[the Angular repository](https://github.com/angular/angular/tree/master/packages/common/locales).
|
|
|
|
The locale identifiers used by CLDR and Angular are based on [BCP47](http://www.rfc-editor.org/rfc/bcp/bcp47.txt).
|
|
These specifications change over time; the following table maps previous identifiers to current ones at
|
|
time of writing:
|
|
|
|
| Locale name | Old locale id | New locale id |
|
|
|-------------------------------|-------------------|---------------|
|
|
| Indonesian | in | id |
|
|
| Hebrew | iw | he |
|
|
| Romanian Moldova | mo | ro-MD |
|
|
| Norwegian Bokmål | no, no-NO | nb |
|
|
| Serbian Latin | sh | sr-Latn |
|
|
| Filipino | tl | fil |
|
|
| Portuguese Brazil | pt-BR | pt |
|
|
| Chinese Simplified | zh-cn, zh-Hans-CN | zh-Hans |
|
|
| Chinese Traditional | zh-tw, zh-Hant-TW | zh-Hant |
|
|
| Chinese Traditional Hong Kong | zh-hk | zh-Hant-HK |
|
|
|
|
|
|
## i18n pipes
|
|
|
|
Angular pipes can help you with internationalization: the `DatePipe`, `CurrencyPipe`, `DecimalPipe`
|
|
and `PercentPipe` use locale data to format data based on the `LOCALE_ID`.
|
|
|
|
By default, Angular only contains locale data for `en-US`. If you set the value of
|
|
`LOCALE_ID` to another locale, you must import locale data for that new locale.
|
|
The CLI imports the locale data for you when you use the parameter `--configuration` with `ng serve` and
|
|
`ng build`.
|
|
|
|
If you want to import locale data for other languages, you can do it manually:
|
|
|
|
<code-example path="i18n/doc-files/app.locale_data.ts" region="import-locale" header="src/app/app.module.ts" linenums="false">
|
|
</code-example>
|
|
|
|
The first parameter is an object containing the locale data imported from `@angular/common/locales`.
|
|
By default, the imported locale data is registered with the locale id that is defined in the Angular
|
|
locale data itself.
|
|
If you want to register the imported locale data with another locale id, use the second parameter to
|
|
specify a custom locale id. For example, Angular's locale data defines the locale id for French as
|
|
"fr". You can use the second parameter to associate the imported French locale data with the custom
|
|
locale id "fr-FR" instead of "fr".
|
|
|
|
The files in `@angular/common/locales` contain most of the locale data that you
|
|
need, but some advanced formatting options might only be available in the extra dataset that you can
|
|
import from `@angular/common/locales/extra`. An error message informs you when this is the case.
|
|
|
|
<code-example path="i18n/doc-files/app.locale_data_extra.ts" region="import-locale-extra" header="src/app/app.module.ts" linenums="false">
|
|
</code-example>
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
All locale data used by Angular are extracted from the Unicode Consortium's
|
|
<a href="http://cldr.unicode.org/" title="CLDR">Common Locale Data Repository (CLDR)</a>.
|
|
|
|
</div>
|
|
|
|
|
|
## Template translations
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
This document refers to a unit of translatable text as "text," a "message", or a
|
|
"text message."
|
|
|
|
</div>
|
|
|
|
The i18n template translation process has four phases:
|
|
|
|
1. Mark static text messages in your component templates for translation.
|
|
|
|
2. Create a translation file: Use the Angular CLI `xi18n` command to extract the marked text into an industry-standard translation source file.
|
|
|
|
3. Edit the generated translation file: Translate the extracted text into the target language.
|
|
|
|
4. Merge the completed translation file into the app. To do this, use the Angular CLI `build` command to compile the app, choosing a [locale-specific configuration](#merge-aot), or specifying the following command options.
|
|
|
|
* `--i18nFile`=*path to the translation file*
|
|
* `--i18nFormat`=*format of the translation file*
|
|
* `--i18nLocale`= *locale id*
|
|
|
|
The command replaces the original messages with translated text, and generates a new version of the app in the target language.
|
|
|
|
You need to build and deploy a separate version of the app for each supported language.
|
|
|
|
{@a i18n-attribute}
|
|
### Mark text with the i18n attribute
|
|
|
|
The Angular `i18n` attribute marks translatable content. Place it on every element tag whose fixed
|
|
text is to be translated.
|
|
|
|
In the example below, an `<h1>` tag displays a simple English language greeting, "Hello i18n!"
|
|
|
|
<code-example path="i18n/doc-files/app.component.html" region="greeting" header="src/app/app.component.html" linenums="false">
|
|
</code-example>
|
|
|
|
To mark the greeting for translation, add the `i18n` attribute to the `<h1>` tag.
|
|
|
|
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute" header="src/app/app.component.html" linenums="false">
|
|
</code-example>
|
|
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
`i18n` is a custom attribute, recognized by Angular tools and compilers.
|
|
After translation, the compiler removes it. It is not an Angular directive.
|
|
|
|
</div>
|
|
|
|
|
|
{@a help-translator}
|
|
### Help the translator with a description and meaning
|
|
|
|
To translate a text message accurately, the translator may need additional information or context.
|
|
|
|
You can add a description of the text message as the value of the `i18n` attribute, as shown in the
|
|
example below:
|
|
|
|
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-desc" header="src/app/app.component.html" linenums="false">
|
|
</code-example>
|
|
|
|
The translator may also need to know the meaning or intent of the text message within this particular
|
|
app context.
|
|
|
|
You add context by beginning the `i18n` attribute value with the _meaning_ and
|
|
separating it from the _description_ with the `|` character: `<meaning>|<description>`
|
|
|
|
<code-example path="i18n/doc-files/app.component.html" region="i18n-attribute-meaning" header="src/app/app.component.html" linenums="false">
|
|
</code-example>
|
|
|
|
All occurrences of a text message that have the same meaning will have the same translation.
|
|
A text message that is associated with different meanings can have different translations.
|
|
|
|
The Angular extraction tool preserves both the meaning and the description in the translation
|
|
source file to facilitate contextually-specific translations, but only the combination of meaning
|
|
and text message are used to generate the specific id of a translation. If you have two
|
|
similar text messages with different meanings, they are extracted separately. If you have two similar
|
|
text messages with different descriptions (not different meanings), then they are extracted only once.
|
|
|
|
|
|
{@a custom-id}
|
|
### Set a custom id for persistence and maintenance
|
|
|
|
The angular i18n extractor tool generates a file with a translation unit entry for each `i18n`
|
|
attribute in a template. By default, it assigns each translation unit a unique id such as this one:
|
|
|
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="generated-id" linenums="false">
|
|
</code-example>
|
|
|
|
When you change the translatable text, the extractor tool generates a new id for that translation unit.
|
|
You must then update the translation file with the new id.
|
|
|
|
Alternatively, you can specify a custom id in the `i18n` attribute by using the prefix `@@`.
|
|
The example below defines the custom id `introductionHeader`:
|
|
|
|
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-solo-id' header='app/app.component.html' linenums="false">
|
|
</code-example>
|
|
|
|
When you specify a custom id, the extractor tool and compiler generate a translation unit with that
|
|
custom id.
|
|
|
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="custom-id" linenums="false">
|
|
</code-example>
|
|
|
|
The custom id is persistent. The extractor tool does not change it when the translatable text changes.
|
|
Therefore, you do not need to update the translation. This approach makes maintenance easier.
|
|
|
|
#### Use a custom id with a description
|
|
|
|
You can use a custom id in combination with a description by including both in the value of the
|
|
`i18n` attribute. In the example below, the `i18n` attribute value includes a description, followed
|
|
by the custom `id`:
|
|
|
|
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-id' header='app/app.component.html' linenums="false">
|
|
</code-example>
|
|
|
|
You also can add a meaning, as shown in this example:
|
|
|
|
<code-example path='i18n/doc-files/app.component.html' region='i18n-attribute-meaning-and-id' header='app/app.component.html' linenums="false">
|
|
</code-example>
|
|
|
|
#### Define unique custom ids
|
|
|
|
Be sure to define custom ids that are unique. If you use the same id for two different text messages,
|
|
only the first one is extracted, and its translation is used in place of both original text messages.
|
|
|
|
In the example below the custom id `myId` is used for two different messages:
|
|
|
|
```html
|
|
<h3 i18n="@@myId">Hello</h3>
|
|
<!-- ... -->
|
|
<p i18n="@@myId">Good bye</p>
|
|
```
|
|
|
|
Consider this translation to French:
|
|
|
|
```xml
|
|
<trans-unit id="myId" datatype="html">
|
|
<source>Hello</source>
|
|
<target state="new">Bonjour</target>
|
|
</trans-unit>
|
|
```
|
|
|
|
Because the custom id is the same, both of the elements in the resulting translation contain
|
|
the same text, `Bonjour`:
|
|
|
|
```html
|
|
<h3>Bonjour</h3>
|
|
<!-- ... -->
|
|
<p>Bonjour</p>
|
|
```
|
|
|
|
|
|
|
|
{@a no-element}
|
|
### Translate text without creating an element
|
|
|
|
If there is a section of text that you would like to translate, you can wrap it in a `<span>` tag.
|
|
However, if you don't want to create a new DOM element merely to facilitate translation,
|
|
you can wrap the text in an `<ng-container>` element.
|
|
The `<ng-container>` is transformed into an html comment:
|
|
|
|
<code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" header="src/app/app.component.html" linenums="false">
|
|
</code-example>
|
|
|
|
{@a translate-attributes}
|
|
### Translate attributes
|
|
|
|
Displayed text is sometimes supplied as the value of an attribute, rather than the content of tag.
|
|
For example, if your template has an image with a `title` attribute, the text value of the `title` attribute needs to be translated.
|
|
|
|
<code-example path="i18n/doc-files/app.component.html" region="i18n-title" header="src/app/app.component.html" linenums="false">
|
|
</code-example>
|
|
|
|
To mark an attribute for translation, add an attribute in the form of `i18n-x`,
|
|
where `x` is the name of the attribute to translate. The following example shows how to mark the
|
|
`title` attribute for translation by adding the `i18n-title` attribute on the `img` tag:
|
|
|
|
<code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" header="src/app/app.component.html" linenums="false">
|
|
</code-example>
|
|
|
|
This technique works for any attribute of any element.
|
|
|
|
You also can assign a meaning, description, and id with the `i18n-x="<meaning>|<description>@@<id>"`
|
|
syntax.
|
|
|
|
## Regular expressions for plurals and selections
|
|
|
|
Different languages have different pluralization rules and grammatical constructions that add
|
|
complexity to the translation task.
|
|
You can use regular expressions with the `plural` and `select` clauses to provide patterns that aid translation in these cases.
|
|
|
|
{@a plural-ICU}
|
|
### Pluralization
|
|
|
|
Suppose that you want to say that something was "updated x minutes ago".
|
|
In English, depending upon the number of minutes, you could display "just now", "one minute ago",
|
|
or "x minutes ago" (with x being the actual number).
|
|
Other languages might express the cardinality differently.
|
|
|
|
The example below shows how to use a `plural` ICU expression to display one of those three options
|
|
based on when the update occurred:
|
|
|
|
<code-example path="i18n/src/app/app.component.html" region="i18n-plural" header="src/app/app.component.html" linenums="false">
|
|
</code-example>
|
|
|
|
* The first parameter is the key. It is bound to the component property (`minutes`), which determines
|
|
the number of minutes.
|
|
* 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.
|
|
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
This syntax conforms to the
|
|
<a href="http://userguide.icu-project.org/formatparse/messages" title="ICU Message Format">ICU Message Format</a>
|
|
as specified in the
|
|
<a href="http://cldr.unicode.org/index/cldr-spec/plural-rules" title="Pluralization Rules">CLDR pluralization rules</a>.
|
|
|
|
</div>
|
|
|
|
Pluralization categories include (depending on the language):
|
|
|
|
* =0 (or any other number)
|
|
* zero
|
|
* one
|
|
* two
|
|
* few
|
|
* many
|
|
* other
|
|
|
|
After the pluralization category, put the default English text in braces (`{}`).
|
|
|
|
In the example above, the three options are specified according to that pluralization pattern. For
|
|
talking about zero minutes, you use `=0 {just now}`. For one minute, you use `=1 {one minute}`.
|
|
Any unmatched cardinality uses `other {{{minutes}} minutes ago}`. You could choose to add patterns
|
|
for two, three, or any other number if the pluralization rules were different. For the example of
|
|
"minute", only these three patterns are necessary in English.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
You can use interpolations and html markup inside of your translations.
|
|
|
|
</div>
|
|
|
|
{@a select-ICU}
|
|
### Select among alternative text messages
|
|
|
|
If your template needs to display different text messages depending on the value of a variable, you
|
|
need to translate all of those alternative text messages.
|
|
|
|
You can handle this with a `select` ICU expression. It is similar to the `plural` expressions
|
|
except that you choose among alternative translations based on a string value instead of a number,
|
|
and you define those string values.
|
|
|
|
The following format message in the component template binds to the component's `gender` property,
|
|
which outputs one of the following string values: "male", "female" or "other".
|
|
The message maps those values to the appropriate translations:
|
|
|
|
<code-example path="i18n/src/app/app.component.html" region="i18n-select" header="src/app/app.component.html" linenums="false">
|
|
</code-example>
|
|
|
|
{@a nesting-ICUS}
|
|
### Nesting plural and select ICU expressions
|
|
|
|
You can also nest different ICU expressions together, as shown in this example:
|
|
|
|
<code-example path="i18n/src/app/app.component.html" region="i18n-nested" header="src/app/app.component.html">
|
|
</code-example>
|
|
|
|
{@a ng-xi18n}
|
|
{@a ng-xi18n-options}
|
|
|
|
## Create a translation source file
|
|
|
|
When your app is ready, you can use the Angular CLI to extract the text messages marked with `i18n` and attributes marked with `i18n-x` into a translation source file.
|
|
Open a terminal window at the root of the app project and run the CLI command `xi18n`.
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
ng xi18n
|
|
</code-example>
|
|
|
|
By default, the command creates a file named `messages.xlf` in your `src/` folder.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
If you don't use the CLI, you have two options:
|
|
* You can use the `ng-xi18n` tool directly from the `@angular/compiler-cli` package.
|
|
For more information, see the [`ng xi18n` command documentation](cli/xi18n).
|
|
* You can use the CLI Webpack plugin `AngularCompilerPlugin` from the `@ngtools/webpack` package.
|
|
Set the parameters `i18nOutFile` and `i18nOutFormat` to trigger the extraction.
|
|
For more information, see the [Angular Ahead-of-Time Webpack Plugin documentation](https://github.com/angular/angular-cli/tree/master/packages/%40ngtools/webpack).
|
|
|
|
</div>
|
|
|
|
{@a other-formats}
|
|
### Output options
|
|
|
|
You can supply command options to change the format, the name, the location, and the source locale of the extracted file.
|
|
For example, to create a file in the `src/locale` folder, specify the output path:
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
ng xi18n --output-path src/locale
|
|
</code-example>
|
|
|
|
By default, the `xi18n` command generates a translation file named `messages.xlf` in the
|
|
<a href="https://en.wikipedia.org/wiki/XLIFF">XML Localization Interchange File Format
|
|
(XLIFF, version 1.2)</a>.
|
|
|
|
The command can read and write files in three translation formats:
|
|
* XLIFF 1.2 (default)
|
|
* XLIFF 2
|
|
* <a href="http://cldr.unicode.org/development/development-process/design-proposals/xmb" >XML Message
|
|
Bundle (XMB)</a>
|
|
|
|
You can specify the translation format explicitly with the `--i18nFormat` command option, as illustrated in
|
|
these example commands:
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
ng xi18n --i18n-format=xlf
|
|
ng xi18n --i18n-format=xlf2
|
|
ng xi18n --i18n-format=xmb
|
|
</code-example>
|
|
|
|
The sample in this guide uses the default XLIFF 1.2 format.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
XLIFF files have the extension .xlf. The XMB format generates .xmb source files but uses
|
|
.xtb (XML Translation Bundle: XTB) translation files.
|
|
|
|
</div>
|
|
|
|
You can change the name of the translation source file that is generated by the extraction tool with
|
|
the `--outFile` command option:
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
|
|
ng xi18n --out-file source.xlf
|
|
|
|
</code-example>
|
|
|
|
You can specify the base locale of your app with the`--i18n-locale` command option:
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
|
|
ng xi18n --i18n-locale fr
|
|
|
|
</code-example>
|
|
|
|
The extraction tool uses the locale to add the app locale information into your translation source
|
|
file. This information is not used by Angular, but external translation tools may need it.
|
|
|
|
|
|
{@a translate}
|
|
## Translate the source text
|
|
|
|
The `ng xi18n` command generates a translation source file named `messages.xlf` in the project `src`
|
|
folder.
|
|
The next step is to translate the display strings in this source file into language-specific
|
|
translation files. The example in this guide creates a French translation file.
|
|
|
|
{@a localization-folder}
|
|
### Create a localization folder
|
|
|
|
Most apps are translated into more than one other language. For this reason, it is standard practice
|
|
for the project structure to reflect the entire internationalization effort.
|
|
|
|
One approach is to dedicate a folder to localization and store related assets, such as
|
|
internationalization files, there.
|
|
|
|
<div class="alert is-helpful">
|
|
|
|
Localization and internationalization are
|
|
<a href="https://en.wikipedia.org/wiki/Internationalization_and_localization">different but
|
|
closely related terms</a>.
|
|
|
|
</div>
|
|
|
|
This guide follows that approach. It has a `locale` folder under `src/`.
|
|
Assets within that folder have a filename extension that matches their associated locale.
|
|
|
|
### Create the translation files
|
|
|
|
For each translation source file, there must be at least one language translation file for the
|
|
resulting translation.
|
|
|
|
For this example:
|
|
|
|
1. Make a copy of the `messages.xlf` file.
|
|
2. Put the copy in the `locale` folder.
|
|
3. Rename the copy to `messages.fr.xlf` for the French language translation.
|
|
|
|
If you were translating to other languages, you would repeat these steps for each target language.
|
|
|
|
{@a translate-text-nodes}
|
|
### Translate text nodes
|
|
|
|
In a large translation project, you would send the `messages.fr.xlf` file to a French translator who
|
|
would enter the translations using an XLIFF file editor.
|
|
|
|
This sample file is easy to translate without a special editor or knowledge of French.
|
|
|
|
1. Open `messages.fr.xlf` and find the first `<trans-unit>` section:
|
|
|
|
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello-before" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
|
</code-example>
|
|
|
|
> This XML element represents the translation of the `<h1>` greeting tag that you marked with the
|
|
`i18n` attribute earlier in this guide.
|
|
|
|
> Note that the translation unit `id=introductionHeader` is derived from the
|
|
[custom `id`](#custom-id "Set a custom id") that you set earlier, but
|
|
without the `@@` prefix required in the source HTML.
|
|
|
|
|
|
2. Duplicate the `<source/>` tag, rename it `target`, and then replace its content with the French
|
|
greeting. If you were working with a more complex translation, you could use the information
|
|
and context provided by the source, description, and meaning elements to guide your selection of
|
|
the appropriate French translation.
|
|
|
|
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-hello" header="src/locale/messages.fr.xlf (<trans-unit>, after translation)" linenums="false">
|
|
</code-example>
|
|
|
|
3. Translate the other text nodes the same way:
|
|
|
|
> <code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-other-nodes" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
|
</code-example>
|
|
|
|
<div class="alert is-important">
|
|
|
|
**The Angular i18n tools generated the ids for these translation units. Don't change them.**
|
|
Each `id` depends upon the content of the template text and its assigned meaning.
|
|
If you change either the text or the meaning, then the `id` changes.
|
|
For more information, see the **[translation file maintenance discussion](#custom-id)**.
|
|
|
|
</div>
|
|
|
|
{@a translate-plural-select}
|
|
## Translating plural and select expressions
|
|
|
|
The _plural_ and _select_ ICU expressions are extracted separately, so they require special attention
|
|
when preparing for translation.
|
|
|
|
Look for these expressions 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.
|
|
|
|
{@a translate-plural}
|
|
### Translate _plural_
|
|
|
|
To translate a `plural`, translate its ICU format match values:
|
|
|
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-plural" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
|
</code-example>
|
|
|
|
You can add or remove plural cases, with each language having its own cardinality. (See
|
|
[CLDR plural rules](http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html).)
|
|
|
|
{@a translate-select}
|
|
### Translate _select_
|
|
|
|
Below is the content of our example `select` ICU expression in the component template:
|
|
|
|
<code-example path="i18n/src/app/app.component.html" region="i18n-select" header="src/app/app.component.html" linenums="false">
|
|
</code-example>
|
|
|
|
The extraction tool broke that into two translation units because ICU expressions are extracted
|
|
separately.
|
|
|
|
The first unit contains the text that was outside of the `select`.
|
|
In place of the `select` is a placeholder, `<x id="ICU">`, that represents the `select` message.
|
|
Translate the text and move around the placeholder if necessary, but don't remove it. If you remove
|
|
the placeholder, the ICU expression will not be present in your translated app.
|
|
|
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-1" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
|
</code-example>
|
|
|
|
The second translation unit, immediately below the first one, contains the `select` message.
|
|
Translate that as well.
|
|
|
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-select-2" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
|
</code-example>
|
|
|
|
Here they are together, after translation:
|
|
|
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translated-select" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
|
</code-example>
|
|
|
|
{@a translate-nested}
|
|
### Translate a nested expression
|
|
|
|
A nested expression is similar to the previous examples. As in the previous example, there are
|
|
two translation units. The first one contains the text outside of the nested expression:
|
|
|
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-1" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
|
</code-example>
|
|
|
|
The second unit contains the complete nested expression:
|
|
|
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested-2" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
|
</code-example>
|
|
|
|
And both together:
|
|
|
|
<code-example path="i18n/doc-files/messages.fr.xlf.html" region="translate-nested" header="src/locale/messages.fr.xlf (<trans-unit>)" linenums="false">
|
|
</code-example>
|
|
|
|
The entire template translation is complete. The next section describes how to load that translation
|
|
into the app.
|
|
|
|
{@a app-pre-translation}
|
|
### The app and its translation file
|
|
|
|
The sample app and its translation file are now as follows:
|
|
|
|
<code-tabs>
|
|
<code-pane header="src/app/app.component.html" path="i18n/src/app/app.component.html">
|
|
</code-pane>
|
|
<code-pane header="src/app/app.component.ts" path="i18n/src/app/app.component.ts">
|
|
</code-pane>
|
|
<code-pane header="src/app/app.module.ts" path="i18n/src/app/app.module.ts">
|
|
</code-pane>
|
|
<code-pane header="src/main.ts" path="i18n/doc-files/main.1.ts">
|
|
</code-pane>
|
|
<code-pane header="src/locale/messages.fr.xlf" path="i18n/doc-files/messages.fr.xlf.html">
|
|
</code-pane>
|
|
</code-tabs>
|
|
|
|
{@a merge}
|
|
## Merge the completed translation file into the app
|
|
|
|
To merge the translated text into component templates, compile the app with the completed
|
|
translation file.
|
|
|
|
Provide the Angular compiler with three translation-specific pieces of information:
|
|
|
|
* The translation file.
|
|
* The translation file format.
|
|
* The locale (`fr` or `en-US` for instance).
|
|
|
|
The compilation process is the same whether the translation file is in `.xlf` format or in another
|
|
format that Angular understands, such as `.xtb`.
|
|
|
|
How you provide this information depends upon whether you compile with
|
|
the JIT compiler or the AOT compiler.
|
|
|
|
* With [AOT](guide/i18n#merge-aot), you pass the information as configuration settings.
|
|
* With [JIT](guide/i18n#merge-jit), you provide the information at bootstrap time.
|
|
|
|
|
|
{@a merge-aot}
|
|
### Merge with the AOT compiler
|
|
|
|
The [AOT compiler](guide/glossary#aot) is part of a build process that produces a small, fast,
|
|
ready-to-run application package, typically for production.
|
|
|
|
When you internationalize with the AOT compiler, you must pre-build a separate application
|
|
package for each language and serve the appropriate package based on either server-side language
|
|
detection or url parameters.
|
|
|
|
To instruct the AOT compiler to use your translation configuration, set the three "i18n" build configuration options in your `angular.json` file.
|
|
|
|
* `i18nFile`: the path to the translation file.
|
|
* `i18nFormat`: the format of the translation file.
|
|
* `i18nLocale`: the locale id.
|
|
|
|
You should also direct the output to a locale-specific folder to keep it separate from other locale versions of your app, by setting the `outputPath` configuration option.
|
|
|
|
```
|
|
"build": {
|
|
...
|
|
"configurations": {
|
|
...
|
|
"fr": {
|
|
"aot": true,
|
|
"outputPath": "dist/my-project-fr/",
|
|
"i18nFile": "src/locale/messages.fr.xlf",
|
|
"i18nFormat": "xlf",
|
|
"i18nLocale": "fr",
|
|
...
|
|
}
|
|
}
|
|
},
|
|
"serve": {
|
|
...
|
|
"configurations": {
|
|
...
|
|
"fr": {
|
|
"browserTarget": "*project-name*:build:fr"
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
You can then pass this configuration to the `ng serve` or `ng build` commands.
|
|
The example below shows how to serve the French language file created in previous
|
|
sections of this guide:
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
ng serve --configuration=fr
|
|
</code-example>
|
|
|
|
For production builds, you define a separate `production-fr` build configuration in
|
|
the CLI configuration file, `angular.json`.
|
|
|
|
```
|
|
...
|
|
"architect": {
|
|
"build": {
|
|
"builder": "@angular-devkit/build-angular:browser",
|
|
"options": { ... },
|
|
"configurations": {
|
|
"fr": {
|
|
"aot": true,
|
|
"outputPath": "dist/my-project-fr/",
|
|
"i18nFile": "src/locale/messages.fr.xlf",
|
|
"i18nFormat": "xlf",
|
|
"i18nLocale": "fr",
|
|
"i18nMissingTranslation": "error",
|
|
}
|
|
// ...
|
|
"serve": {
|
|
"builder": "@angular-devkit/build-angular:dev-server",
|
|
"options": {
|
|
"browserTarget": "my-project:build"
|
|
},
|
|
"configurations": {
|
|
"production": {
|
|
"browserTarget": "my-project:build:production"
|
|
},
|
|
"fr": {
|
|
"browserTarget": "my-project:build:fr"
|
|
}
|
|
}
|
|
},
|
|
|
|
```
|
|
|
|
The same configuration options can also be provided through the CLI with your existing `production` configuration.
|
|
|
|
<code-example language="sh" class="code-shell">
|
|
ng build --prod --i18n-file src/locale/messages.fr.xlf --i18n-format xlf --i18n-locale fr
|
|
</code-example>
|
|
|
|
{@a merge-jit}
|
|
### Merge with the JIT compiler
|
|
|
|
The [JITcompiler](guide/glossary#jit) compiles your app in the browser as the app loads.
|
|
To support translation with the JIT compiler, you must do the following:
|
|
|
|
1. Import the appropriate language translation file as a string constant.
|
|
2. Create corresponding translation providers for the JIT compiler.
|
|
3. Bootstrap the app with those providers.
|
|
|
|
Three providers tell the JIT compiler how to translate the template texts for a particular language
|
|
while compiling the app:
|
|
|
|
* `TRANSLATIONS` is a string containing the content of the translation file.
|
|
* `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlf2`, or `xtb`.
|
|
* `LOCALE_ID` is the locale of the target language.
|
|
|
|
The Angular `bootstrapModule` method has a second `compilerOptions` parameter that can influence the
|
|
behavior of the compiler. You can use it to specify the translation providers:
|
|
|
|
<code-example path="i18n/doc-files/main.2.ts" header="src/main.ts">
|
|
</code-example>
|
|
|
|
Then provide the `LOCALE_ID` in the main module:
|
|
|
|
<code-example path="i18n/doc-files/app.module.ts" header="src/app/app.module.ts" linenums="false">
|
|
</code-example>
|
|
|
|
|
|
{@a missing-translation}
|
|
### Report missing translations
|
|
By default, when a translation is missing, the build succeeds but generates a warning such as
|
|
`Missing translation for message "foo"`. You can configure the level of warning that is generated by
|
|
the Angular compiler:
|
|
|
|
* Error: throw an error. If you are using AOT compilation, the build will fail. If you are using JIT
|
|
compilation, the app will fail to load.
|
|
* Warning (default): show a 'Missing translation' warning in the console or shell.
|
|
* Ignore: do nothing.
|
|
|
|
You specify the warning level in the `configurations` section your Angular CLI build configuration. The example below shows how to set the warning level to error:
|
|
|
|
```
|
|
"configurations": {
|
|
...
|
|
"fr": {
|
|
...
|
|
"i18nMissingTranslation": "error"
|
|
}
|
|
}
|
|
```
|
|
|
|
If you use the JIT compiler, specify the warning level in the compiler config at bootstrap by adding
|
|
the 'MissingTranslationStrategy' property. The example below shows how to set the warning level to
|
|
error:
|
|
|
|
<code-example path="i18n/doc-files/main.3.ts" header="src/main.ts">
|
|
</code-example>
|
|
|
|
### Build for multiple locales
|
|
|
|
When you use the CLI `build` or `serve` command to build your application for different locales, change the output path using the `--outputPath` command option (along with the i18n-specific command options), so that the translation files are saved to different locations.
|
|
When you are serving a locale-specific version from a subdirectory, you can also change the base URL used by your app by specifying the `--baseHref` option.
|
|
|
|
For example, if the French version of your application is served from https://myapp.com/fr/, configure the build for the French version as follows.
|
|
|
|
```
|
|
"configurations": {
|
|
"fr": {
|
|
"aot": true,
|
|
"outputPath": "dist/my-project-fr/",
|
|
"baseHref": "/fr/",
|
|
"i18nFile": "src/locale/messages.fr.xlf",
|
|
"i18nFormat": "xlf",
|
|
"i18nLocale": "fr",
|
|
"i18nMissingTranslation": "error",
|
|
}
|
|
```
|
|
|
|
For more details about how to create scripts to generate an app in multiple languages and how to set up Apache 2 to serve them from different subdirectories, read [this tutorial by Philippe Martin](https://medium.com/@feloy/deploying-an-i18n-angular-app-with-angular-cli-fc788f17e358#.1xq4iy6fp).
|