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

应用本地化

Localizing your app

国际化(i18n)是一个过程,用于对你的应用进行设计和准备以便在全球不同地区使用。本地化是指为不同的本地环境构建应用版本的过程,包括提取用于翻译成不同语言的文本,以及格式化特定本地环境的数据。

Internationalization (i18n) is the process of designing and preparing your app to be usable in different locales around the world. Localization is the process of building versions of your app for different locales, including extracting text for translation into different languages, and formatting data for particular locales.

本地环境(locale)用于标识某个区域(例如某个国家/地区),人们会在该区域内使用特定的语言或语言变体。本地环境决定了日期、时间、数字和货币的格式和解析方式,以及各种测量单位和时区、语言、国家/地区的翻译名称。

A locale identifies a region (such as a country) in which people speak a particular language or language variant. The locale determines the formatting and parsing of dates, times, numbers, and currencies as well as measurement units and the translated names for time zones, languages, and countries.

要为所有目标本地环境创建一个与之相适应的用户界面,并考虑到不同语言中的间距差异。欲知详情,请参阅如何实现国际化

Create an adaptable user interface for all of your target locales that takes into consideration the differences in spacing for different languages. For details, see How to approach internationalization.

使用 Angular 国际化你的应用:

Use Angular to internationalize your app:

  • 使用内置管道以本地格式显示日期、数字、百分比和货币。

    Use built-in pipes to display dates, numbers, percentages, and currencies in a local format.

  • 标记出组件模板中要翻译的文字。

    Mark text in component templates for translation.

  • 标记出要翻译的表达式的复数形式。

    Mark plural forms of expressions for translation.

  • 标记出要翻译的备用文字。

    Mark alternate text for translation.

在为国际用户准备好应用之后,通过执行以下任务,用 Angular CLI 本地化你的应用:

After preparing your app for an international audience, use the Angular CLI to localize your app by performing the following tasks:

  • 用 CLI 命令把标记过的文本提取到源语言文件中。

    Use the CLI to extract marked text to a source language file.

  • 把这个文件为每种语言复制一份,并把这些翻译文件发给翻译人员或翻译服务。

    Make a copy of this file for each language, and send these translation files to a translator or service.

  • 在为一个或多个本地环境构建应用时,使用 CLI 合并这些翻译完成的文件。

    Use the CLI to merge the finished translation files when building your app for one or more locales.

要探索本指南中使用的法语翻译示例应用,请参阅现场演练 / 下载范例

To explore the sample app with French translations used in this guide, see the现场演练 / 下载范例.

先决条件

Prerequisites

要准备翻译你的应用,你应该对这些内容有一个基本的了解:

To prepare your app for translations, you should have a basic understanding of the following:

应用本地化的步骤

Steps to localize your app

要本地化你的应用,请执行以下常规步骤:

To localize your app, follow these general steps:

  1. 添加 localize 包

    Add the localize package.

  2. 按 ID 引用本地环境

    Refer to locales by ID.

  3. 根据本地环境格式化数据

    Format data based on locale.

  4. 准备翻译模板

    Prepare templates for translations.

  5. 使用翻译文件

    Work with translation files.

  6. 把翻译合并到应用中

    Merge translations into the app.

  7. 部署多个本地环境

    Deploy multiple locales.

按照这些步骤进行操作时,可以浏览已翻译的示例应用

While following these steps, you can explore the translated example app.

以下是特殊情况下可能用到的一些可选实践:

The following are optional practices that may be required in special cases:

添加 localize 包

Add the localize package

要利用 Angular 的本地化特性,可以用 Angular CLI 把 @angular/localize 包添加到你的项目中:

To take advantage of Angular's localization features, use the Angular CLI to add the @angular/localize package to your project:

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

这个命令会更新你的项目的 package.jsonpolyfills.ts 文件,以导入 @angular/localize 包。

This command updates your project's package.json and polyfills.ts files to import the @angular/localize package.

有关 package.json 和 polyfill 包的更多信息,请参阅工作空间的 npm 依赖项

For more information about package.json and polyfill packages, see Workspace npm dependencies.

如果没有安装 @angular/localize,那么当你试图构建本地化版本的应用时,Angular CLI 就可能会产生错误。

If @angular/localize is not installed, the Angular CLI may generate an error when you try to build a localized version of your app.

按 ID 引用本地环境

Refer to locales by ID

使用 Unicode 本地环境标识符(ID)引用本地环境,该标识符用于指定语言、国家/地区以及其他变体或细分的可选代码。

Refer to a locale using the Unicode locale identifier (ID), which specifies the language, country, and an optional code for further variants or subdivisions.

Unicode 本地环境标识符
Unicode locale identifiers
  • 要获取语言代码列表,请参见 ISO 639-2

    For a list of language codes, see ISO 639-2.

  • ID 要符合 Unicode 通用本地化数据仓库(Common Locale Data Repository CLDR)。有关 Unicode 本地环境标识符的更多信息,请参见 CLDR 核心规范

    IDs conform to the Unicode Common Locale Data Repository (CLDR). For more information about Unicode locale identifiers, see the CLDR core specification.

  • CLDR 和 Angular 的标识符都基于 BCP47

    CLDR and Angular base their identifiers on BCP47 tags.

