# Internationalization (i18n)
# 国际化(i18n)
Angular's _internationalization_ (_i18n_) tools help make your app available in multiple languages.
Angular的*国际化*(*i18n*)工具可以帮助我们使用多个语言发布应用。
Try this live example
of a JIT-compiled app, translated into Spanish.
**试试** 这个翻译为西班牙语版JiT编译应用的在线例子。
{@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_工具,它们可以帮你把组件模板文本翻译成多种语言。
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_".
**国际化**工作者通常将一个可翻译的文本叫作“信息”。
本章使用了“文本”和“信息”,它们可以互换,也可以组合“文本信息”。
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`属性是可翻译内容的标记。
将它放到每个固定文本需要翻译的元素标签中。
`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工具和编译器认识它。
它将在完成翻译**之后**,被编译器移除。
In the accompanying sample, an `
` tag displays a simple English language greeting
that you translate into Spanish:
在例子中,`
`标签显示了一句简单的英文问候语,它将被翻译为西班牙语:
Add the `i18n` attribute to the tag to mark it for translation.
添加`i18n`属性到该标签上,把它标记为需要翻译的文本。
{@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属性添加描述:
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 (`|`):
在描述的前面,我们为指定的字符串添加一些上下文含义,用`|`将其与描述文字隔开(`<意图>|<描述>`)。
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
### 设置一个自定义的`id`来提升可搜索性和可维护性
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:
Angular 的 `i18n` 提取工具会为模板中每个带有`i18n`属性的元素生成一个*翻译单元(translation unit)*条目,并保存到一个文件中。默认情况下,它为每个翻译单元指定一个唯一的`id`,就像这样:
This _id_ is obscure and difficult for humans to read or remember.
这个`id`对于人类来说太晦涩,难于阅读和记忆。
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).
更糟的是,当我们修改这段可翻译的文字时(比如修改一个拼写错误),提取工具会生成一个新的`id`。
我们就会丢失这段翻译成果,除非把它修改为新的`id`。那样维护起来就太复杂了。
Consider specifying your own, meaningful _id_ in the `i18n` attribute, **prefixed with `@@`**.
要想自己为`i18n`属性指定一个有意义的`id`,可以给它**添加`@@`前缀**。
Now the extractor tool and compiler will generate a translation unit with _your custom id_ and never change it.
现在,提取工具和编译器就会用*你的自定义id`生成一个翻译单元,而不会再改变它。
Here is the `i18n` attribute with a _definition_, followed by the custom `id`:
下面这个例子中的`i18n`属性中有一个*定义*,然后跟着自定义`id`:
Here is a _meaning_ and a _description_ and the _id_ at the end:
下面这个例子带有*含义*和*描述*,最后是`id`:
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.
为了确保定义出*唯一*的自定义id。如果我们对两个*不同的*文本块使用了同一个id,那么就只有一个会被提取出来,然后其翻译结果会被用于全部文本块。
For example:
比如:
```html
Hello
Good bye
```
with the translation:
带有翻译结果的:
```xml
Hola
```
Both `
` elements will contain the text `Hola`.
两个`
`元素都会包含文本`Hola`。
{@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 `` tag but for some reason (CSS comes to mind)
you don't want to create a new DOM element merely to facilitate translation.
假设有一段文字要翻译。
我们可以把它包装进``标签中,但是因为某些原因(比如出于CSS方面的考虑),你可能不想仅仅为了翻译而创建一个新的DOM元素。
Here are two techniques to try.
可以尝试两种技术来解决这个问题。
(1) Wrap the text in an `` element. The `` is never rendered:
(1) 把文本包装进一个``元素中。而``永远不会被渲染出来:
(2) Wrap the text in a pair of HTML comments:
(2) 把文本包装进一对 HTML 注释中:
{@a translate-attributes}
## Add _i18n_ translation attributes
## 添加 *i18n* 翻译属性
You've added an image to your template. You care about accessibility too so you add a `title` attribute:
我们已经把一个图片添加到了模板中。我们也关心可访问性,故此也添加了一个`title`属性:
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.
这个 `title` 属性也需要翻译。
Angular i18n 支持更多形如`i18n-x`的属性,其中的`x`就是要翻译的属性名。
To translate the `title` on the `img` tag from the previous example, write:
为了翻译前面例子中`img`标签上的`title`属性,就要这样写:
You can also assign a meaning and a description with the `i18n-x="|"` syntax.
我们也同样可以使用`i18n-x="|"`语法来指定一个含义和描述。
{@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.
假设应用中需要谈论一些狼。
在英语中,根据狼的数量,可能要显示为"no wolves"、"one wolf"、"two wolves"或"a wolf pack"。
而在其它语言中则可能会有不同的**基数**规则。
Here's how you could mark up the component template to display the phrase appropriate to the number of wolves:
下面我们示范要如何书写组件模板来显示适当的短语来表示狼的数量:
* The first parameter is the key. It is bound to the component property (`wolves`) that determines the number of wolves.
第一个参数是key。它绑定到了组件中表示狼的数量的`wolves`属性。
* The second parameter identifies this as a `plural` translation type.
第二个参数表示这是一个`plural`(复数)翻译类型。
* The third parameter defines a pluralization pattern consisting of pluralization
categories and their matching values.
第三个参数定义了一组复数表示模式,这个模式由复数类别和它们所匹配的值组成。
Pluralization categories include:
复数类别包括:
* =0 (or any other number)
=0 (或其它数字)
* zero
zero(零)
* one
one(一个)
* two
two(两个)
* few
few(少数)
* many
many(很多)
* other
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}`.
如果要说一只狼,就写`=1 {one wolf}`。
* For zero wolves, you could write `=0 {no wolves}`.
如果要说零只狼,就写`=0 {no wolves}`。
* For two wolves, you could write `=2 {two wolves}`.
如果要说两只狼,就写`=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}`.
三只、四只或其它数量的狼也都以此类推。
或者,我们也可以指定**`other`**类来捕获所有未匹配上的数量,写法为:`other {a wolf pack}`。
{@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
ICU message syntax.
You choose among alternative translation based on a string value instead of a number.
我们可以使用`select`翻译器来处理它。
`select`也同样遵循 ICU 消息语法。我们在候选文本之间选择,但根据的是一个字符串值而不再是数字。
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:
组件模板中的下列消息格式绑定到了组件的`gender`属性,这个属性的取值是"m"或"f"。
这个消息会把那些值映射到适当的翻译文本:
## Nesting pluralization and selection expressions
## 把"复数"与"选择"表达式嵌套在一起
You can also nest different ICU expressions together. For example:
我们也可以把不同的 ICU 表达式嵌套在一起,比如:
{@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`,安装它们:
npm install @angular/compiler-cli @angular/platform-server --save
Open a terminal window at the root of the application project and enter the `ng-xi18n` command:
在应用的项目根目录打开一个终端窗口,并输入`ng-xi18n`命令:
./node_modules/.bin/ng-xi18n
Windows users may have to quote the command like this: `"./node_modules/.bin/ng-xi18n"`
By default, the tool generates a translation file named **`messages.xlf`** in the
XML Localization Interchange File Format (XLIFF, version 1.2).
工具默认生成一个名为**`messages.xlf`**的翻译文件,格式为XML本土化互换文件格式(XLIFF, version 1.2)。
{@a other-formats}
### Other translation formats
### 其它翻译格式
Angular i18n tooling supports XLIFF 1.2 and XLIFF 2 as well as the
XML Message Bundle (XMB).
除了XML消息捆(XMB)格式外,Angular的i18n工具也同样支持 XLIFF 1.2和XLIFF 2 格式。
You can specify your choice of format _explicitly_ with the `--i18nFormat` flag as illustrated in these example commands
我们可以使用`--i18nFormat`来明确指定想用的格式,范例如下:
./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
The sample in _this_ guide sticks with the default _XLIFF 1.2_ format.
本章的范例默认使用 _XLIFF 1.2_ 格式。
{@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:
我们还可能需要指定其它选项。
比如,如果TypeScript的配置文件`tsconfig.json`位于其它地方而不是根目录,我们就要通过`-p`选项来明确指出它的路径。
./node_modules/.bin/ng-xi18n -p path/to/tsconfig.json
./node_modules/.bin/ng-xi18n --i18nFormat=xmb -p path/to/tsconfig.json
{@a npm-i18n-script}
### Add an _npm_ script for convenience
### 添加`npm`便利脚本
Consider adding a convenience shortcut to the `scripts` section of the `package.json`
to make the command easier to remember and run:
考虑在`package.json`的`scripts`区中添加一个便利脚本,来让命令更容易记忆和运行:
"scripts": {
"i18n": "ng-xi18n",
...
}
Now you can issue command variations such as these:
现在,我们就可以使用这些命令的变体形式了,比如:
npm run i18n
npm run i18n -- -p path/to/tsconfig.json
npm run i18n -- --i18nFormat=xmb -p path/to/tsconfig.json
Note the `--` flag before the options.
It tells _npm_ to pass every flag thereafter to `ng-xi18n`.
注意选项前面的`--`标识。它告诉`npm`要把这个参数后面的每一个标识都透传给`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.
其中一种方法是为本土化和相关资源(比如国际化文件)创建一个专门的目录。
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
well-known codeset.
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
many XLIFF file editors.
在现实世界中,`messages.es.xlf`文件会被发给西班牙语翻译,他们使用这些XLIFF文件编辑器中的一种来翻译它。
This sample file is easy to translate without a special editor or knowledge of Spanish.
Open `messages.es.xlf` and find the first `` section:
我们不需要任何编辑器或者西班牙语知识就可以轻易的翻译本例子文件。
打开`messages.es.xlf`并找到``节点:
This XML element represents the translation of the `
` greeting tag you marked with the `i18n` attribute.
这个XML元素代表了你使用`i18n`属性标记的`
`问候语标签的翻译。
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.
注意,翻译单元`id=introductionHeader`派生自[*自定义*`id`](#custom-id "设置自定义id"),它设置起来更简单,但是在HTML源码中**不需要`@@`前缀**。
Using the _source_, _description_, and _meaning_ elements to guide your translation,
replace the `` tag with the Spanish greeting:
翻译中利用_source_、_description_和_meaning_元素的信息,替换``标签为西班牙语问候语:
Translate the other text nodes the same way:
**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)**.
参见**[关于如何维护翻译结果文件的讨论](#maintenance)**。
This is why you should **[specify custom ids](#custom-id "Set a custom id")** and avoid tool generated ids.
这就是为什么我们应该**[指定自定义 id](#custom-id "Set a custom id")**,避免让工具自动生成id。
{@a translate-plural-select}
## Translate _plural_ and _select_
## 翻译*复数(plural)*和*选择(select)*
Translating _plural_ and _select_ messages is a little tricky.
翻译*复数*和*选择*类的消息有点棘手。
The `