填写这份《一分钟调查》,帮我们(开发组)做得更好!去填写Home

国际化(i18n)

Internationalization (i18n)

应用程序的国际化涉及到开发的很多方面,主要是如何让应用可以被全世界的用户使用而且用起来比较友好。 本页面讲的是 Angular 的国际化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.

可以把这个翻译为法语版的 AOT 应用i18n 例子i18n 例子作为一个简单的例子。

See thei18n Examplei18n Examplefor a simple example of an AOT-compiled app, translated into French.

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 简化了国际化工作的下列几个方面:

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.

为了进行本地化,你可以使用 Angular CLI 来生成大部分必要的代码,用与创建要发给翻译人员的文件以及把应用发布成多种语言。 如果要为你的应用添加 i18n 支持,CLI 会在下列步骤中给你提供帮助:

For localization, you can use the Angular 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.

使用 Angular CLI 进行本地化

Setting up localization with the Angular CLI

使用 Angular CLI 进行本地化的第一步是将 @angular/localize 包添加到项目中。这将在您的项目中安装这个包,并初始化项目以使用 Angular 的本地化功能。

The first step to setting up localization when using the Angular CLI is to add the @angular/localize package to the project. This will install the package within your project as well as initialize the project to take advantage of Angular's localization features.

ng add @angular/localize
      
      ng add @angular/localize
    