该 ID 由一个语言标识符组成,例如 en 表示英文, fr 表示法语,后跟短划线(-)和本地环境扩展,比如 US 代表美国,CA 代表加拿大。比如,en-US 是指美国英语区,fr-CA 是指加拿大法语区。Angular 使用这种 ID 来查找对应的本地化数据。

The ID consists of a language identifier, such as en for English or fr for French, followed by a dash (-) and a locale extension, such as US for the United States or CA for Canada. For example, en-US refers to English in the United States, and fr-CA refers to French in Canada. Angular uses this ID to find the correct corresponding locale data.

许多国家/地区(比如法国和加拿大)都使用相同的语言(法语,标识为 fr),但在语法、标点符号、货币格式、十进制数字格式和日期格式方面都有所不同。在本地化你的应用时,可以使用更具体的本地环境 ID,例如加拿大法语区( fr-CA )。

Many countries, such as France and Canada, use the same language (French, identified as fr) but differ in grammar, punctuation, and formats for currency, decimal numbers, and dates. Use a more specific locale ID, such as French for Canada (fr-CA), when localizing your app.

Angular 默认使用 en-US(美国英语)作为应用的源本地环境。

Angular by default uses en-US (English in the United States) as your app's source locale.

Angular 的代码仓库中包含常见的本地环境。你可以通过在应用的工作区配置文件 angular.json 中的 sourceLocale 字段中设置源本地环境来为此构建更改应用的源本地环境。构建过程(在本指南的把翻译合并到应用程序中描述)会使用应用中的 angular.json 文件自动设置 LOCALE_ID令牌并加载本地化数据。

The Angular repository includes common locales. You can change your app's source locale for the build by setting the source locale in the sourceLocale field of your app's workspace configuration file (angular.json). The build process (described in Merge translations into the app in this guide) uses your app's angular.json file to automatically set the LOCALE_IDtoken and load the locale data.

根据本地环境格式化数据

Format data based on locale

Angular 提供了下列内置数据转换管道 ,它们根据本地化的规则使用 LOCALE_ID令牌格式化数据:

Angular provides the following built-in data transformation pipes that use the LOCALE_IDtoken to format data according to the locale's rules:

例如,{{today | date}} 使用 DatePipeLOCALE_ID 中指定的本地化格式显示当前日期。

For example, {{today | date}} uses DatePipe to display the current date in the format for the locale in LOCALE_ID.

要覆盖 LOCALE_ID 的值, 请添加 locale 参数。例如,要强制该货币使用 en-US 而不管你为 LOCALE_ID 设置的是哪种本地环境,请使用如下格式:{{amount | currency : 'en-US'}}

To override the value of LOCALE_ID, add the locale parameter. For example, to force the currency to use en-US no matter which language-locale you set for LOCALE_ID, use this form: {{amount | currency : 'en-US'}}.

准备翻译模板

Prepare templates for translations

要翻译你的应用模板,就要用 Angular 的 i18n 属性标记出文本、属性和其他元素为翻译人员或翻译服务准备出文本。请遵循以下常规步骤:

To translate your app's templates, you need to prepare the text for a translator or translation service by marking text, attributes, and other elements with the Angular i18n attribute. Follow these general steps:

  1. 标记要翻译的文本

    Mark text for translations.

  2. 添加有用的描述和含义,以便为翻译人员提供额外的信息或背景信息。

    Add helpful descriptions and meanings to help the translator with additional information or context.

  3. 翻译不显示的文本

    Translate text not for display.

  4. 标记要翻译的元素属性 ,比如图像的 title 属性。

    Mark element attributes for translations, such as an image's title attribute.

  5. 标记复数形式和替换形式以便翻译,以符合不同语言的复数规则和语法结构。

    Mark plurals and alternates for translation in order to comply with the pluralization rules and grammatical constructions of different languages.

标记要翻译的文本

Mark text for translations

使用 i18n 属性在组件模板中标记静态文本消息以进行翻译。把它放到每个带有要翻译的静态文本的元素标签上。

Mark the static text messages in your component templates for translation using the i18n attribute. Place it on every element tag with fixed text to be translated.

比如,下面的 <h1> 标签会显示一个简单的英文问候语 “Hello i18n!”。

For example, the following <h1> tag displays a simple English language greeting, "Hello i18n!"

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

要把这个问候语标记为要翻译的,请把 i18n 属性添加到 <h1> 标签上。

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.

添加有用的描述和含义

Add helpful descriptions and meanings

要准确翻译文本信息,翻译人员可能需要额外的信息或上下文。把此文本信息的描述添加为 i18n 属性的值,如下例所示:

To translate a text message accurately, the translator may need additional information or context. Add a description of the text message as the value of the i18n attribute, as shown in the following example:

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

翻译人员可能还需要知道该特定应用上下文中,这段文本的意义或意图,以便像其它具有相同含义的文本一样翻译它。用带含义i18n 属性值开头,并用 | 字符把它和描述分隔开。

The translator may also need to know the meaning or intent of the text message within this particular app context, in order to translate it the same way as other text with the same meaning. Start the i18n attribute value with the meaning and separate it from the description with the | character: <meaning>|<description>.

例如,你可以添加这样的含义:<h1> 标签是一个站点标头,它在用作标题时和从另一段文本中引用时都要翻译成一样的:

For example, you can add the meaning that this <h1> tag is a site header that needs to be translated the same way not only when used as a header, but also when referred to from another section of text:

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

其结果是,任何标有 site header 的文字,都会翻译成完全相同的结果。

