983 lines
38 KiB
Markdown
983 lines
38 KiB
Markdown
# Internationalization (i18n)
|
||
|
||
# 国际化(i18n)
|
||
|
||
Angular's _internationalization_ (_i18n_) tools help make your app available in multiple languages.
|
||
|
||
Angular的*国际化*(*i18n*)工具可以帮助我们使用多个语言发布应用。
|
||
|
||
Try this <live-example name="i18n" title="i18n Example in Spanish">live example</live-example>
|
||
of a JIT-compiled app, translated into Spanish.
|
||
|
||
**试试** 这个翻译为西班牙语版JiT编译应用的<live-example name="i18n">在线例子</live-example>。
|
||
|
||
|
||
{@a angular-i18n}
|
||
|
||
## Angular and _i18n_ template translation
|
||
|
||
## Angular和_i18n_模板翻译
|
||
|
||
Application internationalization is a challenging, many-faceted effort that
|
||
takes dedication and enduring commitment.
|
||
Angular's _i18n_ internationalization facilities can help.
|
||
|
||
应用程序国际化很具有挑战性,多方面的努力,需要持久的奉献和决心。
|
||
Angular的_i18n_国际化工具可以帮助你。
|
||
|
||
This page describes the _i18n_ tools available to assist translation of component template text
|
||
into multiple languages.
|
||
|
||
本章描述了一些_i18n_工具,它们可以帮你把组件模板文本翻译成多种语言。
|
||
|
||
<div class="l-sub-section">
|
||
|
||
Practitioners of _internationalization_ refer to a translatable text as a "_message_".
|
||
This page uses the words "_text_" and "_message_" interchangeably and in the combination, "_text message_".
|
||
**国际化**工作者通常将一个可翻译的文本叫作“信息”。
|
||
本章使用了“文本”和“信息”,它们可以互换,也可以组合“文本信息”。
|
||
|
||
</div>
|
||
|
||
The _i18n_ template translation process has four phases:
|
||
|
||
_i18n_模板翻译流程有四个阶段:
|
||
|
||
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.
|
||
|
||
Angular的_i18n_工具将标记的信息提取到一个行业标准的翻译源文件。
|
||
|
||
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.
|
||
|
||
Angular编译器导入完成翻译的文件,使用翻译的文本替换原始信息,并生成新的目标语言版本的应用程序。
|
||
|
||
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
|
||
|
||
## 使用_i18n_属性标记文本
|
||
|
||
The Angular `i18n` attribute is a marker for translatable content.
|
||
Place it on every element tag whose fixed text should be translated.
|
||
|
||
Angular的`i18n`属性是可翻译内容的标记。
|
||
将它放到每个固定文本需要翻译的元素标签中。
|
||
|
||
|
||
<div class="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.
|
||
|
||
`i18n`不是Angular指令。
|
||
它是一个自定义**属性**,Angular工具和编译器认识它。
|
||
它将在完成翻译**之后**,被编译器移除。
|
||
|
||
</div>
|
||
|
||
In the accompanying sample, an `<h1>` tag displays a simple English language greeting
|
||
that you translate into Spanish:
|
||
|
||
在例子中,`<h1>`标签显示了一句简单的英文问候语,它将被翻译为西班牙语:
|
||
|
||
|
||
<code-example path="i18n/src/app/app.component.1.html" region="greeting" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
Add the `i18n` attribute to the tag to mark it for translation.
|
||
|
||
|
||
添加`i18n`属性到该标签上,把它标记为需要翻译的文本。<code-example path="i18n/src/app/app.component.1.html" region="i18n-attribute" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
{@a help-translator}
|
||
|
||
### Help the translator with a _description_ and _meaning_
|
||
|
||
### 用描述和意图来帮助翻译人员
|
||
|
||
In order to translate it accurately, the translator may
|
||
need a description of the message.
|
||
Assign a description to the i18n attribute:
|
||
|
||
|
||
翻译人员可能需要待翻译文本的描述才能翻译准确。
|
||
为i18n属性添加描述:<code-example path="i18n/src/app/app.component.1.html" region="i18n-attribute-desc" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
In order to deliver a correct translation, the translator may need to
|
||
know the _meaning_ or _intent_ of the text within _this particular_ application context.
|
||
|
||
为了给出正确的翻译,翻译者需要知道你这段文本在特定情境下的 *真实意图*。
|
||
在描述的前面,为指定的字符串添加一些上下文含义,用`|`将其与描述文字隔开(`<意图>|<描述>`)。
|
||
|
||
You add context by beginning the string with the _meaning_ and
|
||
separating it from the _description_ with the `|` character (`<meaning>|<description>`):
|
||
|
||
// TODO: Translate
|
||
|
||
<code-example path="i18n/src/app/app.component.1.html" region="i18n-attribute-meaning" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
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 facilitate contextually-specific translations.
|
||
|
||
如果所有地方出现的文本具有**相同**含义时,它们应该有**相同**的翻译,
|
||
但是如果在某些地方它具有**不同含义**,那么它应该有不同的翻译。
|
||
Angular的提取工具在翻译源文件中保留**含义**和**描述**,以支持符合特定上下文的翻译。
|
||
|
||
|
||
{@a custom-id}
|
||
|
||
### Set a custom _id_ to improve search and maintenance
|
||
|
||
// TODO: Translate
|
||
|
||
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/src/locale/messages.es.xlf.html" region="generated-id" linenums="false">
|
||
</code-example>
|
||
|
||
This _id_ is obscure and difficult for humans to read or remember.
|
||
|
||
Worse, when you change the translatable text, perhaps to fix a typo,
|
||
the extractor tool generates a new _id_ for that translation.
|
||
You will lose the translation unless you update it with the new _id_.
|
||
That [complicates maintenance](#maintenance).
|
||
|
||
Consider specifying your own, meaningful _id_ in the `i18n` attribute, **prefixed with `@@`**.
|
||
|
||
<code-example path='i18n/src/app/app.component.1.html' region='i18n-attribute-solo-id' title='app/app.component.html' linenums="false">
|
||
</code-example>
|
||
|
||
Now the extractor tool and compiler will generate a translation unit with _your custom id_ and never change it.
|
||
|
||
<code-example path="i18n/src/locale/messages.es.xlf.html" region="custom-id" linenums="false">
|
||
</code-example>
|
||
|
||
Here is the `i18n` attribute with a _definition_, followed by the custom `id`:
|
||
|
||
<code-example path='i18n/src/app/app.component.1.html' region='i18n-attribute-id' title='app/app.component.html' linenums="false">
|
||
</code-example>
|
||
|
||
Here is a _meaning_ and a _description_ and the _id_ at the end:
|
||
|
||
<code-example path='i18n/src/app/app.component.1.html' region='i18n-attribute-meaning-and-id' title='app/app.component.html' linenums="false">
|
||
</code-example>
|
||
|
||
<div class="l-sub-section">
|
||
|
||
Be sure to define _unique_ custom ids. If you use the same id for 2 _different_ blocks of text, only the first one will be extracted,
|
||
and its translation used in both blocks of text.
|
||
|
||
For example:
|
||
|
||
```html
|
||
<p i18n="@@myId">Hello</p>
|
||
<p i18n="@@myId">Good bye</p>
|
||
```
|
||
|
||
with the translation:
|
||
|
||
```xml
|
||
<trans-unit id="myId" datatype="html">
|
||
<source>Hello</source>
|
||
<target state="new">Hola</target>
|
||
</trans-unit>
|
||
```
|
||
|
||
Both `<p>` elements will contain the text `Hola`.
|
||
|
||
</div>
|
||
|
||
{@a no-element}
|
||
|
||
### 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 rendered:
|
||
|
||
<code-example path="i18n/src/app/app.component.html" region="i18n-ng-container" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
(2) Wrap the text in a pair of HTML comments:
|
||
|
||
<code-example path="i18n/src/app/app.component.html" region="i18n-with-comment" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
{@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:
|
||
|
||
<code-example path="i18n/src/app/app.component.1.html" region="i18n-title" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
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:
|
||
|
||
<code-example path="i18n/src/app/app.component.html" region="i18n-title-translate" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
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:
|
||
|
||
<code-example path="i18n/src/app/app.component.html" region="i18n-plural" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
* 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 (or any other number)
|
||
* zero
|
||
* one
|
||
* two
|
||
* few
|
||
* many
|
||
* 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}`.
|
||
|
||
<div class="l-sub-section">
|
||
|
||
This syntax conforms to the
|
||
<a href="http://userguide.icu-project.org/formatparse/messages" title="ICU Message Format">ICU Message Format</a>
|
||
that derives from the
|
||
<a href="http://cldr.unicode.org/" title="CLDR">Common Locale Data Repository (CLDR)</a>,
|
||
which specifies the
|
||
<a href="http://cldr.unicode.org/index/cldr-spec/plural-rules" title="Pluralization Rules">pluralization rules</a>.
|
||
|
||
</div>
|
||
|
||
{@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" 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:
|
||
|
||
<code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
## Nesting pluralization and selection expressions
|
||
|
||
You can also nest different ICU expressions together. For example:
|
||
|
||
<code-example path="i18n/src/app/app.component.html" region="i18n-nested" title="src/app/app.component.html">
|
||
</code-example>
|
||
|
||
{@a ng-xi18n}
|
||
|
||
## Create a translation source file with the _ng-xi18n_ tool
|
||
|
||
## 使用_ng-xi18n_工具创建翻译源文件
|
||
|
||
Use the **_ng-xi18n_ extraction tool** to extract the `i18n`-marked texts
|
||
into a translation source file in an industry standard format.
|
||
|
||
使用`ng-xi18n`提取工具来将`i18n`标记的文本提取到一个符合行业标准格式的翻译源文件。
|
||
|
||
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:
|
||
|
||
它是在`@angular/compiler-cli` npm包中的一个Angular CLI工具。
|
||
如果你还没有安装这个CLI和它的 `platform-server`,安装它们:
|
||
|
||
<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:
|
||
|
||
在应用的项目根目录打开一个终端窗口,并输入`ng-xi18n`命令:
|
||
|
||
|
||
<code-example language="sh" class="code-shell">
|
||
./node_modules/.bin/ng-xi18n
|
||
</code-example>
|
||
|
||
<div class="l-sub-section">
|
||
|
||
Windows users may have to quote the command like this: `"./node_modules/.bin/ng-xi18n"`
|
||
|
||
</div>
|
||
|
||
By default, the tool 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>.
|
||
工具默认生成一个名为**`messages.xlf`**的翻译文件,格式为<a href="https://en.wikipedia.org/wiki/XLIFF" target="_blank">XML本土化互换文件格式(XLIFF, version 1.2)</a>。
|
||
|
||
{@a other-formats}
|
||
|
||
### Other translation formats
|
||
|
||
Angular i18n tooling supports XLIFF 1.2 and XLIFF 2 as well as the
|
||
<a href="http://cldr.unicode.org/development/development-process/design-proposals/xmb" >XML Message Bundle (XMB)</a>.
|
||
|
||
You can specify your choice of format _explicitly_ with the `--i18nFormat` flag as illustrated in these example commands
|
||
|
||
<code-example language="sh" class="code-shell">
|
||
./node_modules/.bin/ng-xi18n --i18nFormat=xlf --outFile=messages.xlf
|
||
./node_modules/.bin/ng-xi18n --i18nFormat=xlf2 --outFile=messages.xliff2.xlf
|
||
./node_modules/.bin/ng-xi18n --i18nFormat=xmb --outFile=messages.xmb
|
||
</code-example>
|
||
|
||
The sample in _this_ guide sticks with the default _XLIFF 1.2_ 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 guide sample creates a Spanish translation file.
|
||
`ng-xi18n`命令在项目根目录生成一个名为`messages.xlf`的翻译源文件。
|
||
下一步是将英文模板文本翻译到目标语言的翻译文件。
|
||
本烹饪书创建了一个西班牙语翻译文件。
|
||
|
||
{@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 ,
|
||
such as internationalization files, there.
|
||
|
||
其中一种方法是为本土化和相关资源(比如国际化文件)创建一个专门的目录。
|
||
|
||
|
||
<div class="l-sub-section">
|
||
|
||
Localization and internationalization are
|
||
<a href="https://en.wikipedia.org/wiki/Internationalization_and_localization">different but closely related terms</a>.
|
||
|
||
本土化和国际化是<a href="https://en.wikipedia.org/wiki/Internationalization_and_localization" target="_blank">不同但是很相近的概念</a>。
|
||
|
||
</div>
|
||
|
||
This guide follows that suggestion. It has a `locale` folder under `src/`.
|
||
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">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.
|
||
|
||
{@a translate-text-nodes}
|
||
|
||
### 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">many XLIFF file editors</a>.
|
||
|
||
在现实世界中,`messages.es.xlf`文件会被发给西班牙语翻译,他们使用<a href="https://en.wikipedia.org/wiki/XLIFF#Editors" target="_blank">这些XLIFF文件编辑器</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:
|
||
|
||
|
||
我们不需要任何编辑器或者西班牙语知识就可以轻易的翻译本例子文件。
|
||
打开`messages.es.xlf`并找到`<trans-unit>`节点:<code-example path="i18n/src/locale/messages.es.xlf.html" region="translated-hello" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
|
||
</code-example>
|
||
|
||
This XML element represents the translation of the `<h1>` greeting tag you marked with the `i18n` attribute.
|
||
|
||
这个XML元素代表了你使用`i18n`属性标记的`<h1>`问候语标签的翻译。
|
||
|
||
<div class="l-sub-section">
|
||
// TODO: Translate
|
||
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.
|
||
|
||
</div>
|
||
|
||
Using the _source_, _description_, and _meaning_ elements to guide your translation,
|
||
replace the `<target/>` tag with the Spanish greeting:
|
||
|
||
翻译中利用_source_、_description_和_meaning_元素的信息,替换`<target/>`标签为西班牙语问候语:
|
||
|
||
|
||
<code-example path="i18n/src/locale/messages.es.xlf.html" region="translated-hello" title="src/locale/messages.es.xlf (<trans-unit>, after translation)" linenums="false">
|
||
</code-example>
|
||
|
||
Translate the other text nodes the same way:
|
||
|
||
<code-example path="i18n/src/locale/messages.es.xlf.html" region="translated-other-nodes" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
|
||
</code-example>
|
||
|
||
<div class="alert is-important">
|
||
|
||
**The tool generated the `id`s for _these_ translation units. Don't touch them.**
|
||
Each `id` depends upon the content of the message and its assigned meaning.
|
||
Change either factor and the `id` changes as well.
|
||
|
||
注意`id`是工具生成的。不要修改它。
|
||
它的值取决于两个因素:信息的内容和其指定的含义。
|
||
改变任何一个因素,`id`就会改变。
|
||
|
||
See the **[translation file maintenance discussion](#maintenance)**.
|
||
|
||
This is why you should **[specify custom ids](#custom-id "Set a custom id")** and avoid tool generated ids.
|
||
|
||
</div>
|
||
|
||
{@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.
|
||
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.
|
||
|
||
{@a translate-plural}
|
||
|
||
### Translate _plural_
|
||
To translate a `plural`, translate its ICU format match values:
|
||
|
||
<code-example path="i18n/src/locale/messages.es.xlf.html" region="translated-plural" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
|
||
</code-example>
|
||
|
||
{@a translate-select}
|
||
|
||
### Translate _select_
|
||
The `select` behaves a little differently. Here again is the ICU format message in the component template:
|
||
|
||
<code-example path="i18n/src/app/app.component.html" region="i18n-select" title="src/app/app.component.html" linenums="false">
|
||
</code-example>
|
||
|
||
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.
|
||
|
||
<code-example path="i18n/src/locale/messages.es.xlf.html" region="translate-select-1" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
|
||
</code-example>
|
||
|
||
The second translation unit, immediately below the first one, contains the `select` message. Translate that.
|
||
|
||
<code-example path="i18n/src/locale/messages.es.xlf.html" region="translate-select-2" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
|
||
</code-example>
|
||
|
||
Here they are together, after translation:
|
||
|
||
<code-example path="i18n/src/locale/messages.es.xlf.html" region="translated-select" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
|
||
</code-example>
|
||
|
||
### Translate a nested expression
|
||
|
||
A nested expression is not different from the previous ones. As in the previous example, we have _two_ translation units.
|
||
|
||
The first one contains the text outside the nested expression:
|
||
|
||
<code-example path="i18n/src/locale/messages.es.xlf.html" region="translate-nested-1" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
|
||
</code-example>
|
||
|
||
The second unit contains the complete nested expression:
|
||
|
||
<code-example path="i18n/src/locale/messages.es.xlf.html" region="translate-nested-2" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
|
||
</code-example>
|
||
|
||
And both together:
|
||
|
||
<code-example path="i18n/src/locale/messages.es.xlf.html" region="translate-nested" title="src/locale/messages.es.xlf (<trans-unit>)" linenums="false">
|
||
</code-example>
|
||
|
||
|
||
|
||
The entire template translation is complete. It's
|
||
time to incorporate that translation into the application.
|
||
|
||
<a id='app-pre-translation'></a>
|
||
|
||
### The app before translation
|
||
|
||
### 翻译前的应用程序
|
||
|
||
When the previous steps finish, the sample app _and_ its translation file are as follows:
|
||
|
||
如下所示,是完成前面的步骤后的例子应用**和**它的翻译文件:
|
||
|
||
|
||
<code-tabs>
|
||
<code-pane title="src/app/app.component.html" path="i18n/src/app/app.component.html">
|
||
</code-pane>
|
||
<code-pane title="src/app/app.component.ts" path="i18n/src/app/app.component.ts">
|
||
</code-pane>
|
||
<code-pane title="src/app/app.module.ts" path="i18n/src/app/app.module.ts">
|
||
</code-pane>
|
||
<code-pane title="src/main.ts" path="i18n/src/main.1.ts">
|
||
</code-pane>
|
||
<code-pane title="src/locale/messages.es.xlf" path="i18n/src/locale/messages.es.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 application with the completed translation file.
|
||
The process is the same whether the file is in `.xlf` format or
|
||
in another format that Angular understands, such as `.xtb`.
|
||
|
||
要合并已经翻译的文件到组件模板,使用翻译过的文件编译应用。
|
||
不管文件是`.xlf`格式还是其他Angular接受的格式(`.xlif`和`.xtb`),流程是一样的。
|
||
|
||
You provide the Angular compiler with three new pieces of information:
|
||
|
||
你要为Angular编译器提供下列三种新信息:
|
||
|
||
* The translation file.
|
||
|
||
翻译文件
|
||
|
||
* The translation file format.
|
||
|
||
翻译文件的格式
|
||
|
||
* The <a href="https://en.wikipedia.org/wiki/XLIFF">_Locale ID_</a>
|
||
(`es` or `en-US` for instance).
|
||
|
||
目标<a href="https://en.wikipedia.org/wiki/XLIFF" target="_blank">_语言环境ID_</a>
|
||
(例如`es`或`en-US`)
|
||
|
||
_How_ you provide this information depends upon whether you compile with
|
||
the JIT (_Just-in-Time_) compiler or the AOT (_Ahead-of-Time_) compiler.
|
||
|
||
你如何提供这些信息取决于你使用的是JiT(即时)编译器还是AoT(预先)编译器。
|
||
|
||
* With [JIT](guide/i18n#jit), you provide the information at bootstrap time.
|
||
|
||
使用[JiT](guide/i18n#jit)时,在引导时提供
|
||
|
||
* With [AOT](guide/i18n#aot), you pass the information as `ngc` options.
|
||
|
||
使用[AoT](guide/i18n#aot)时,在`ngc`命令的选项里提供
|
||
|
||
|
||
{@a jit}
|
||
|
||
### Merge with the JIT compiler
|
||
|
||
### 用JiT编译器合并
|
||
|
||
The JIT compiler compiles the application in the browser as the application loads.
|
||
Translation with the JIT compiler is a dynamic process of:
|
||
|
||
JiT(即时)编译器在应用程序加载时,在浏览器中编译应用。
|
||
在使用JiT编译器的环境中翻译是一个动态的流程,包括:
|
||
|
||
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.
|
||
|
||
新建对应的翻译提供商来指导JiT编译器,
|
||
|
||
4. Bootstrapping the application with those providers.
|
||
|
||
使用这些提供商来启动应用。
|
||
|
||
Open `index.html` and revise the launch script as follows:
|
||
|
||
打开`index.html`并这样修改加载脚本:
|
||
|
||
|
||
<code-example path="i18n/src/index.html" region="i18n" title="index.html (launch script)" linenums="false">
|
||
</code-example>
|
||
|
||
In this sample, the user's language is hard-coded as a global `document.locale` variable
|
||
in the `index.html`.
|
||
|
||
在本例中,用户的语言在`index.html`中被硬编码到一个全局的`document.locale`变量中。
|
||
|
||
|
||
{@a text-plugin}
|
||
|
||
### SystemJS text plugin
|
||
|
||
### SystemJS文本插件
|
||
|
||
<div class="alert is-important">
|
||
// TODO: Translate
|
||
This plugin only applies to an application using SystemJS. If you are using the Angular CLI, please refer to their
|
||
[docs](https://github.com/angular/angular-cli/wiki/xi18n).
|
||
|
||
</div>
|
||
|
||
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将`text`映射为`systemjs-text-plug.js`。
|
||
在这个文本插件的帮助下,SystemJS可以读取任何原始文件并将其内容作为字符串返回。
|
||
你需要使用它来导入语言翻译文件。
|
||
|
||
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:
|
||
|
||
SystemJS没有自带原始文本插件,但是我们很容易添加它。
|
||
在`src/`目录新建下面的`systemjs-text-plugin.js`文件:
|
||
|
||
|
||
<code-example path="i18n/src/systemjs-text-plugin.js" title="src/systemjs-text-plugin.js" linenums="false">
|
||
</code-example>
|
||
|
||
{@a create-translation-providers}
|
||
|
||
### Create translation providers
|
||
|
||
### 新建翻译提供商
|
||
|
||
Three providers tell the JIT compiler how to translate the template texts for a particular language
|
||
while compiling the application:
|
||
|
||
三种提供商帮助JiT编译在编译应用时,将模板文本翻译到某种语言:
|
||
|
||
* `TRANSLATIONS` is a string containing the content of the translation file.
|
||
|
||
`TRANSLATIONS`是含有翻译文件内容的字符串。
|
||
|
||
* `TRANSLATIONS_FORMAT` is the format of the file: `xlf`, `xlf2`, or `xtb`.
|
||
|
||
`TRANSLATIONS_FORMAT`是文件的格式: `xlf`、`xlif`或`xtb`。
|
||
|
||
* `LOCALE_ID` is the locale of the target language.
|
||
|
||
`LOCALE_ID`是目标语言的语言环境。
|
||
|
||
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:
|
||
|
||
在下面的`src/app/i18n-providers.ts`文件的`getTranslationProviders()`函数中,根据用户的**语言环境**和对应的翻译文件构建这些提供商:
|
||
|
||
|
||
<code-example path="i18n/src/app/i18n-providers.ts" region="without-missing-translation" title="src/app/i18n-providers.ts">
|
||
</code-example>
|
||
|
||
1. It gets the locale from the global `document.locale` variable that was set in `index.html`.
|
||
|
||
它从在`index.html`中设置的全局`document.locale`变量中获取语言环境。
|
||
|
||
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.
|
||
|
||
如果没有语言环境或者语言是美国英语(`en-US`),则就无需翻译。该函数以`Promise`的形式返回一个空的`noProviders`数组。它必须要返回`Promise`,因为这个函数可能异步从服务器读取翻译文件。
|
||
|
||
1. It creates a transaction filename from the locale according to the name and location convention
|
||
[described earlier](guide/i18n#localization-folder).
|
||
|
||
根据[上面描述](guide/i18n#localization-folder)的名字和本土化的约定,它根据语言环境创建一个合约文件名。
|
||
|
||
1. 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](guide/i18n#text-plugin).
|
||
|
||
`getTranslationsWithSystemJs()`方法读取翻译并以字符串的形式返回其内容。
|
||
注意它在文件名上附加`!text`,告诉SystemJS使用[文本插件](guide/i18n#text-plugin)。
|
||
|
||
1. The callback composes a providers array with the three translation providers.
|
||
|
||
回调函数使用这三种翻译提供商创建一个提供商数组。
|
||
|
||
1. Finally, `getTranslationProviders()` returns the entire effort as a promise.
|
||
|
||
最后,`getTranslationProviders()`返回以承诺的形式返回全部流程的结果。
|
||
|
||
|
||
<div class="alert is-important">
|
||
// TDOO: Translate
|
||
The `LOCALE_ID` has to be a valid locale id as explained in [here](http://userguide.icu-project.org/locale).
|
||
|
||
</div>
|
||
|
||
{@a bootstrap-the-app}
|
||
|
||
### Bootstrap with translation providers
|
||
|
||
### 使用翻译提供商引导应用
|
||
|
||
The Angular `bootstrapModule()` method has a second _options_ parameter
|
||
that can influence the behavior of the compiler.
|
||
|
||
Angular的`bootstrapModule()`方法接受**可选的**第二参数,它可以影响编译器的行为。
|
||
|
||
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:
|
||
|
||
从`getTranslationProviders()`返回的翻译提供商创建_options_对象,并将其传给`bootstrapModule`。
|
||
打开`src/main.ts`并这样修改引导代码:
|
||
|
||
|
||
<code-example path="i18n/src/main.ts" title="src/main.ts" linenums="false">
|
||
</code-example>
|
||
|
||
Notice that it waits for the `getTranslationProviders()` promise to resolve before
|
||
bootstrapping the app.
|
||
|
||
注意,它等待`getTranslationProviders()`承诺的解析完成后,才引导应用。
|
||
|
||
The app is now _internationalized_ for English and Spanish and there is a clear path for adding
|
||
more languages.
|
||
|
||
现在,应用已经被国际化为英语版和西班牙语版,而且我们有了清晰的添加更多语言的方法。
|
||
|
||
|
||
{@a aot}
|
||
|
||
### _Internationalization_ with the AOT compiler
|
||
|
||
### 使用AoT编译器时的国际化
|
||
|
||
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.
|
||
|
||
JiT编译器在浏览器中动态编译应用时,将其翻译到目标语言。
|
||
这样很灵活,但是对用户来讲,可能速度太慢。
|
||
|
||
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, in this case `index.html`,
|
||
you determine which language the user needs
|
||
and serve the appropriate application package.
|
||
|
||
AoT(预先)编译器是一种构建流程,出产尺寸小、速度快和可执行的应用程序包。
|
||
在使用Aot编译器的环境中国际化,你为每种语言预先构建一个单独的应用程序包。然后,在宿主网络页面(`index.html`)中,你再决定用户需要哪种语言,并选择合适的应用程序包。
|
||
|
||
This guide 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.
|
||
|
||
本烹饪书不介绍如何构建多种应用程序包和如何根据用户的语言设置推送它们。
|
||
它介绍了一些必要的步骤,来告诉AoT采用翻译文件。
|
||
|
||
Internationalization with the AOT compiler requires
|
||
some setup specifically for AOT compilation.
|
||
Start with the application project as shown
|
||
[just before merging the translation file](guide/i18n#app-pre-translation)
|
||
and refer to the [AOT guide](guide/aot-compiler) to make it _AOT-ready_.
|
||
|
||
使用AoT编译器时的国际化,需要一些针对AoT的设置。
|
||
以[合并翻译文件之前](guide/i18n#app-pre-translation)的应用项目开始,并参见[AoT烹饪书](guide/aot-compiler),把它变成与AoT兼容的项目。
|
||
|
||
Next, issue an `ngc` compile command for each supported language, including English.
|
||
The result is a separate version of the application for each language.
|
||
|
||
接下来,为每种支持的语言(包括英语)运行一次`ngc`编译命令。
|
||
结果是每种语言都有自己单独的应用版本。
|
||
|
||
Tell AOT how to translate by adding three options to the `ngc` command:
|
||
|
||
通过添加下面三种选项到`ngc`命令来告诉AoT编译器如何翻译:
|
||
|
||
* `--i18nFile`: the path to the translation file.
|
||
|
||
`--i18nFile`: 翻译文件的路径
|
||
|
||
* `--locale`: the name of the locale.
|
||
|
||
`--locale`: 语言环境的名字
|
||
|
||
* `--i18nFormat`: the format of the localization file.
|
||
|
||
`--i18nFormat`: 翻译文件的格式
|
||
|
||
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>
|
||
|
||
<div class="l-sub-section">
|
||
|
||
Windows users may have to quote the command:
|
||
|
||
Windows用户可能需要双引号这个命令:
|
||
|
||
<code-example language="sh" class="code-shell">
|
||
"./node_modules/.bin/ngc" --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf
|
||
</code-example>
|
||
|
||
</div>
|
||
|
||
### Report missing translations
|
||
|
||
If you forgot to provide a translation, the build will succeed with a warning that you might easily overlook.
|
||
You can configure the Angular compiler for different "missing translation" behaviors:
|
||
|
||
* Error
|
||
* Warning (default)
|
||
* Ignore
|
||
|
||
To change the behavior in JIT, you can use the following configuration:
|
||
|
||
<code-example language="typescript">
|
||
{ provide: CompilerConfig, useValue: new CompilerConfig({ missingTranslation: MissingTranslationStrategy.Error }) }
|
||
</code-example>
|
||
|
||
A good place to use it is the translation providers:
|
||
|
||
<code-example path="i18n/src/app/i18n-providers.ts" region="missing-translation" title="src/app/i18n-providers.ts"></code-example>
|
||
|
||
To change the behavior in AOT, add the `--missingTranslation` flag to the compilation command:
|
||
|
||
<code-example language="sh" class="code-shell">
|
||
./node_modules/.bin/ngc --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf --missingTranslation=error
|
||
</code-example>
|
||
|
||
{@a maintenance}
|
||
|
||
## 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 the `id` _can be a serious problem!_
|
||
|
||
If the `id` is generated by the tool, _most_ changes to _existing_ markup
|
||
cause the tool to generate a _new_ `id` for the affected translation unit.
|
||
|
||
After an `id` changes, the translation files are no longer in sync.
|
||
Because of that, you get some warning messages during re-compilation.
|
||
The warning messages identify that some translations are missing, but they don't tell you which
|
||
old `ids` are no longer valid.
|
||
|
||
If you use a [custom id](#custom-id "Set a custom id"),
|
||
the tooling preserves the custom `id` as you make changes to the corresponding translation unit. **Use custom _ids_ unless you have a very good reason to do otherwise.**
|
||
|
||
Whether you use generated or custom `ids`, **always 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
|
||
will help you find and update `ids` and other changes across your translation files.
|
||
|