为你的应用设置语言环境(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".

Unicode 的语言环境标识是由 Unicode 语言标识、一个可选的 - 字符,后跟一个语言环境扩展项组合而成的。(由于历史的原因,还支持用 _ 作为 - 的替代品。)比如,语言环境标识 fr-CA 中的 fr 代表法语的语言标识,而 CA 代表的是加拿大的语言扩展。

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.

Angular 遵循 Unicode 的 LDML 惯例,它使用基于 BCP47 标准的稳定标识(Unicode 的语言环境标识)。当你要定义自己的语言环境时,遵循这个惯例非常重要,因为 Angular 的 i18n 工具会使用这种语言环境标识来查找相应的本地化数据。

Angular follows the Unicode LDML convention that uses stable identifiers (Unicode locale identifiers) based on the norm BCP47. 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.

默认情况下,Angular 使用的语言环境标识是 en-US,它表示美国英语。

By default, Angular uses the locale en-US, which is English as spoken in the United States of America.

要了解关于 Unicode 语言环境标识的更多信息,参见 CLDR 核心规范

For more information about Unicode locale identifiers, see the CLDR core spec.

要查看 Angular 支持的语言环境总表,参见 Angular 源码仓库

For a complete list of locales supported by Angular, see the Angular repository.

CLDR 和 Angular 使用的语言环境标识基于 BCP47。 这些规范可能会随时间而变化,下表中是本文编写时语言环境标识的新旧版本对照表:

The locale identifiers used by CLDR and Angular are based on BCP47. These specifications change over time; the following table maps previous identifiers to current ones at time of writing:

语言环境名称

Locale name

旧 ID

Old locale id

新 ID

New locale id

印度尼西亚

Indonesian

inid

希伯来

Hebrew

iwhe

罗马尼亚摩尔多瓦

Romanian Moldova

moro-MD

挪威 Bokmål

Norwegian Bokmål

no, no-NOnb

塞尔维亚拉丁语

Serbian Latin

shsr-Latn

菲律宾

Filipino

tlfil

葡萄牙巴西

Portuguese Brazil

pt-BRpt

中文简体

Chinese Simplified

zh-cn, zh-Hans-CNzh-Hans

中文繁体

Chinese Traditional

zh-tw, zh-Hant-TWzh-Hant

中文繁体(香港)

Chinese Traditional Hong Kong

zh-hkzh-Hant-HK

i18n 管道

i18n pipes

Angular 的管道可以帮助你进行国际化:DatePipeCurrencyPipeDecimalPipePercentPipe 都使用 LOCALE_ID 这个注入令牌关联的本地化数据来进行格式化。

Angular pipes can help you with internationalization: the DatePipe, CurrencyPipe, DecimalPipe and PercentPipe use locale data to format data based on the LOCALE_ID dependency injection token.

默认情况下,Angular 只包含 en-US 的本地化数据。 当你使用 ng serveng build--i18nLocale 参数或构建器选项 i18nLocale 时,CLI 会自动帮你包含进相应的本地化数据。 不过,如果你手动把 LOCALE_ID 的值设置为其它语言环境,你就必须为那个新的语言环境导入本地化数据。

By default, Angular only contains locale data for en-US. The CLI automatically includes the locale data and sets the LOCALE_ID value for you when you use the parameter --i18nLocale or option i18nLocale with ng serve and ng build. However, if you manually set the value of LOCALE_ID to another locale, you must import locale data for that new locale.

如果还要为其它语言导入本地化数据,你可以手工完成它:

If you want to import locale data for other languages, you can do it manually:

import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; // the second parameter 'fr-FR' is optional registerLocaleData(localeFr, 'fr-FR');
src/app/app.module.ts
      
      import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';

// the second parameter 'fr-FR' is optional
registerLocaleData(localeFr, 'fr-FR');
    

第一个参数是一个包含从 @angular/common/locales 中导入的本地化数据的对象。 默认情况下,导入 Angular 自带的本地化数据时会使用数据中自带的一个语言环境标识进行注册。 如果你要使用其它语言环境标识来注册这个导入的本地化数据,可以在第二个参数中指定一个自定义的语言环境标识。 比如,Angular 为法语定义的语言环境标识是 “fr”,你可以通过第二个参数为这些导入的法语本地化数据指定一个自定义的语言环境标识 “fr-FR”。

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".

@angular/common/locales 中的文件包含你需要的大多数本地化数据, 不过有些高级的格式选项只存在于从 @angular/common/locales/extra 中导入的扩展数据集中。遇到这种情况,你就会收到一条错误信息。

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. Ivy will automatically include the extra locale data if the locale was configured via i18nLocale.

import { registerLocaleData } from '@angular/common'; import localeFr from '@angular/common/locales/fr'; import localeFrExtra from '@angular/common/locales/extra/fr'; registerLocaleData(localeFr, 'fr-FR', localeFrExtra);
src/app/app.module.ts
      
      import { registerLocaleData } from '@angular/common';
import localeFr from '@angular/common/locales/fr';
import localeFrExtra from '@angular/common/locales/extra/fr';

registerLocaleData(localeFr, 'fr-FR', localeFrExtra);
    

Angular 中使用的所有本地化数据都是从 Unicode 联盟的常用本地化数据仓库 (CLDR) 中提取的。

All locale data used by Angular are extracted from the Unicode Consortium's Common Locale Data Repository (CLDR).

模板翻译

Template translations

本文档中会把翻译文本的最小单元称为“文本”、“消息”或“文本消息”。

This document refers to a unit of translatable text as "text," a "message", or a "text message."

i18n 模板的翻译过程分为四个阶段

The i18n template translation process has four phases:

  1. 在组件模板中标记需要翻译的静态文本信息。

    Mark static text messages in your component templates for translation.

  2. 创建翻译文件:使用 Angular CLI 的 xi18n 命令,把标记过的文本提取到一个符合行业标准的翻译源文件中。

    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. 将目标语言环境和语言翻译添加到应用程序的配置中。

    Add the target locale and language translation to the application's configuration.

  1. 将完成的翻译文件合并到应用程序中。为此,请使用 Angular CLI build 命令来编译应用程序,选择特定语言环境的配置或指定 --localize 选项 。该命令会将原始消息替换为翻译后的文本,并以目标语言生成该应用程序的新版本。

    Merge the completed translation file into the application. To do this, use the Angular CLI build command to compile the app, choosing a locale-specific configuration, or specifying the --localize option. The command replaces the original messages with translated text, and generates a new version of the app in the target language.

  • 当要为每个语言环境使用单独的配置时,您需要为每种支持的语言构建和部署单独的应用程序版本。

    When using individual configurations per locale, you need to build and deploy a separate version of the app for each supported language.

  • 当使用 --localize 选项时,CLI 将为每种受支持的语言自动构建单独的应用程序版本。通过消除对每种受支持语言执行完整的应用程序构建的要求,此选项可缩短构建过程。不过您仍然需要分别部署每种特定语言的版本。

    When using the --localize option, the CLI will automatically build a separate version of the application for each supported language. This option shortens the build process by removing the requirement to perform a full application build for each supported language. You still need to deploy each language-specific version separately.

使用 i18n 属性标记文本

Mark text with the i18n attribute

Angular的i18n属性是可翻译内容的标记。 将它放到每个固定文本需要翻译的元素标签中。

The Angular i18n attribute marks translatable content. Place it on every element tag whose fixed text is to be translated.

在下面的例子中,<h1>标签显示了一句简单的英文问候语,“Hello i18n!”

In the example below, an <h1> tag displays a simple English language greeting, "Hello i18n!"

<h1>Hello i18n!</h1>
src/app/app.component.html
      
      <h1>Hello i18n!</h1>
    

要想把它标记为需要翻译的文本,就给 <h1> 标签添加上 i18n 属性。

To mark the greeting for translation, add the i18n attribute to the <h1> tag.

<h1 i18n>Hello i18n!</h1>
src/app/app.component.html
      
      <h1 i18n>Hello i18n!</h1>
    

i18n 是一个自定义属性,会被 Angular 工具和编译器识别。 翻译之后,编译器就会移除它。它不是 Angular 指令。

i18n is a custom attribute, recognized by Angular tools and compilers. After translation, the compiler removes it. It is not an Angular directive.

用描述和意图来帮助翻译人员

Help the translator with a description and meaning

要想翻译的更准确,翻译人员可能需要待翻译文本的额外信息或上下文。

To translate a text message accurately, the translator may need additional information or context.

你可以用 i18n 属性的值来添加这些文本信息的描述,例子如下:

You can add a description of the text message as the value of the i18n attribute, as shown in the example below:

<h1 i18n="An introduction header for this sample">Hello i18n!</h1>
src/app/app.component.html
      
      <h1 i18n="An introduction header for this sample">Hello i18n!</h1>
    

为了给出正确的翻译,翻译者需要知道你这段文本在特定情境下的含义真实意图

The translator may also need to know the meaning or intent of the text message within this particular app context.

在描述的前面,你可以用 i18n 开头的属性值来为指定的字符串添加一些上下文含义,用 | 将其与描述文字隔开(<意图>|<描述>)。

You add context by beginning the i18n attribute value with the meaning and separating it from the description with the | character: <meaning>|<description>

<h1 i18n="site header|An introduction header for this sample">Hello i18n!</h1>
src/app/app.component.html
      
      <h1 i18n="site header|An introduction header for this sample">Hello i18n!</h1>
    

如果所有地方出现的文本具有相同含义时,它们应该有相同的翻译, 但是如果在某些地方它具有不同含义,那么它应该有不同的翻译。

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.

Angular 的提取工具会在翻译源文件中保留含义描述,以支持符合特定上下文的翻译。但它只会使用含义和文本消息的组合来为待翻译文本生成明确的 id。如果你有两个相同的文本消息,但是含义不同,它们就会被分别提取。如果你有两个相同的文本消息,但是描述不同(但含义相同),它们就只会提取一次。

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.

设置一个自定义的 id 来提升可搜索性和可维护性

Set a custom id for persistence and maintenance

Angular 的 i18n 提取工具会为模板中每个带有 i18n 属性的元素生成一个翻译单元(translation unit)条目,并保存到一个文件中。默认情况下,它为每个翻译单元指定一个唯一的 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:

<trans-unit id="ba0cc104d3d69bf669f97b8d96a4c5d8d9559aa3" datatype="html">
messages.fr.xlf.html
      
      <trans-unit id="ba0cc104d3d69bf669f97b8d96a4c5d8d9559aa3" datatype="html">
    

当你修改这段可翻译的文字时,提取工具会为那个翻译单元生成一个新的 id。 你就要使用这个新的 id 来修改这个翻译文件。

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.

另一种方案是,你可以使用 @@ 前缀在 i18n 属性中指定一个自定义的 id。 下面这个例子就定义了一个自定义 id introductionHeader

Alternatively, you can specify a custom id in the i18n attribute by using the prefix @@. The example below defines the custom id introductionHeader:

<h1 i18n="@@introductionHeader">Hello i18n!</h1>
app/app.component.html
      
      <h1 i18n="@@introductionHeader">Hello i18n!</h1>
    

一旦你指定了自定义 id,提取工具和编译器就会用*你的自定义 id` 生成一个翻译单元,而不会再改变它。

When you specify a custom id, the extractor tool and compiler generate a translation unit with that custom id.

<trans-unit id="introductionHeader" datatype="html">
messages.fr.xlf.html
      
      <trans-unit id="introductionHeader" datatype="html">
    

自定义 id 是永久性的,翻译工具待翻译文本发生变化时不会修改它。 因此,你不必修改翻译结果。这种方式可以让维护变得更简单。

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.

在描述中使用自定义 id

Use a custom id with a description

你可以在 i18n 属性的值中使用自定义 id 与描述信息的组合。 下面的例子中,i18n 的属性中中就包含了一条跟在自定义 id 后面的描述信息:

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:

<h1 i18n="An introduction header for this sample@@introductionHeader">Hello i18n!</h1>
app/app.component.html
      
      <h1 i18n="An introduction header for this sample@@introductionHeader">Hello i18n!</h1>
    

你还可以添加含义,例子如下:

You also can add a meaning, as shown in this example:

<h1 i18n="site header|An introduction header for this sample@@introductionHeader">Hello i18n!</h1>
app/app.component.html
      
      <h1 i18n="site header|An introduction header for this sample@@introductionHeader">Hello i18n!</h1>
    

定义唯一的自定义 ID

Define unique custom ids

要确保自定义 id 是唯一的。如果你对两个不同的文本块使用了同一个 id,那么就只有一个会被提取出来,然后其翻译结果会被用于全部原始文本消息。

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.

在下面这个例子中,自定义的 id myId 就被用在了两个不同的消息上:

In the example below the custom id myId is used for two different messages:

<h3 i18n="@@myId">Hello</h3> <!-- ... --> <p i18n="@@myId">Good bye</p>
      
      <h3 i18n="@@myId">Hello</h3>

<!-- ... -->

<p i18n="@@myId">Good bye</p>
    

考虑下列法文翻译:

Consider this translation to French:

<trans-unit id="myId" datatype="html"> <source>Hello</source> <target state="new">Bonjour</target> </trans-unit>
      
      <trans-unit id="myId" datatype="html">
  <source>Hello</source>
  <target state="new">Bonjour</target>
</trans-unit>
    

由于自定义 id 都是一样的,所以翻译结果中所有的元素都包含同样的文本 Bonjour

Because the custom id is the same, both of the elements in the resulting translation contain the same text, Bonjour:

<h3>Bonjour</h3> <!-- ... --> <p>Bonjour</p>
      
      <h3>Bonjour</h3>

<!-- ... -->

<p>Bonjour</p>
    

翻译文本,而不必创建元素

Translate text without creating an element

如果要翻译一段纯文本,你就可以把它用 <span> 标签包裹起来。 但如果由于某些原因(比如 CSS 结构方面的考虑),你可能不希望仅仅为了翻译而创建一个新的 DOM 元素,那么也可以把这段文本包裹进一个 <ng-container> 元素中。<ng-container> 将被转换成一个 HTML 注释:

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:

<ng-container i18n>I don't output any element</ng-container>
src/app/app.component.html
      
      <ng-container i18n>I don't output any element</ng-container>
    

翻译属性

Translate attributes

要显示的文本有时候会以属性值的形式提供,而不是标签的内容。 比如,假如你的模板中有一个带 title 属性的图片,这个 title 属性的文本值就要翻译。

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.

<img [src]="logo" title="Angular logo">
src/app/app.component.html
      
      <img [src]="logo" title="Angular logo">
    

要把一个属性标记为需要翻译的,就添加一个形如 i18n-x 的属性,其中的 x 是要翻译的属性的名字。 下面的例子中演示了如何通过给 img 标签添加 i18n-title 属性来把 title 属性标记为待翻译的。

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:

<img [src]="logo" i18n-title title="Angular logo" />
src/app/app.component.html
      
      <img [src]="logo" i18n-title title="Angular logo" />
    

这个技巧适用于任何元素上的任何属性。

This technique works for any attribute of any element.

你还可以通过 i18n-x="<meaning>|<description>@@<id>" 语法来给它写上含义(meaning)、描述(description)和 id。

You also can assign a meaning, description, and id with the i18n-x="<meaning>|<description>@@<id>" syntax.

复数与选择的表达式

Regular expressions for plurals and selections

不同的语言具有不同的复数规则和语法结构,这为翻译工作平添了很多复杂性。 你可以使用带有 pluralselect 的正则表达式来提供一些模式,来辅助翻译这些情况。

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.

复数规则

Pluralization

假设你要说某些东西“updated x minutes ago(在 x 分钟前修改了)”。 在英语中,根据分钟数,可能要显示为 "just now"、"one minute ago" 或 "x minutes ago"(这里的 x 是实际的数量)。 而在其它语言中则可能会有不同的基数规则。

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.

下面这个例子示范了如何使用 ICU 表达式 plural 来根据这次修改发生的时间显示这三个选项之一:

The example below shows how to use a plural ICU expression to display one of those three options based on when the update occurred:

<span i18n>Updated {minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago}}</span>
src/app/app.component.html
      
      <span i18n>Updated {minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago}}</span>
    
  • 第一个参数是 key。它绑定到了组件中表示分钟数的 minutes 属性。

    The first parameter is the key. It is bound to the component property (minutes), which determines the number of minutes.

  • 第二个参数表示这是一个 plural(复数)翻译类型。

    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.

这种语法遵守 CLDR 复数规则 中指定的 ICU 消息格式

This syntax conforms to the ICU Message Format as specified in the CLDR pluralization rules.

复数类别包括(取决于语言):

Pluralization categories include (depending on the language):

  • =0 (或其它数字)

    =0 (or any other number)

  • zero(零)

    zero

  • one(一个)

    one

  • two(两个)

    two

  • few(少数)

    few

  • many(很多)

    many

  • other(其它)

    other

复数类别之后的括号({})中是默认的英语文本。

After the pluralization category, put the default English text in braces ({}).

在上面的例子中,这三个选项都是根据复数模式来指定的。要说零分钟,就用 =0 {just now}。一分钟就用 =1 {one minute}。 无法匹配的数量就用 other {{{minutes}} minutes ago}。如果复数规则与此不同,你还可以为两个、三个或任意数量添加更多的模式。对于这个 “minute” 的例子,英语中只要这三种模式就够了。

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.

你可以在翻译结果中使用插值和 HTML 标记。

You can use interpolations and html markup inside of your translations.

在候选文本中选择

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.

你可以使用 ICU 表达式 select 来翻译这些。它与 ICU 表达式 plural 类似,只是你要根据一个字符串值而不是数字来选择这些候选翻译文本,而这些字符串值是你自己定义的。

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.

组件模板中的下列消息格式绑定到了组件的 gender 属性,这个属性的取值是 "male"、"female" 或 "other"。 这个消息会把那些值映射到适当的翻译文本:

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:

<span i18n>The author is {gender, select, male {male} female {female} other {other}}</span>
src/app/app.component.html
      
      <span i18n>The author is {gender, select, male {male} female {female} other {other}}</span>
    

把"复数"与"选择"表达式嵌套在一起

Nesting plural and select ICU expressions

你也可以把不同的 ICU 表达式嵌套在一起,比如:

You can also nest different ICU expressions together, as shown in this example:

<span i18n>Updated: {minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago by {gender, select, male {male} female {female} other {other}}}} </span>
src/app/app.component.html
      
      <span i18n>Updated: {minutes, plural,
  =0 {just now}
  =1 {one minute ago}
  other {{{minutes}} minutes ago by {gender, select, male {male} female {female} other {other}}}}
</span>
    

创建翻译源文件

Create a translation source file

当你的应用就绪之后,你可以使用 Angular CLI 来提取出带有 i18n 标记和带有 i18n-x 属性的文本信息,并存入一个翻译源文件。 在应用的项目根目录打开一个终端窗口,并运行 CLI 的 xi18n 命令。

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.

ng xi18n
      
      ng xi18n
    

默认情况下,该命令会在项目的根目录下创建一个名叫 messages.xlf 的文件。

By default, the command creates a file named messages.xlf in your project's root directory.

输出选项

Output options

你可以提供一些命令选项来改变所提取的文件的格式、名字、位置以及源语言区域。 比如,在 src/locale 目录下创建一个文件,可以指定输出路径(output path):

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:

ng xi18n --output-path src/locale
      
      ng xi18n --output-path src/locale
    

默认情况下,xi18n 命令会以 XML 翻译交换文件格式(XLIFF, 1.2 版) 生成一个名叫 messages.xlf 的翻译文件。

By default, the xi18n command generates a translation file named messages.xlf in the XML Localization Interchange File Format (XLIFF, version 1.2).

该命令可以用三种翻译格式之一读写文件:

The command can read and write files in three translation formats:

你可以使用 --format 选项明确指定想用的格式,范例如下:

You can specify the translation format explicitly with the --format command option, as illustrated in these example commands:

ng xi18n --format=xlf ng xi18n --format=xlf2 ng xi18n --format=xmb
      
      ng xi18n  --format=xlf
ng xi18n  --format=xlf2
ng xi18n  --format=xmb
    

本章的范例使用默认的 XLIFF 1.2 格式。

The sample in this guide uses the default XLIFF 1.2 format.

XLIFF 文件带有 .xlf 扩展名。XMB 格式会生成 .xmb 格式的源文件,但使用 .xtb(XML 翻译包)格式的翻译文件。

XLIFF files have the extension .xlf. The XMB format generates .xmb source files but uses .xtb (XML Translation Bundle: XTB) translation files.

你还可以使用 --out-file 选项来为提取工具生成的翻译源文件改名:

You can change the name of the translation source file that is generated by the extraction tool with the --outFile command option:

ng xi18n --out-file source.xlf
      
      ng xi18n --out-file source.xlf
    

你还可以使用 --i18n-locale 选项来指定应用的基本语言环境:

You can specify the base locale of your app with the--i18n-locale command option:

ng xi18n --i18n-locale fr
      
      ng xi18n --i18n-locale fr
    

该提取工具会用这个语言环境标识把本地化信息添加到你的翻译源文件中。这个信息对 Angular 来说没用,不过外部翻译工具可能会需要它。

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.

翻译源文本

Translate the source text

默认情况下,ng xi18n 命令会在项目的 src 目录下生成一个名为 messages.xlf 的翻译源文件。 下一步是将要显示的字符串翻译到指定语言的翻译文件。 这个例子中创建了一个法语翻译文件。

By default, 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.

新建一个本土化目录

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.

本土化和国际化是不同但是很相近的概念

Localization and internationalization are different but closely related terms.

本指南遵循了这种方式。在src/目录下,有一个专门的locale目录,该目录中的文件都带一个与相关语言环境匹配的扩展名。

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. 复制一份 messages.xlf 文件。

    Make a copy of the messages.xlf file.

  2. 把这个副本放进 locale 目录下。

    Put the copy in the locale folder.

  3. 把这个副本改名为 messages.fr.xlf 以作为法语翻译结果。

    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.

翻译文本节点

Translate text nodes

在现实世界中,messages.fr.xlf 文件会被发给法语翻译,他们会使用某种 XLIFF 文件编辑器来翻译它。

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. 打开 messages.fr.xlf 并找到第一个 <trans-unit> 区:

    Open messages.fr.xlf and find the first <trans-unit> section:

<trans-unit id="introductionHeader" datatype="html"> <source>Hello i18n!</source> <note priority="1" from="description">An introduction header for this sample</note> <note priority="1" from="meaning">User welcome</note> </trans-unit>
src/locale/messages.fr.xlf (trans-unit)
      
      <trans-unit id="introductionHeader" datatype="html">
  <source>Hello i18n!</source>
  <note priority="1" from="description">An introduction header for this sample</note>
  <note priority="1" from="meaning">User welcome</note>
</trans-unit>
    

这个 XML 元素表示前面你加过 i18n 属性的那个打招呼用的 <h1> 标签。

This XML element represents the translation of the <h1> greeting tag that you marked with the i18n attribute earlier in this guide.

注意这个 id=introductionHeader 的翻译单元是来自你以前设置过的自定义 id的。但是并没有源 HTML 所需的 @@ 前缀。

Note that the translation unit id=introductionHeader is derived from the custom idthat you set earlier, but without the @@ prefix required in the source HTML.

  1. 复制 <source/> 标记,把它改名为 target,并把它的内容改为法语版的 “greeting”。 如果你要做的是更复杂的翻译,可能会使用由源文本、描述信息和含义等提供的信息和上下文来给出更恰当的法语翻译。

    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.

<trans-unit id="introductionHeader" datatype="html"> <source>Hello i18n!</source> <target>Bonjour i18n !</target> <note priority="1" from="description">An introduction header for this sample</note> <note priority="1" from="meaning">User welcome</note> </trans-unit>
src/locale/messages.fr.xlf (trans-unit, after translation)
      
      <trans-unit id="introductionHeader" datatype="html">
  <source>Hello i18n!</source>
  <target>Bonjour i18n !</target>
  <note priority="1" from="description">An introduction header for this sample</note>
  <note priority="1" from="meaning">User welcome</note>
</trans-unit>
    
  1. 用同样的方式翻译其它文本节点:

    Translate the other text nodes the same way:

<trans-unit id="ba0cc104d3d69bf669f97b8d96a4c5d8d9559aa3" datatype="html"> <source>I don&apos;t output any element</source> <target>Je n'affiche aucun élément</target> </trans-unit> <trans-unit id="701174153757adf13e7c24a248c8a873ac9f5193" datatype="html"> <source>Angular logo</source> <target>Logo d'Angular</target> </trans-unit>
src/locale/messages.fr.xlf (trans-unit)
      
      <trans-unit id="ba0cc104d3d69bf669f97b8d96a4c5d8d9559aa3" datatype="html">
  <source>I don&apos;t output any element</source>
  <target>Je n'affiche aucun élément</target>
</trans-unit>
<trans-unit id="701174153757adf13e7c24a248c8a873ac9f5193" datatype="html">
  <source>Angular logo</source>
  <target>Logo d'Angular</target>
</trans-unit>
    

Angular 的 i18n 工具会为这些翻译单元生成一些 id,不要修改它们。 每个 id 都是根据模板文本的内容及其含义来生成的。 无论你修改了文本还是含义,它们的 id 都会改变。 要了解更多信息,参见 关于翻译文件可维护性的讨论

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.

翻译复数(plural)和选择(select)表达式

Translating plural and select expressions

复数选择的 ICU 表达式都是分别提取的,所以在准备翻译时,它们需要格外注意。

The plural and select ICU expressions are extracted separately, so they require special attention when preparing for translation.

你要从原始模板中其它地方识别出来的翻译单元来找到这些表达式之间的联系。 比如在这个例子中,你知道 select 一定会出现在 logo 的翻译单元的紧下方。

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.

翻译复数

Translate plural

要翻译一个复数,就要翻译它的 ICU 格式中匹配的值:

To translate a plural, translate its ICU format match values:

<trans-unit id="5a134dee893586d02bffc9611056b9cadf9abfad" datatype="html"> <source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes ago} }</source> <target>{VAR_PLURAL, plural, =0 {à l'instant} =1 {il y a une minute} other {il y a <x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes} }</target> </trans-unit>
src/locale/messages.fr.xlf (trans-unit)
      
      <trans-unit id="5a134dee893586d02bffc9611056b9cadf9abfad" datatype="html">
  <source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes ago} }</source>
  <target>{VAR_PLURAL, plural, =0 {à l'instant} =1 {il y a une minute} other {il y a <x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes} }</target>
</trans-unit>
    

你可以添加或删除复数的情况,每种语言都有自己的基数规则。(参见 CLDR 复数规则)。

You can add or remove plural cases, with each language having its own cardinality. (See CLDR plural rules.)

翻译选择(select)

Translate select

下面是组件模板中的 ICU 表达式 select 的例子:

Below is the content of our example select ICU expression in the component template:

<span i18n>The author is {gender, select, male {male} female {female} other {other}}</span>
src/app/app.component.html
      
      <span i18n>The author is {gender, select, male {male} female {female} other {other}}</span>
    

提取工具会把它拆成两个翻译单元,因为 ICU 表达式是分别提取的。

The extraction tool broke that into two translation units because ICU expressions are extracted separately.

第一个单元包含 select 之外的文本。 这里的 select 是一个占位符 <x id="ICU">,用来表示 select 中的消息。 翻译这段文本,如果需要就把占位符放在那里,但不要删除它。 如果删除了占位符,ICU 表达式就不会出现在翻译后的应用中。

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.

</trans-unit> <trans-unit id="f99f34ac9bd4606345071bd813858dec29f3b7d1" datatype="html"> <source>The author is <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></source> <target>L'auteur est <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></target> </trans-unit>
src/locale/messages.fr.xlf (trans-unit)
      
      </trans-unit>
<trans-unit id="f99f34ac9bd4606345071bd813858dec29f3b7d1" datatype="html">
  <source>The author is <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></source>
  <target>L'auteur est <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></target>
</trans-unit>
    

第一个翻译单元的紧下方就是第二个翻译单元,包含 select 中的消息。照样翻译它。

The second translation unit, immediately below the first one, contains the select message. Translate that as well.

<trans-unit id="eff74b75ab7364b6fa888f1cbfae901aaaf02295" datatype="html"> <source>{VAR_SELECT, select, male {male} female {female} other {other} }</source> <target>{VAR_SELECT, select, male {un homme} female {une femme} other {autre} }</target> </trans-unit>
src/locale/messages.fr.xlf (trans-unit)
      
      <trans-unit id="eff74b75ab7364b6fa888f1cbfae901aaaf02295" datatype="html">
  <source>{VAR_SELECT, select, male {male} female {female} other {other} }</source>
  <target>{VAR_SELECT, select, male {un homme} female {une femme} other {autre} }</target>
</trans-unit>
    

在翻译之后,它们会放在一起:

Here they are together, after translation:

</trans-unit> <trans-unit id="f99f34ac9bd4606345071bd813858dec29f3b7d1" datatype="html"> <source>The author is <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></source> <target>L'auteur est <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></target> </trans-unit> <trans-unit id="eff74b75ab7364b6fa888f1cbfae901aaaf02295" datatype="html"> <source>{VAR_SELECT, select, male {male} female {female} other {other} }</source> <target>{VAR_SELECT, select, male {un homme} female {une femme} other {autre} }</target> </trans-unit>
src/locale/messages.fr.xlf (trans-unit)
      
      </trans-unit>
<trans-unit id="f99f34ac9bd4606345071bd813858dec29f3b7d1" datatype="html">
  <source>The author is <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></source>
  <target>L'auteur est <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></target>
</trans-unit>
<trans-unit id="eff74b75ab7364b6fa888f1cbfae901aaaf02295" datatype="html">
  <source>{VAR_SELECT, select, male {male} female {female} other {other} }</source>
  <target>{VAR_SELECT, select, male {un homme} female {une femme} other {autre} }</target>
</trans-unit>
    

翻译嵌套的表达式

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:

<trans-unit id="972cb0cf3e442f7b1c00d7dab168ac08d6bdf20c" datatype="html"> <source>Updated: <x id="ICU" equiv-text="{minutes, plural, =0 {...} =1 {...} other {...}}"/></source> <target>Mis à jour: <x id="ICU" equiv-text="{minutes, plural, =0 {...} =1 {...} other {...}}"/></target> </trans-unit>
src/locale/messages.fr.xlf (trans-unit)
      
      <trans-unit id="972cb0cf3e442f7b1c00d7dab168ac08d6bdf20c" datatype="html">
  <source>Updated: <x id="ICU" equiv-text="{minutes, plural, =0 {...} =1 {...} other {...}}"/></source>
  <target>Mis à jour: <x id="ICU" equiv-text="{minutes, plural, =0 {...} =1 {...} other {...}}"/></target>
</trans-unit>
    

第二个包含完整的嵌套表达式:

The second unit contains the complete nested expression:

<trans-unit id="7151c2e67748b726f0864fc443861d45df21d706" datatype="html"> <source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes ago by {VAR_SELECT, select, male {male} female {female} other {other} }} }</source> <target>{VAR_PLURAL, plural, =0 {à l'instant} =1 {il y a une minute} other {il y a <x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes par {VAR_SELECT, select, male {un homme} female {une femme} other {autre} }} }</target> </trans-unit>
src/locale/messages.fr.xlf (trans-unit)
      
      <trans-unit id="7151c2e67748b726f0864fc443861d45df21d706" datatype="html">
  <source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes ago by {VAR_SELECT, select, male {male} female {female} other {other} }} }</source>
  <target>{VAR_PLURAL, plural, =0 {à l'instant} =1 {il y a une minute} other {il y a <x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes par {VAR_SELECT, select, male {un homme} female {une femme} other {autre} }} }</target>
</trans-unit>
    

放在一起时:

And both together:

<trans-unit id="972cb0cf3e442f7b1c00d7dab168ac08d6bdf20c" datatype="html"> <source>Updated: <x id="ICU" equiv-text="{minutes, plural, =0 {...} =1 {...} other {...}}"/></source> <target>Mis à jour: <x id="ICU" equiv-text="{minutes, plural, =0 {...} =1 {...} other {...}}"/></target> </trans-unit> <trans-unit id="7151c2e67748b726f0864fc443861d45df21d706" datatype="html"> <source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes ago by {VAR_SELECT, select, male {male} female {female} other {other} }} }</source> <target>{VAR_PLURAL, plural, =0 {à l'instant} =1 {il y a une minute} other {il y a <x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes par {VAR_SELECT, select, male {un homme} female {une femme} other {autre} }} }</target> </trans-unit>
src/locale/messages.fr.xlf (trans-unit)
      
      <trans-unit id="972cb0cf3e442f7b1c00d7dab168ac08d6bdf20c" datatype="html">
  <source>Updated: <x id="ICU" equiv-text="{minutes, plural, =0 {...} =1 {...} other {...}}"/></source>
  <target>Mis à jour: <x id="ICU" equiv-text="{minutes, plural, =0 {...} =1 {...} other {...}}"/></target>
</trans-unit>
<trans-unit id="7151c2e67748b726f0864fc443861d45df21d706" datatype="html">
  <source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes ago by {VAR_SELECT, select, male {male} female {female} other {other} }} }</source>
  <target>{VAR_PLURAL, plural, =0 {à l'instant} =1 {il y a une minute} other {il y a <x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes par {VAR_SELECT, select, male {un homme} female {une femme} other {autre} }} }</target>
</trans-unit>
    

整个模板的翻译就完成了。下一节会讲如何翻译结果加载到应用程序中。

The entire template translation is complete. The next section describes how to load that translation into the app.

应用及其翻译文件

The app and its translation file

下面是例子应用及其翻译文件:

The sample app and its translation file are now as follows:

<h1 i18n="User welcome|An introduction header for this sample@@introductionHeader"> Hello i18n! </h1> <ng-container i18n>I don't output any element</ng-container> <br /> <img [src]="logo" i18n-title title="Angular logo" /> <br> <button (click)="inc(1)">+</button> <button (click)="inc(-1)">-</button> <span i18n>Updated {minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago}}</span> ({{minutes}}) <br><br> <button (click)="male()">&#9794;</button> <button (click)="female()">&#9792;</button> <button (click)="other()">&#9895;</button> <span i18n>The author is {gender, select, male {male} female {female} other {other}}</span> <br><br> <span i18n>Updated: {minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago by {gender, select, male {male} female {female} other {other}}}} </span>import { Component } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html' }) export class AppComponent { minutes = 0; gender = 'female'; fly = true; logo = 'https://angular.io/assets/images/logos/angular/angular.png'; inc(i: number) { this.minutes = Math.min(5, Math.max(0, this.minutes + i)); } male() { this.gender = 'male'; } female() { this.gender = 'female'; } other() { this.gender = 'other'; } }import { NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent ], bootstrap: [ AppComponent ] }) export class AppModule { }import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; import { environment } from './environments/environment'; if (environment.production) { enableProdMode(); } platformBrowserDynamic().bootstrapModule(AppModule);<?xml version="1.0" encoding="UTF-8" ?> <xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2"> <file source-language="en" datatype="plaintext" original="ng2.template"> <body> <trans-unit id="introductionHeader" datatype="html"> <source>Hello i18n!</source> <note priority="1" from="description">An introduction header for this sample</note> <note priority="1" from="meaning">User welcome</note> </trans-unit> <trans-unit id="introductionHeader" datatype="html"> <source>Hello i18n!</source> <target>Bonjour i18n !</target> <note priority="1" from="description">An introduction header for this sample</note> <note priority="1" from="meaning">User welcome</note> </trans-unit> <trans-unit id="ba0cc104d3d69bf669f97b8d96a4c5d8d9559aa3" datatype="html"> <source>I don&apos;t output any element</source> <target>Je n'affiche aucun élément</target> </trans-unit> <trans-unit id="701174153757adf13e7c24a248c8a873ac9f5193" datatype="html"> <source>Angular logo</source> <target>Logo d'Angular</target> </trans-unit> <trans-unit id="5a134dee893586d02bffc9611056b9cadf9abfad" datatype="html"> <source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes ago} }</source> <target>{VAR_PLURAL, plural, =0 {à l'instant} =1 {il y a une minute} other {il y a <x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes} }</target> </trans-unit> </trans-unit> <trans-unit id="f99f34ac9bd4606345071bd813858dec29f3b7d1" datatype="html"> <source>The author is <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></source> <target>L'auteur est <x id="ICU" equiv-text="{gender, select, male {...} female {...} other {...}}"/></target> </trans-unit> <trans-unit id="eff74b75ab7364b6fa888f1cbfae901aaaf02295" datatype="html"> <source>{VAR_SELECT, select, male {male} female {female} other {other} }</source> <target>{VAR_SELECT, select, male {un homme} female {une femme} other {autre} }</target> </trans-unit> <trans-unit id="972cb0cf3e442f7b1c00d7dab168ac08d6bdf20c" datatype="html"> <source>Updated: <x id="ICU" equiv-text="{minutes, plural, =0 {...} =1 {...} other {...}}"/></source> <target>Mis à jour: <x id="ICU" equiv-text="{minutes, plural, =0 {...} =1 {...} other {...}}"/></target> </trans-unit> <trans-unit id="7151c2e67748b726f0864fc443861d45df21d706" datatype="html"> <source>{VAR_PLURAL, plural, =0 {just now} =1 {one minute ago} other {<x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes ago by {VAR_SELECT, select, male {male} female {female} other {other} }} }</source> <target>{VAR_PLURAL, plural, =0 {à l'instant} =1 {il y a une minute} other {il y a <x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes par {VAR_SELECT, select, male {un homme} female {une femme} other {autre} }} }</target> </trans-unit> </body> </file> </xliff>
      
      <h1 i18n="User welcome|An introduction header for this sample@@introductionHeader">
  Hello i18n!
</h1>

<ng-container i18n>I don't output any element</ng-container>

<br />

<img [src]="logo" i18n-title title="Angular logo" />
<br>
<button (click)="inc(1)">+</button> <button (click)="inc(-1)">-</button>
<span i18n>Updated {minutes, plural, =0 {just now} =1 {one minute ago} other {{{minutes}} minutes ago}}</span>
({{minutes}})
<br><br>
<button (click)="male()">&#9794;</button> <button (click)="female()">&#9792;</button> <button (click)="other()">&#9895;</button>
<span i18n>The author is {gender, select, male {male} female {female} other {other}}</span>
<br><br>
<span i18n>Updated: {minutes, plural,
  =0 {just now}
  =1 {one minute ago}
  other {{{minutes}} minutes ago by {gender, select, male {male} female {female} other {other}}}}
</span>
    

合并已经翻译的文件

Merge the completed translation file into the app

要把已经翻译的文件合并到组件模板,就要用翻译过的文件编译应用。 你需要为这些翻译文件提供所在路径、支持的语言环境或一组语言环境。你可以在命令行中提供这些,也可以在项目的 angular.json 文件中提供这些。

To merge the translated text into component templates, compile the app with the completed translation file. You will need to provide the path to the translation file, and the supported locale or locales for which you have provided translations. You can do this on the command line, or through a build configuration in the project's angular.json file.

无论翻译文件是 .xlf 还是 Angular 支持的其它格式(比如 .xtb),其编译过程都是一样的。

The compilation process is the same whether the translation file is in .xlf format or in another format that Angular understands, such as .xtb.

AOT 预先编译器是构建过程的一部分,它可以生成又小又快,直接可用的应用包,在 Angular 9 的 Ivy 中,AOT 被同时用于开发期构建和生产包构建中。

The AOT compiler is part of a build process that produces a small, fast, ready-to-run application package. With Ivy in Angular version 9, AOT is used by default for both development and production builds.

使用 JIT 模式时,Ivy 不支持合并 i18n 翻译。如果禁用 Ivy 并使用 JIT 模式,则可以在此处找到有关翻译合并的更多信息。

Ivy does not support merging i18n translations when using JIT mode. If you disable Ivy and are using JIT mode, additional information regarding translation merging can be found here.

当你使用 AOT 编译器进行国际化时,你必须为每种语言预先编译一个独立的应用包,并且依靠服务端语言检测或 URL 参数来找出合适的包。 CLI 可以配置成自动为每个已定义的语言环境构建出独立的语言环境专用版本。

When you internationalize with the AOT compiler, you must build a separate application package for each language and serve the appropriate package based on either server-side language detection or URL parameters. The CLI can be configured to automatically build separate locale-specific versions for each defined locale.

CLI 配置文件中的项目选项 i18n 用于定义项目的语言环境。子选项标识源语言,并告诉编译器在哪里可以找到项目支持的翻译。

The i18n project option in your CLI configuration file is used to define locales for a project. The sub-options identify the source language and tell the compiler where to find supported translations for the project.

  • sourceLocale —— 应用程序的源代码中使用的语言环境。默认为 en-US

    sourceLocale - The locale used within the source code for the application. Defaults to en-US.

  • locales —— 从语言环境标识符到翻译文件的映射表

    locales - A map of locale identifiers to translation files

"projects": { ... "angular.io-example": { ... "i18n": { "sourceLocale": "en-US", "locales": { "fr": "src/locale/messages.fr.xlf" } } ... "targets": { ... } } }
angular.json
      
      "projects": {
  ...
  "angular.io-example": {
    ...
    "i18n": {
      "sourceLocale": "en-US",
      "locales": {
        "fr": "src/locale/messages.fr.xlf"
      }
    }
    ...
    "targets": {
      ...
    }
  }
}
    

要指示 AOT 编译器使用您的翻译配置,请在 CLI 配置文件 angular.json 设置 localize 构建配置选项。该选项支持以下值:

To instruct the AOT compiler to use your translation configuration, set the localize build configuration option in your CLI configuration file, angular.json. The option supports the following values:

  • true —— 构建并生成所有已定义语言环境(包括源语言环境)的版本。

    true - Build and generate locale-specific versions for all defined locales including the source locale.

  • false ——(默认)禁用本地化并且不生成特定于语言环境的版本。

    false - (default) Disable localization and do not generate locale-specific versions.

  • 语言环境标识符数组 —— 构建,并为一个或多个指定语言环境生成专用版本。

    Array of locale identifiers - Build and generate locale-specific versions for one or more specified locales.

在使用 localize 选项时,CLI 将输出放置在特定语言环境的目录中,以便让它与应用程序的其它语言环境的版本分开。目录位于项目已配置的 outputPath 中。 CLI 还通过把语言环境添加到已配置的 baseHref 中来为应用程序的每个版本调整 HTML 的 base HREF。

When using the localize option, the CLI places the output in a locale-specific directory to keep it separate from other locale versions of your application. The directories are placed within the configured outputPath for the project. The CLI also adjusts the HTML base HREF for each version of the application by adding the locale to the configured baseHref.

您还可以在现有的 production 配置中为 ng build 命令提供 --localize 选项。在这个例子中,CLI 会在项目配置中构建 i18n 下定义的所有语言环境。

You can also provide the --localize option to the ng build command with your existing production configuration. In this case, the CLI builds all locales defined under i18n in the project configuration.

ng build --prod --localize
      
      ng build --prod --localize
    

要让特定的构建选项仅应用于一个语言环境,可以创建一个自定义的语言环境专用的配置。在这个例子中,localize 选项指定单个语言环境,如下所示。

To apply specific build options to only one locale, you can create a custom locale-specific configuration. In this case, the localize option specifies the single locale, as shown here.

"build": { ... "configurations": { ... "fr": { "localize": ["fr"], "main": "src/main.fr.ts", ... } } }, "serve": { ... "configurations": { ... "fr": { "browserTarget": "*project-name*:build:fr" } } }
angular.json
      
      "build": {
  ...
  "configurations": {
    ...
    "fr": {
      "localize": ["fr"],
      "main": "src/main.fr.ts",
      ...
    }
  }
},
"serve": {
  ...
  "configurations": {
    ...
    "fr": {
      "browserTarget": "*project-name*:build:fr"
    }
  }
}
    

然后,您可以将此配置传给 ng serveng build 命令。下面的例子演示了如何使用前面部分创建的法语文件来启动开发服务器:

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:

ng serve --configuration=fr
      
      ng serve --configuration=fr
    

CLI 开发服务器(ng serve)仅可用于单个语言环境。

The CLI development server (ng serve) can only be used with a single locale.

对于生产版本,可以使用配置组合来同时执行两个配置:

For production builds, you can use configuration composition to execute both configurations:

ng build --configuration=production,fr
      
      ng build --configuration=production,fr
    
... "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { ... }, "configurations": { "fr": { "localize": ["fr"], } } }, ... "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" } } } }
angular.json
      
      ...
"architect": {
  "build": {
    "builder": "@angular-devkit/build-angular:browser",
    "options": { ... },
    "configurations": {
      "fr": {
        "localize": ["fr"],
      }
    }
  },
  ...
  "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"
      }
    }
  }
}
    

汇报缺失的翻译

Report missing translations

默认情况下,如果缺少了某个翻译文件,构建工具会成功但给出警告(如Missing translation for message "foo")。你可以配置 Angular 编译器生成的警告级别:

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(错误):抛出错误,如果你使用的是 AOT 编译器,构建就会失败。如果使用的是 JIT 编译器,应用的加载就会失败。

    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(警告 - 默认):在控制台中显示一条 “Missing translation” 警告。

    Warning (default): show a 'Missing translation' warning in the console or shell.

  • Ignore(忽略):什么也不做。

    Ignore: do nothing.

你可以在 Angular CLI 配置文件 angular.jsonbuild 目标的 options 区指定警告级别。下面这个例子展示了如何把警告级别设置为 error

You specify the warning level in the options section for the build target of your Angular CLI configuration file, angular.json. The example below shows how to set the warning level to error.

"options": { ... "i18nMissingTranslation": "error" }
angular.json
      
      "options": {
  ...
  "i18nMissingTranslation": "error"
}
    

发布为多个语言环境

Deployment for multiple locales

要了解如何创建脚本来为不同的语言环境生成应用,以及如何配置 Apache 2 和 NGINX 来从不同的子目录下启动服务,请阅读 Philippe Martin 写的这篇教程

For more details about how to create scripts to generate an app in multiple languages and how to set up Apache 2 and NGINX to serve them from different subdirectories, read this tutorial by Philippe Martin.