As a result, any text marked with site header as the meaning is translated exactly the same way.

含义(meaning)如何控制文本的提取和合并
How meanings control text extraction and merging

Angular 提取工具(在本指南的“使用翻译文件”中讲解)会为模板中的每个 i18n 属性生成一个翻译单元条目。它会根据其含义描述为每个翻译单元分配一个唯一的 ID。

The Angular extraction tool (described in Work with translation files in this guide) generates a translation unit entry for each i18n attribute in a template. It assigns each translation unit a unique ID based on the meaning and description.

要用不同的 ID 提取具有不同含义的文本元素。例如,如果单词 “right” 出现在一个地方时表示正确(比如:"You are right"),而在另一个地方的含义是方向(比如:"Turn right"),那么这个词的翻译就会有所不同,并且会作为不同的翻译条目合并回应用。

The same text elements with different meanings are extracted with separate IDs. For example, if the word "right" appears with the meaning correct (as in "You are right") in one place, and with the meaning direction (as in "Turn right") in another place, the word is translated differently and merged back into the app as different translation entries.

如果相同的文本元素具有不同的描述含义相同,那么它们只会被提取一次,只有一个 ID。只要出现了相同的文本元素,就会把这个翻译条目合并回应用。

If the same text elements have different descriptions but the same meaning, they are extracted only once, with only one ID. That one translation entry is merged back into the app wherever the same text elements appear.

翻译不显示的文字

Translate text not for display

虽然也可以使用 <span> 标签来翻译未显示的文本,但这样你就会创建一个新的 DOM 元素。要避免这种情况,请把它放在 <ng-container> 元素中,该元素会被转换成一个不显示的 HTML 注释,如下例所示:

While you can translate non-displayed text using a <span> tag, you are creating a new DOM element. To avoid doing so, wrap the text in an <ng-container> element, which is transformed into a non-displayed HTML comment as shown in this example:

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

标记要翻译的元素属性

Mark element attributes for translations

title 等 HTML 属性包含要与模板中的其它显示文本一起翻译的文本。下面的代码展示了一个带 title 属性的图片:

HTML attributes such as title include text that should be translated along with the rest of the displayed text in the template. The following example shows an image with a title attribute:

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

为了标记出要翻译的属性,就要为它添加一个 i18n-属性名 属性。下面的例子展示了如何通过添加 i18n-titleimg 标签上标记出 title 属性:

To mark an attribute for translation, add i18n-attribute in which attribute is the attribute to translate. The following example shows how to mark the title attribute on the img tag by adding i18n-title:

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

你可以对任意元素的任何属性添加 i18n-属性名 属性。你也可以用 i18n-属性名="<meaning>|<description>@@<id>" 语法来为它指定含义、描述和自定义 ID。

You can use i18n-attribute with any attribute of any element. You also can assign a meaning, description, and custom ID with the i18n-attribute="<meaning>|<description>@@<id>" syntax.

标记复数形式和替换形式以便翻译

Mark plurals and alternates for translation

不同的语言有不同的复数规则和语法结构,这会让翻译变得困难。要简化翻译,可以使用带有正则表达式的 Unicode 国际化组件(International Components for Unicode ICU)子句,比如 plural 标出要用的复数形式,用 select 标出候选的备用文字。

Different languages have different pluralization rules and grammatical constructions that can make translation difficult. To simplify translation, use International Components for Unicode (ICU) clauses with regular expressions, such as plural to mark the uses of plural numbers, and select to mark alternate text choices.

ICU 条款遵循 CLDR 复数规则中指定的 ICU 消息格式

The ICU clauses adhere to the ICU Message Format specified in the CLDR pluralization rules.

标出复数形式

Mark plurals

使用 plural 子句标出那些在逐字翻译时可能用不到的表达式。

Use the plural clause to mark expressions that may not be meaningful if translated word-for-word.

比如,如果你想用英文显示 “updated x minutes ago”,你可能需要显示 “just now”、“one minute ago” 或 “ x minutes ago”( x为实际数字)。在其他语言中这种基数规则可能不同。下面的代码演示了如何使用 plural 子句表达这三个选项:

For example, if you want to display "updated x minutes ago" in English, you may want to display "just now", "one minute ago", or "x minutes ago" (with x as the actual number). Other languages might express this cardinality differently. The following example shows how to use a plural clause to express these three options:

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

在上面的例子中:

