Internationalization (i18n)

国际化(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.

应用程序的国际化涉及到开发的很多方面,主要是如何让应用可以被全世界的用户使用而且用起来比较友好。 本页面讲的是 Angular 的国际化i18n)工具,它可以帮助你使用多个语言发布应用。

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

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

Angular and i18n

Angular 与 i18n

Internationalization is the process of designing and preparing your app to be usable in different languages. Localization is the process of translating your internationalized app into specific languages for particular locales.

国际化是一个设计和准备应用程序的过程,使其能用于不同的语言。 本地化是一个把国际化的应用针对部分区域翻译成特定语言的过程。

Angular simplifies the following aspects of internationalization:

Angular 简化了国际化工作的下列几个方面:

  • Displaying dates, number, percentages, and currencies in a local format.

    用本地格式显示日期、数字、百分比以及货币。

  • Preparing text in component templates for translation.

    准备组件模板中待翻译的文本。

  • Handling plural forms of words.

    处理单词的复数形式。

  • Handling alternative text.

    处理候选文本。

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

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

  • 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 项目,Angular CLI 为它生成了写多语言应用时必须的大部分样板代码。

Setting up the locale of your app

为你的应用设置地区(locale)

A locale is an identifier (id) that refers to a set of user preferences that tend to be shared within a region of the world, such as country. This document refers to a locale identifier as a "locale" or "locale id".

地区是一个唯一性标识,它代表的是世界某个区域(比如国家)中共享的一组用户首选项。本文档中提到的“地区”就是指这个地区标识。

A Unicode locale identifier is composed of a Unicode language identifier and (optionally) the character - followed by a locale extension. (For historical reasons the character _ is supported as an alternative to -.) For example, in the locale id fr-CA the fr refers to the French language identifier, and the CA refers to the locale extension Canada.

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

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

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

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

To set your app's locale to another value, use the CLI parameter --configuration with the value of the locale id that you want to use:

要把你的应用的地区改为其它值,可以使用 CLI 参数 --configuration 来传入你要使用的地区标识:

ng serve --configuration=fr

If you use JIT, you also need to define the LOCALE_ID provider in your main module:

如果要使用 JIT,你就得在你的主模块中定义 LOCALE_ID 这个服务提供商:

import { LOCALE_ID, NgModule } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from '../src/app/app.component'; @NgModule({ imports: [ BrowserModule ], declarations: [ AppComponent ], providers: [ { provide: LOCALE_ID, useValue: 'fr' } ], bootstrap: [ AppComponent ] }) export class AppModule { }

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

要了解关于 Unicode 地区标识的更多信息,参见 CLDR 核心规范

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

要查看 Angular 支持的地区总表,参见 Angular 源码仓库

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:

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

Locale name地区名称Old locale id旧 IDNew locale id新 ID
Indonesian印度尼西亚inid
Hebrew希伯来iwhe
Romanian Moldova罗马尼亚摩尔多瓦moro-MD
Norwegian Bokmål挪威 Bokmålno, 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 pipes

i18n 管道

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

Angular 的管道可以帮助你进行国际化:DatePipeCurrencyPipeDecimalPipePercentPipe 都使用本地化数据来根据 LOCALE_ID 格式化数据。

By default, Angular only contains locale data for en-US. If you set the value of LOCALE_ID to another locale, you must import locale data for that new locale. The CLI imports the locale data for you when you use the parameter --configuration with ng serve and ng build.

默认情况下,Angular 只包含 en-US 的本地化数据。如果你要把 LOCALE_ID 的值设置为其它地区,就必须为那个新地区导入本地化数据。 当你使用 ng serveng build--configuration 参数时,CLI 会自动帮你导入相应的本地化数据。

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' is optional registerLocaleData(localeFr, '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 自带的本地化数据时会使用数据中自带的一个地区标识进行注册。 如果你要使用其它地区标识来注册这个导入的本地化数据,可以在第二个参数中指定一个自定义的地区标识。 比如,Angular 为法语定义的地区标识是 “fr”,你可以通过第二个参数为这些导入的法语本地化数据指定一个自定义的地区标识 “fr-FR”。

The files in @angular/common/locales contain most of the locale data that you need, but some advanced formatting options might only be available in the extra dataset that you can import from @angular/common/locales/extra. An error message informs you when this is the case.

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

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);

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

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

Template translations

模板翻译

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

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

The i18n template translation process has four phases:

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

  1. Mark static text messages in your component templates for translation.

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

  2. Create a translation file: Use the Angular CLI xi18n command to extract the marked text into an industry-standard translation source file.

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

  3. Edit the generated translation file: Translate the extracted text into the target language.

    编辑所生成的翻译文件:把提取出的文本翻译成目标语言。

  4. Merge the completed translation file into the app. To do this, use the Angular CLI build command to compile the app, choosing a locale-specific configuration, or specifying the following command options.

    把翻译完成的文件合并回应用。要做到这一点,请使用 Angular CLI 的 build 命令来编译此应用,选择一个区域相关的配置,或指定下列命令选项。

    • --i18nFile=path to the translation file

      --i18nFile=指向翻译文件的路径

    • --i18nFormat=format of the translation file

      --i18nFormat=此翻译文件的格式

    • --i18nLocale= locale id

      --i18nLocale=地区 ID

The command replaces the original messages with translated text, and generates a new version of the app in the target language.

该命令会使用翻译的文本替换原始信息,并生成新的目标语言版本的应用程序。

You need to build and deploy a separate version of the app for each supported language.

你可以为每种支持的语言构建和部署单独的应用程序版本。

Mark text with the i18n attribute

使用 i18n 属性标记文本

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

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

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

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

<h1>Hello i18n!</h1>

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

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

<h1 i18n>Hello i18n!</h1>

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

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

Help the translator with a description and meaning

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

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

要想翻译的更准确,翻译人员可能需要待翻译文本的额外信息或场景说明。

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

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

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

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

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

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

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

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

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.

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

Set a custom id for persistence 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,就像这样:

<trans-unit id="ba0cc104d3d69bf669f97b8d96a4c5d8d9559aa3" datatype="html">

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.

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

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

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

<h1 i18n="@@introductionHeader">Hello i18n!</h1>

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

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

<trans-unit id="introductionHeader" datatype="html">

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

在描述中使用自定义 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:

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

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

Define unique custom ids

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

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

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

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

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

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

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

Translate text without creating an element

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

If there is a section of text that you would like to translate, you can wrap it in a <span> tag. However, if you don't want to create a new DOM element merely to facilitate translation, you can wrap the text in an <ng-container> element. The <ng-container> is transformed into an html comment:

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