In the above example:

  • 第一个参数 minutes ,被绑定到组件的属性( minutes ),它决定了分钟数。

    The first parameter, minutes, 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 pattern of pluralization categories and their matching values:

    • 零分钟时,使用 =0 {just now}

      For zero minutes, use =0 {just now}.

    • 一分钟后,使用 =1 {one minute}

      For one minute, use =1 {one minute}.

    • 对于任何无法匹配的基数,使用 other {{{minutes}} minutes ago} 。你还可以使用表达式中带有 plural 子句的 HTML 标记和插值 ,比如 {{{minutes}}

      For any unmatched cardinality, use other {{{minutes}} minutes ago}. You can use HTML markup and interpolations such as {{{minutes}} with the plural clause in expressions.

    • 在复数类别后面,把默认文本(英文)放在花括号({})中。

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

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

Pluralization categories include (depending on the language):

  • =0(或任何其他数字)

    =0 (or any other number)

  • zero

  • one

  • two

  • few

  • many

  • other

本地环境可能不支持某些复数类别
Locales may not support some pluralization categories

很多本地环境都不支持某些复数类别。例如,默认本地环境( en-US )和其他本地环境(例如 es )都有非常简单的 plural() 函数,它们不支持这 few 类别。 en-USplural() 函数实例如下:

Many locales don't support some of the pluralization categories. For example, the default locale (en-US) and other locales (such as es) have very simple plural() functions that don't support the few category. The following shows the en-US plural() function:

function plural(n: number): number { let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length; if (i === 1 && v === 0) return 1; return 5; }
      
      function plural(n: number): number {
  let i = Math.floor(Math.abs(n)), v = n.toString().replace(/^[^.]*\.?/, '').length;
  if (i === 1 && v === 0) return 1;
  return 5;
}
    

该函数只返回 1(one)或 5(other)。这个 few 类别永远不会匹配。如果所有复数类别都不匹配,Angular 就会尝试匹配 other 类别。other 用作缺失类别的标准后备。

The function will only ever return 1 (one) or 5 (other). The few category will never match. If none of the pluralization categories match, Angular will try to match other. Use other as the standard fallback for a missing category.

有关复数类别的详细信息,请参阅 “CLDR - Unicode 公共本地化数据存储库”中的选择复数类别名称

For more information about pluralization categories, see Choosing plural category names in the CLDR - Unicode Common Locale Data Repository.

标记替代表达式和嵌套表达式

Mark alternates and nested expressions

如果需要根据变量的值来显示备用文本,你需要翻译所有的备用项。

If you need to display alternate text depending on the value of a variable, you need to translate all of the alternates.

select 子句类似于 plural 子句,它会根据你定义的字符串值标记出备用文本的可选值。例如,组件模板中的下列子句绑定了组件的 gender 属性,该属性输出以下字符串值之一:“male”、“female” 或 “other”。该子句将这些值映射成适当的翻译:

The select clause, similar to the plural clause, marks choices for alternate text based on your defined string values. For example, the following clause in the component template binds to the component's gender property, which outputs one of the following string values: "male", "female" or "other". The clause 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>
    

你还可以把不同的子句嵌套在一起,比如下例中的 pluralselect 子句:

You can also nest different clauses together, such as the plural and select clauses in the following 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>
    

使用翻译文件

Work with translation files

在准备好要翻译的模板后,使用 Angular CLI 的 xi18n 命令把模板中标记过的文本提取到源语言文件中。所谓标记过的文本包括标有 i18n 的文本和标有 i18n-属性名 的属性,如前一节中所描述。请执行以下步骤:

After preparing a template for translation, use the Angular CLI xi18n command to extract the marked text in the template into a source language file. The marked text includes text marked with i18n and attributes marked with i18n-attribute as described in the previous section. Follow these steps:

  1. 提取源语言文件 。你可以选择更改位置、格式和名称。

    Extract the source language file. You can optionally change the location, format, and name.

  2. 通过复制源语言文件,可以为每种语言创建一个翻译文件

    Create a translation file for each language by copying the source language file.

  3. 翻译每个翻译文件

    Translate each translation file.

  4. 单独翻译复数形式和替代表达式

    Translate plurals and alternate expressions separately.

提取源语言文件

Extract the source language file

要提取源语言文件,请打开终端窗口,切换到应用项目的根目录,执行以下 CLI 命令:

To extract the source language file, open a terminal window, change to the root directory of your app project, and run the following CLI command:

ng xi18n
      
      ng xi18n
    

xi18n 命令使用 XML 本地化交换文件格式(XLIFF 版本 1.2)在项目的根目录下创建一个名为 messages.xlf 的源语言文件。

The xi18n command creates a source language file named messages.xlf in your project's root directory using the XML Localization Interchange File Format (XLIFF, version 1.2).

使用下列 xi18n 命令可以改变源语言文件的位置、格式和文件名:

Use the following xi18n command options to change the source language file location, format, and file name:

  • --output-path:改变位置。

    --output-path: Change the location.

  • --format:改变格式。

    --format: Change the format.

  • --outFile:改变文件名。

    --outFile: Change the file name.

注意:--i18n-locale 选项已弃用。 Angular 9 会使用应用的工作空间配置文件( angular.json )中配置的源本地环境。

Note: The --i18n-locale option is deprecated. Angular 9 uses the source locale configured in your app's workspace configuration file (angular.json).

ng xi18n 提取机制使用的是 ViewEngine 编译器,它无法处理 Ivy 编译器可以处理的一些代码语法。这个问题的解决方案目前正在开发中。要跟踪修复进度或做出贡献,请参阅 PR 32912

The ng xi18n extraction mechanism uses the ViewEngine compiler, which is not able to cope with some code syntax that the Ivy compiler can handle. A fix for this issue is currently under development. To follow or contribute to this fix see PR 32912.

修改源语言文件的位置

Change the source language file location

要把文件创建在 src/locale 目录下,请把输出路径指定为一个选项,如下例所示:

To create a file in the src/locale directory, specify the output path as an option, as shown in the following example:

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

修改源语言文件格式

Change the source language file format

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

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

使用 --format 命令选项显式指定转换格式,如下例所示:

Specify the translation format explicitly with the --format command option, as shown in the following examples:

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 文件使用扩展名 .xlf。 XMB 格式生成 .xmb 源语言文件,但使用 .xtb(XML Translation Bundle:XTB)翻译文件。

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

修改源语言文件名

Change the source language file name

要更改提取工具生成的源语言文件的名称,请使用 --outFile 命令选项:

To change the name of the source language file generated by the extraction tool, use the --outFile command option:

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

为每种语言创建一个翻译文件

Create a translation file for each language

ng xi18n 命令(不带选项时)会在项目的 src 文件夹下生成一个名为 messages.xlf 的源语言文件。通过复制源语言文件为每种语言创建一个翻译文件。为了避免混淆这么多翻译文件,你应该把这些语言的翻译文件整理到 src/ 下的一个专用 locale 文件夹中。这些文件使用与相关的本地环境匹配的扩展名,例如 messages.fr.xlf

The ng xi18n command (with no options) generates a source language file named messages.xlf in the project src folder. Create translation files for each language by copying the source language file. To avoid confusion with multiple translations, you should organize the language translation files by locale in a dedicated locale folder under src/. Use a filename extension that matches the associated locale, such as messages.fr.xlf.

例如,要创建法语翻译文件,请按照下列步骤操作:

For example, to create a French translation file, follow these steps:

  1. 复制一下 messages.xlf 源语言文件。

    Make a copy of the messages.xlf source language file.

  2. 把这份副本放在 src/locale 文件夹中。

    Put the copy in the src/locale folder.

  3. 把该副本重命名为 messages.fr.xlf 以便进行法语( fr )翻译。把这个翻译文件发给翻译人员。

    Rename the copy to messages.fr.xlf for the French language (fr) translation. Send this translation file to the translator.

针对要添加到应用中的每种语言,重复上述步骤。

Repeat the above steps for each language you want to add to your app.

翻译各个翻译文件

Translate each translation file

除非你能流利的说那种语言并且有时间编辑这些翻译文件,否则很可能要把每个翻译文件都发给翻译人员,翻译人员会使用 XLIFF 文件编辑器来创建和编辑翻译。

Unless you are fluent in the language and have the time to edit translations, you would likely send each translation file to a translator, who would then use an XLIFF file editor to create and edit the translation.

要演示这个过程,请参阅现场演练 / 下载范例中的 messages.fr.xlf 文件,它包含法语翻译,无需特殊的 XLIFF 编辑器或法语知识,即可编辑。请执行以下步骤:

To demonstrate this process, see the messages.fr.xlf file in the现场演练 / 下载范例, which includes a French translation you can edit without a special XLIFF editor or knowledge of French. Follow these steps:

  1. 打开 messages.fr.xlf 并找到第一个 <trans-unit> 元素。这是一个翻译单元 ,也叫做文本节点,代表对之前标记过 i18n 属性的 <h1> 标签的翻译:

    Open messages.fr.xlf and find the first <trans-unit> element. This is a translation unit, also known as a text node, representing the translation of the <h1> greeting tag that was previously marked with the i18n attribute:

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

id="introductionHeader"" 是一个自定义 ID ,但在源 HTML 中没有 @@ 前缀。

The id="introductionHeader"" is a custom ID, but without the @@ prefix required in the source HTML.

  1. 在文本节点中复制 <source>...</source> 元素,把它重命名为 target 元素,然后用法语文本替换它的内容:

    Duplicate the <source>...</source> element in the text node, rename it target, and then replace its content with the French text:

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

在更复杂的翻译中,以前讲过的描述(description)和含义(meaning)中提供的信息和上下文可以帮助你选择合适的单词进行翻译。

In a more complex translation, the information and context in the description and meaning elements described previously would help you choose the right words for translation.

  1. 翻译其他文本节点的方式与下例所示相同:

    Translate the other text nodes the same way as shown in the following example:

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

不要更改翻译单元的 ID。每个 id 都是由 Angular 生成的,取决于模板文本的内容及其指定的含义。如果你改变了文本或含义,那么 id 就会改变。有关管理文本更新和 ID 的更多信息,请参阅上一节的自定义 ID

Don't change the IDs for translation units. Each id is generated by Angular and depends on 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 about managing text updates and IDs, see the previous section on custom IDs.

翻译复数和替代表达式

Translate plurals and alternate expressions

pluralselectplural ICU 表达式作为附加信息被提取出来,因此你必须单独翻译它们。

The plural and select ICU expressions are extracted as additional messages, so you must translate them separately.

翻译复数

Translate plurals

要翻译 plural ,请把它的 ICU 格式匹配值翻译成下面的例子:

To translate a plural, translate its ICU format match values as shown in the following example:

  • just now

    just now

  • one minute ago

    one minute ago

  • <x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes ago

    <x id="INTERPOLATION" equiv-text="{{minutes}}"/> minutes ago

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

你可以根据需要为每种语言添加或移除多个 case。

You can add or remove plural cases as needed for each language.

对于语言复数规则,参见CLDR 复数规则

For language plural rules, see CLDR plural rules.

翻译替代表达式

Translate alternate expressions

Angular 还提供了另一种 select ICU(Unicode 国际化组件)表达式作为单独的翻译单元。下图显示了组件模板中的一个 select ICU 表达式:

Angular also extracts alternate select ICU expressions as separate translation units. The following shows a 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>
    

在这个例子中,Angular 把此表达式提取成了两个翻译单元。第一个单元包含 select 子句外的文本,并使用了一个 select 占位符( <x id="ICU"> ):

In this example, Angular extracts the expression into two translation units. The first contains the text outside of the select clause, and uses a placeholder for select (<x id="ICU">):

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

在翻译文本时,你可以根据需要移动这个占位符,但不能删除它。如果你删除了占位符,这个 ICU 表达式就不会出现在翻译后的应用中。

When translating the text, you can move the placeholder if necessary, but don't remove it. If you remove the placeholder, the ICU expression will not appear in your translated app.

第二个翻译单元包含 select 子句:

The second translation unit contains the select clause:

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

下面的例子展示了翻译过的翻译单元:

The following example shows both translation units after translating:

</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 nested expressions

Angular 对嵌套表达式的处理方式和替代表达式一样,会把它提取成两个翻译单元。第一个包含嵌套表达式外部的文本:

Angular treats a nested expression in the same manner as an alternate expression, extracting it into two translation units. The first 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 translation 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>
    

下面的例子展示了翻译后的翻译单元:

The following example shows both translation units after translating:

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

把翻译合并到应用中

Merge translations into the app

要把已完成的译文合并到应用中,请使用 Angular CLI 为每个本地环境构建应用的可分发副本。构建过程中会用翻译文本替换原始文本,并为应用的每个可分发副本设置 LOCALE_ID 令牌。它还会加载并注册本地化数据。

To merge the completed translations into the app, use the Angular CLI to build a copy of the app's distributable files for each locale. The build process replaces the original text with translated text, and sets the LOCALE_ID token for each distributable copy of the app. It also loads and registers the locale data.

合并之后,你可以使用服务器端的语言检测功能或使用不同的子目录来为应用的每个可分发副本架设服务,就像下一章中部署多个本地环境部分描述的那样。

After merging, you can serve each distributable copy of the app using server-side language detection or different subdirectories, as described in the next section about deploying multiple locales.

此构建过程会用预先(AOT)编译生成一个小巧、快速、可立即运行的应用。在 Angular 9 的 Ivy 中,AOT 默认用于开发版本和生产版本,并且需要 AOT 对组件模板进行本地化。

The build process uses ahead-of-time (AOT) compilation to produce a small, fast, ready-to-run app. With Ivy in Angular version 9, AOT is used by default for both development and production builds, and AOT is required to localize component templates.

有关构建过程的详细解说,请参阅构建和提供 Angular 应用。这个构建过程可用于 .xlf 格式的翻译文件或 Angular 能理解的其它格式,比如 .xtb

For a detailed explanation the build process, see Building and serving Angular apps. This build process works for translation files in the .xlf format or in another format that Angular understands, such as .xtb.

在使用 JIT 模式时,Ivy 不支持合并 i18n 的翻译。如果你禁用了 Ivy 并正在使用 JIT 模式,请参阅合并 JIT 编译器

Ivy does not support merging i18n translations when using JIT mode. If you disable Ivy and are using JIT mode, see merging with the JIT compiler.

要为每个本地环境构建应用的一个可分发副本,请在项目工作空间配置文件 angular.json中的构建配置定义本地环境。这个方法通过放弃为每个本地环境执行完整构建的需求,缩短了构建过程。

To build a separate distributable copy of the app for each locale, define the locales in the build configuration in your project's workspace configuration file angular.json. This method shortens the build process by removing the requirement to perform a full app build for each locale.

然后,你可以使用 angular.json 中的 "localize" 选项为每个本地环境生成一个应用版本 。您也可以使用 Angular CLI build命令及其 --localize 选项来进行命令行构建

You can then generate app versions for each locale using the "localize" option in angular.json. You can also build from the command line using the Angular CLI buildcommand with the --localize option.

你也可以选择只针对一种本地环境来用特定的构建选项配置自定义本地环境。

You can optionally apply specific build options for just one locale for a custom locale configuration.

在构建配置中定义本地环境

Define locales in the build configuration

在应用的构建配置( angular.json)中使用 i18n 项目选项来定义项目的本地环境。它下面的子选项用于标识源语言,并告诉编译器要在哪里找到该项目支持的各种翻译:

Use the i18n project option in your app's build configuration file (angular.json) to define locales for a project. The following sub-options identify the source language and tell the compiler where to find supported translations for the project:

  • sourceLocale:你在应用源代码中使用的本地环境(默认为 en-US

    sourceLocale: The locale you use within the app source code (en-US by default)

  • locales:本地环境标识符到翻译文件的映射表

    locales: A map of locale identifiers to translation files

例如,下面的 angular.json 文件片段把源本地环境设置为 en-US 并提供了到 fr(法语)本地环境翻译文件的路径:

For example, the following excerpt of an angular.json file sets the source locale to en-US and provides the path to the fr (French) locale translation file:

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

为每种本地环境生成一个应用版本

Generate app versions for each locale

要在构建配置中使用你的本地环境定义,请使用 angular.json"localize" 选项告诉 CLI 要为此构建配置生成哪些本地环境:

To use your locale definition in the build configuration, use the "localize" option in angular.json to tell the CLI which locales to generate for the build configuration:

  • 对于以前在构建配置中定义的所有本地环境,都要"localize" 设置为 true

    Set "localize" to true for all the locales previously defined in the build configuration.

  • "localize" 设置为预定义的本地环境标识符子集的数组,来要求只构建那些本地环境版本。

    Set "localize" to an array of a subset of the previously-defined locale identifiers to build only those locale versions.

  • "localize" 设置为 false 表示禁用本地化,不生成任何特定于本地环境的版本。

    Set "localize" to false to disable localization and not generate any locale-specific versions.

注意:本地化组件模板需要进行预先(AOT)编译。如果更改了此设置,请将 "aot" 设置为 true,以便使用 AOT。

Note: Ahead-of-time (AOT) compilation is required to localize component templates. If you changed this setting, set "aot" to true in order to use AOT.

下面的例子展示了在 angular.json 中把 "localize" 选项设为 true,以便在构建配置中定义所有的本地环境:

The following example shows the "localize" option set to true in angular.json so that all locales defined in the build configuration are built:

"build": { "builder": "@angular-devkit/build-angular:browser", "options": { "localize": true, "aot": true, ...
angular.json
      
      "build": {
  "builder": "@angular-devkit/build-angular:browser",
  "options": {
    "localize": true,
    "aot": true,
    ...
    

由于 i18n 的部署复杂性以及最小化重建时间的需要,开发服务器一次只支持一个本地环境的本地化。如果定义了多个本地环境,那么当使用 ng serve 时,把 "localize" 选项设置为 true 就会导致错误。如果你想针对特定的本地环境(比如 fr )进行开发,只要把这个选项设置为特定的本地环境(比如 "localize": ["fr"])就可以了。

Due to the deployment complexities of i18n and the need to minimize rebuild time, the development server only supports localizing a single locale at a time. Setting the "localize" option to true will cause an error when using ng serve if more than one locale is defined. Setting the option to a specific locale, such as "localize": ["fr"], can work if you want to develop against a specific locale (such as fr).

CLI 会加载并注册本地化数据,把生成的每个版本都放在一个特定本地环境的目录下,以保证它与其它本地版本分开,并把这些目录放在所配置的 outputPath 中。对于应用的每个变体, html 元素的 lang 属性都会设置为这个本地环境。 CLI 还会通过在所配置的 baseHref 上添加本地环境,来为每个版本的应用调整 HTML 的 base HREF。

The CLI loads and registers the locale data, places each generated version in a locale-specific directory to keep it separate from other locale versions, and puts the directories within the configured outputPath for the project. For each application variant the lang attribute of the html element is set to the locale. The CLI also adjusts the HTML base HREF for each version of the app by adding the locale to the configured baseHref.

你可以把 "localize" 属性设置为所有配置都能有效继承(或可覆盖)的共享配置。

You can set the "localize" property as a shared configuration that all the configurations effectively inherit (or can override).

从命令行构建

Build from the command line

你还可以将 --localize 选项与 ng build命令和现有的 production 配置一起使用。 CLI 会构建在构建配置中定义的所有本地环境,类似于把 "localize" 选项设置为 true ,如上一节所述。

You can also use the --localize option with the ng buildcommand and your existing production configuration. The CLI builds all locales defined in the build configuration, which is similar to setting the "localize" option to true as described in the previous section.

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

只针对一种本地环境应用特定的构建选项

Apply specific build options for just one locale

要想只为一个本地环境应用特定的构建选项,你可以通过指定一个本地环境来创建一个特定于本地环境的自定义配置,如下例所示:

To apply specific build options to only one locale, you can create a custom locale-specific configuration by specifying a single locale as shown in the following example:

"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 following shows how to serve the French language file created in the example for this guide:

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

你可以使用 CLI 开发服务器( ng serve ),但只能使用一个本地环境。

You can use the CLI development server (ng serve), but only 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 编译器所生成的警告级别:

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(默认值):在控制台或 shell 中显示 Missing translation 警告。

    warning (default): Show a Missing translation warning in the console or shell.

  • ignore:什么都不做

    ignore: Do nothing.

在 Angular CLI 配置文件( angular.json )中 build 下的 options 部分指定警告级别。下面的代码展示了如何把警告级别设置为 error

Specify the warning level in the options section for the build target of your Angular CLI configuration file (angular.json). The following example shows how to set the warning level to error:

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

部署多个本地环境

Deploy multiple locales

如果 myapp 是那个包含应用分发文件的目录,那么你通常可以在每个本地化目录中为不同的本地环境提供不同的版本,比如 myapp/fr(法语版)和 myapp.com/es(西班牙语版)。

If myapp is the directory containing your app's distributable files, you would typically make available different versions for different locales in locale directories such as myapp/fr for the French version and myapp.com/es for the Spanish version.

带有 href 属性的 HTML base 标签为相对链接指定了基址 URI 或 URL。如果你把 angular.json 中的 "localize" 选项设置为 true 或者设置了一个本地环境 ID 的数组,那么 CLI 就会通过把该本地环境 ID 添加到已配置的 "baseHref" 中来为每个应用版本修正 base href。你可以在工作区的配置文件(angular.json )中为每个本地环境指定 "baseHref",比如下面的例子中,这个 "baseHref" 被设置为空字符串:

The HTML base tag with the href attribute specifies the base URI, or URL, for relative links. If you set the "localize" option in angular.json to true or to an array of locale IDs, the CLI adjusts the base href for each version of the app by adding the locale to the configured "baseHref". You can specify the "baseHref" for each locale in your workspace configuration file (angular.json), as shown in the following example, which sets "baseHref" to an empty string:

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

您也可以在编译时使用 CLI 的 --baseHref 选项与 ng build声明 base href

You can also use the CLI --baseHref option with ng buildto declare the base href at compile time.

如何配置托管多种本地环境的服务器超出了本指南的范围。关于如何将应用部署到远程服务器的详细信息,请参见部署指南。

Configuring servers for hosting multiple locales is outside the scope of this guide. For details on how to deploy apps to a remote server, see Deployment.

浏览已翻译的范例应用

Explore the translated example app

下面显示了该应用及其翻译文件的示例:

The following tabs show the example app and its translation files:

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

可选实践

Optional practices

以下是特殊情况下可能会用到的一些可选实践:

The following are optional practices that may be required in special cases:

手动设置源本地环境

Set the source locale manually

Angular 已经包含了 en-US 本地化数据。在使用 ng build--localize 选项时,Angular CLI 会自动包含本地化数据并设置 LOCALE_ID 的值。

Angular already contains locale data for en-US. The Angular CLI automatically includes the locale data and sets the LOCALE_ID value when you use the --localize option with ng build.

若要手动将应用的源本地环境设置为自动包含的值以外的本地环境,请执行以下步骤:

To manually set an app's source locale to one other than the automatic value, follow these steps:

  1. Angular 的代码仓库中查找此本地环境组合的 ID。

    Look up the ID for the language-locale combination in the Angular repository.

  2. 设置 LOCALE_ID令牌。下面的例子中把 LOCALE_ID 的值设置为 fr(法语):

    Set the LOCALE_IDtoken. The following example sets the value of LOCALE_ID to fr (French):

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 { }
src/app/app.module.ts
      
      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 { }
    

导入本地化数据的全局变体

Import global variants of the locale data

如果使用带有 --localize 选项的 CLI 命令 ng build配置本地环境,Angular 就会自动包含本地化数据。

Angular will automatically include locale data if you configure the locale using the --localize option with ng buildCLI command.

Angular 的代码仓库 中的一些文件( @angular/common/locales )包含了你需要的大部分本地化数据,但是一些高级的格式化选项需要提供额外的本地化数据。本地化数据的全局变体可以在 @angular/common/locales/global下找到。下面的例子导入了法语( fr )的全局变体:

The Angular repository files (@angular/common/locales) contain most of the locale data that you need, but some advanced formatting options require additional locale data. Global variants of the locale data are available in @angular/common/locales/global. The following example imports the global variants for French (fr):

import '@angular/common/locales/global/fr;
app.module.ts
      
      import '@angular/common/locales/global/fr;
    

用自定义 ID 管理标记过的文本

Manage marked text with custom IDs

Angular 的提取器会为模板中的每个 i18n 属性生成一个带翻译单元条目的文件。如前所述(在控制文本的提取和合并方式中),Angular 会为每个翻译单元分配一个唯一的 ID,如下所示:

The Angular extractor generates a file with a translation unit entry for each i18n attribute in a template. As described previously (in How meanings control text extraction and merging), Angular assigns each translation unit a unique ID such as the following:

<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 generates a new ID for that translation unit. In most cases a text change would also require a change to the translation. Therefore, using a new ID keeps the text change in sync with translations.

但是,某些翻译系统需要 ID 满足特定的格式或语法。为满足这一需求,你可以用自定义 ID 来标记文本。虽然大多数开发人员不需要使用自定义 ID,但有些开发人员可能希望使用具有独特语法的 ID 传递额外的元数据(例如应用中的库、组件或应用范围)。

However, some translation systems require a specific form or syntax for the ID. To address this requirement, you can mark text with custom IDs. While most developers don't need to use custom IDs, some may want to use IDs that have a unique syntax to convey additional metadata (such as the library, component, or area of the app in which the text appears).

使用前缀 @@ 可以在 i18n 属性中指定自定义 ID。下面的例子定义了自定义 ID introductionHeader

Specify a custom ID in the i18n attribute by using the prefix @@. The following example 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 generates a translation unit with the custom ID:

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

如果改变了文本,提取器就不会修改 ID。因此,您无需采取额外步骤来更新翻译。使用自定义 ID 的一个缺点是,如果你修改了文本,你的翻译可能会与新修改过的源文本不同步。

If you change the text, the extractor does not change the ID. As a result, you don't have to take the extra step of updating the translation. The drawback of using custom IDs is that if you change the text, your translation may be out-of-sync with the newly changed source text.

使用带描述的自定义 ID

Use a custom ID with a description

使用自定义 ID 结合描述和含义可以进一步帮助翻译。下面的例子中就包含一个描述,其后紧跟着自定义 id

Use a custom ID in combination with a description and a meaning to further help the translator. The following example 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>
    

下面的例子添加了一个含义:

The following example adds a meaning:

<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,那么提取工具只会提取出第一个,而 Angular 会使用它的翻译代替两个原始文本元素。

Be sure to define custom IDs that are unique. If you use the same ID for two different text elements, the extraction tool extracts only the first one, and Angular uses its translation in place of both original text elements.

例如,在下面的代码中,为两个不同的文本元素定义了相同的自定义 ID myId

For example, in the following code the same custom ID myId is defined for two different text elements:

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

下面是它翻译成的法语:

The following shows the 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>
    

这两个元素现在都使用了相同的翻译( Bonjour ),这是因为它们是使用相同的自定义 ID 定义的:

Both elements now use the same translation (Bonjour) because they were defined with the same custom ID:

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