国际化 (i18n)

Angular's internationalization (i18n) tools help make your app available in multiple languages.

Angular的国际化i18n)工具可以帮助我们使用多个语言发布应用。

Contents

目录

Try this live example of a JIT-compiled app, translated into Spanish.

试试 这个翻译为西班牙语版JiT编译应用的在线例子

Angular and i18n template translation

Angular和i18n模板翻译

Application internationalization is a challenging, many-faceted effort that takes dedication and enduring commitment. Angular's i18n internationalization facilities can help.

应用程序国际化很具有挑战性,多方面的努力,需要持久的奉献和决心。 Angular的i18n国际化工具可以帮助你。

This page describes the i18n tools available to assist translation of component template text into multiple languages.

本章描述了一些i18n工具,它们可以帮你把组件模板文本翻译成多种语言。

Practitioners of internationalization refer to a translatable text as a "message". This page uses the words "text" and "message" interchangably and in the combination, "text message".

国际化工作者通常将一个可翻译的文本叫作“信息”。 本章使用了“文本”和“信息”,它们可以互换,也可以组合“文本信息”。

The i18n template translation process has four phases:

i18n模板翻译流程有四个阶段:

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

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

  2. An angular i18n tool extracts the marked messages into an industry standard translation source file.

    Angular的i18n工具将标记的信息提取到一个行业标准的翻译源文件。

  3. A translator edits that file, translating the extracted text messages into the target language, and returns the file to you.

    翻译人员编辑该文件,翻译提取出来的文本信息到目标语言,并将该文件还给你。

  4. The Angular compiler imports the completed translation files, replaces the original messages with translated text, and generates a new version of the application in the target language.

    Angular编译器导入完成翻译的文件,使用翻译的文本替换原始信息,并生成新的目标语言版本的应用程序。

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

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

Mark text with the i18n attribute

使用i18n属性标记文本

The Angular i18n attribute is a marker for translatable content. Place it on every element tag whose fixed text should be translated.

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

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

i18n不是Angular指令。 它是一个自定义属性,Angular工具和编译器认识它。 它将在完成翻译之后,被编译器移除。

In the accompanying sample, an <h1> tag displays a simple English language greeting that you translate into Spanish:

在例子中,<h1>标签显示了一句简单的英文问候语,它将被翻译为西班牙语:

src/app/app.component.html

<h1>Hello i18n!</h1>

Add the i18n attribute to the tag to mark it for translation.

添加i18n属性到该标签上,把它标记为需要翻译的文本。

src/app/app.component.html

<h1 i18n>Hello i18n!</h1>

Help the translator with a description and intent

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

In order to translate it accurately, the translator may need a description of the message. Assign a description to the i18n attribute:

翻译人员可能需要待翻译文本的描述才能翻译准确。 为i18n属性添加描述:

src/app/app.component.html

<h1 i18n="An introduction header for this sample">Hello i18n!</h1>

In order to deliver a correct translation, the translator may need to know your intent—the true meaning of the text within this particular application context. In front of the description, add some contextual meaning to the assigned string, separating it from the description with the | character (<meaning>|<description>):

为了给出正确的翻译,翻译者需要知道你这段文本在特定情境下的 真实意图。 在描述的前面,为指定的字符串添加一些上下文含义,用|将其与描述文字隔开(<意图>|<描述>)。

src/app/app.component.html

<h1 i18n="User welcome|An introduction header for this sample">Hello i18n!</h1>

While all appearances of a message with the same meaning have the same translation, a message with a variety of possible meanings could have different translations. The Angular extraction tool preserves both the meaning and the description in the translation source file to facilitiate contextually-specific translations.

如果所有地方出现的文本具有相同含义时,它们应该有相同的翻译, 但是如果在某些地方它具有不同含义,那么它应该有不同的翻译。 Angular的提取工具在翻译源文件中保留含义描述,以支持符合特定上下文的翻译。

Translate text without creating an element

Suppose there is a stretch of text that you'd like to translate. You could wrap it in a <span> tag but for some reason (CSS comes to mind) you don't want to create a new DOM element merely to facilitate translation.

Here are two techniques to try.

(1) Wrap the text in an <ng-container> element. The <ng-container> is never renderered:

src/app/app.component.html

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

(2) Wrap the text in a pair of HTML comments:

src/app/app.component.html

<!--i18n: optional meaning|optional description --> I don't output any element either <!--/i18n-->

Add i18n-... translation attributes

You've added an image to your template. You care about accessibility too so you add a title attribute:

src/app/app.component.html

<img [src]="logo" title="Angular logo">

The title attribute needs to be translated. Angular i18n support has more translation attributes in the form,i18n-x, where x is the name of the attribute to translate.

To translate the title on the img tag from the previous example, write:

src/app/app.component.html

<img [src]="logo" i18n-title title="Angular logo" />

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

Handle singular and plural

Different languages have different pluralization rules.

Suppose your application says something about a collection of wolves. In English, depending upon the number of wolves, you could display "no wolves", "one wolf", "two wolves", or "a wolf pack". Other languages might express the cardinality differently.

Here's how you could mark up the component template to display the phrase appropriate to the number of wolves:

src/app/app.component.html

<span i18n>{wolves, plural, =0 {no wolves} =1 {one wolf} =2 {two wolves} other {a wolf pack}}</span>

Pluralization categories include:

Put the default English translation in braces ({}) next to the pluralization category.

You could keep this up for three, four, and every other number of wolves. Or you could specify the other category as a catch-all for any unmatched cardinality and write something like: other {a wolf pack}.

This syntax conforms to the ICU Message Format that derives from the Common Locale Data Repository (CLDR), which specifies the pluralization rules.

Select among alternative texts

The application displays different text depending upon whether the hero is male or female. These text alternatives require translation too.

You can handle this with a select translation. A select also follows the ICU message syntax. You choose among alternative translation based on a string value instead of a number.

The following format message in the component template binds to the component's gender property, which outputs either an "m" or an "f". The message maps those values to the appropriate translation:

src/app/app.component.html

<span i18n>The hero is {gender, select, m {male} f {female}}</span>

Create a translation source file with the ng-xi18n tool

使用ng-xi18n工具创建翻译源文件

Use the ng-xi18n extraction tool to extract the i18n-marked texts into a translation source file in an industry standard format.

使用ng-xi18n提取工具来将i18n标记的文本提取到一个符合行业标准格式的翻译源文件。

This is an Angular CLI tool in the @angular/compiler-cli npm package. If you haven't already installed the CLI and its platform-server peer dependency, do so now:

它是在@angular/compiler-cli npm包中的一个Angular CLI工具。 如果你还没有安装这个CLI和它的 platform-server,安装它们:

npm install @angular/compiler-cli @angular/platform-server --save

Open a terminal window at the root of the application project and enter the ng-xi18n command:

在应用的项目根目录打开一个终端窗口,并输入ng-xi18n命令:

./node_modules/.bin/ng-xi18n

Windows users may have to quote the command like this: "./node_modules/.bin/ng-xi18n"

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

工具默认生成一个名为messages.xlf的翻译文件,格式为XML本土化互换文件格式(XLIFF, version 1.2)

Other translation formats

You can generate a file named messages.xmb in the XML Message Bundle (XMB) format by adding the --i18nFormat=xmb flag.

./node_modules/.bin/ng-xi18n --i18nFormat=xmb

This sample sticks with the XLIFF format.

Other options

You may have to specify additional options. For example, if the tsconfig.json TypeScript configuration file is located somewhere other than in the root folder, you must identify the path to it with the -p option:

./node_modules/.bin/ng-xi18n -p path/to/tsconfig.json ./node_modules/.bin/ng-xi18n --i18nFormat=xmb -p path/to/tsconfig.json

Add an npm script for convenience

Consider adding a convenience shortcut to the scripts section of the package.json to make the command easier to remember and run:

"scripts": { "i18n": "ng-xi18n", ... }

Now you can issue command variations such as these:

npm run i18n npm run i18n -- -p path/to/tsconfig.json npm run i18n -- --i18nFormat=xmb -p path/to/tsconfig.json

Note the -- flag before the options. It tells npm to pass every flag thereafter to ng-xi18n.

Translate text messages

翻译文本信息

The ng-xi18n command generates a translation source file in the project root folder named messages.xlf. The next step is to translate the English language template text into the specific language translation files. The cookbook sample creates a Spanish translation file.

ng-xi18n命令在项目根目录生成一个名为messages.xlf的翻译源文件。 下一步是将英文模板文本翻译到目标语言的翻译文件。 本烹饪书创建了一个西班牙语翻译文件。

Create a localization folder

新建一个本土化目录

You will probably translate into more than one other language so it's a good idea for the project structure to reflect your entire internationalization effort.

你很有可能翻译到更多其他语言,所以为全部国际化工作做适当的调整项目目录结构是理所当然的。

One approach is to dedicate a folder to localization and store related assets , such as internationalization files, there.

其中一种方法是为本土化和相关资源(比如国际化文件)创建一个专门的目录。

Localization and internationalization are different but closely related terms.

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

This cookbook follows that suggestion. It has a locale folder under the src/. Assets within the folder carry a filename extension that matches a language-culture code from a well-known codeset.

Make a copy of the messages.xlf file, put it in the locale folder and rename it messages.es.xlffor the Spanish language translation. Do the same for each target language.

Translate text nodes

In the real world, you send the messages.es.xlf file to a Spanish translator who fills in the translations using one of the many XLIFF file editors.

在现实世界中,messages.es.xlf文件会被发给西班牙语翻译,他们使用这些XLIFF文件编辑器中的一种来翻译它。

This sample file is easy to translate without a special editor or knowledge of Spanish. Open messages.es.xlf and find the first <trans-unit> section:

我们不需要任何编辑器或者西班牙语知识就可以轻易的翻译本例子文件。 打开messages.es.xlf并找到<trans-unit>节点:

src/locale/messages.es.xlf (<trans-unit>)

<trans-unit id="af2ccf4b5dba59616e92cf1531505af02da8f6d2" datatype="html"> <source>Hello i18n!</source> <target>¡Hola i18n!</target> <note priority="1" from="description">An introduction header for this sample</note> <note priority="1" from="meaning">User welcome</note> </trans-unit>

This XML element represents the translation of the <h1> greeting tag you marked with the i18n attribute.

这个XML元素代表了你使用i18n属性标记的<h1>问候语标签的翻译。

Using the source, description, and meaning elements to guide your translation, replace the <target/> tag with the Spanish greeting:

翻译中利用sourcedescriptionmeaning元素的信息,替换<target/>标签为西班牙语问候语:

src/locale/messages.es.xlf (<trans-unit>, after translation)

<trans-unit id="af2ccf4b5dba59616e92cf1531505af02da8f6d2" datatype="html"> <source>Hello i18n!</source> <target>¡Hola i18n!</target> <note priority="1" from="description">An introduction header for this sample</note> <note priority="1" from="meaning">User welcome</note> </trans-unit>

Note that the tool generates the id. Don't touch it. Its value depends on the content of the message and its assigned meaning. Change either factor and the id changes as well.

注意id是工具生成的。不要修改它。 它的值取决于两个因素:信息的内容和其指定的含义。 改变任何一个因素,id就会改变。

See the translation file maintenance discussion.

Translate the other text nodes the same way:

src/locale/messages.es.xlf (<trans-unit>)

<trans-unit id="ba0cc104d3d69bf669f97b8d96a4c5d8d9559aa3" datatype="html"> <source>I don&apos;t output any element</source> <target>No genero ningún elemento</target> </trans-unit> <trans-unit id="df3cf8b55cb528cf8c00167e0b119bfb828538b5" datatype="html"> <source>I don&apos;t output any element either</source> <target>Yo tampoco genero ningún elemento</target> <note priority="1" from="description">optional description</note> <note priority="1" from="meaning">optional meaning</note> </trans-unit> <trans-unit id="701174153757adf13e7c24a248c8a873ac9f5193" datatype="html"> <source>Angular logo</source> <target>Logo de Angular</target> </trans-unit>

Translate plural and select

Translating plural and select messages is a little tricky.

The <source> tag is empty for plural and select translation units, which makes them hard to correlate with the original template. The XLIFF format doesn't yet support the ICU rules. However, the XMB format does support the ICU rules.

You'll just have to look for them in relation to other translation units that you recognize from elsewhere in the source template. In this example, you know the translation unit for the select must be just below the translation unit for the logo.

Translate plural

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

src/locale/messages.es.xlf (<trans-unit>)

<trans-unit id="6e22e74e8cbd3095560cfe08993c4fdfa3c50eb0" datatype="html"> <source/> <target>{wolves, plural, =0 {ningún lobo} =1 {un lobo} =2 {dos lobos} other {una horda de lobos}}</target> </trans-unit>

Translate select

The select behaves a little differently. Here again is the ICU format message in the component template:

src/app/app.component.html

<span i18n>The hero is {gender, select, m {male} f {female}}</span>

The extraction tool broke that into two translation units.

The first unit contains the text that was outside the select. In place of the select is a placeholder, <x id="ICU">, that represents the select message. Translate the text and leave the placeholder where it is.

src/locale/messages.es.xlf (<trans-unit>)

<trans-unit id="61cafedb85466ab789b3ae817bba1a545468ee1c" datatype="html"> <source>The hero is <x id="ICU"/></source> <target>El heroe es <x id="ICU"/></target> </trans-unit>

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

src/locale/messages.es.xlf (<trans-unit>)

<trans-unit id="14c7055d67771a3b7b6888d282ac092896be06b6" datatype="html"> <source/> <target>{gender, select, m {hombre} f {mujer}}</target> </trans-unit>

Here they are together, after translation:

src/locale/messages.es.xlf (<trans-unit>)

<trans-unit id="61cafedb85466ab789b3ae817bba1a545468ee1c" datatype="html"> <source>The hero is <x id="ICU"/></source> <target>El heroe es <x id="ICU"/></target> </trans-unit> <trans-unit id="14c7055d67771a3b7b6888d282ac092896be06b6" datatype="html"> <source/> <target>{gender, select, m {hombre} f {mujer}}</target> </trans-unit>

The entire template translation is complete. It's time to incorporate that translation into the application.

The app before translation

翻译前的应用程序

When the previous steps finish, the sample app and its translation file are as follows:

如下所示,是完成前面的步骤后的例子应用它的翻译文件:

<h1 i18n="User welcome|An introduction header for this sample">Hello i18n!</h1> <ng-container i18n>I don't output any element</ng-container> <br /> <!--i18n: optional meaning|optional description --> I don't output any element either <!--/i18n--> <br /> <img [src]="logo" i18n-title title="Angular logo" /> <br> <button (click)="inc(1)">+</button> <button (click)="inc(-1)">-</button> <span i18n>{wolves, plural, =0 {no wolves} =1 {one wolf} =2 {two wolves} other {a wolf pack}}</span> ({{wolves}}) <br><br> <button (click)="male()">&#9794;</button> <button (click)="female()">&#9792;</button> <span i18n>The hero is {gender, select, m {male} f {female}}</span> <br> import { Component } from '@angular/core'; @Component({ selector: 'my-app', templateUrl: './app.component.html' }) export class AppComponent { wolves = 0; gender = 'f'; fly = true; logo = 'https://angular.io/resources/images/logos/angular/angular.png'; inc(i: number) { this.wolves = Math.min(5, Math.max(0, this.wolves + i)); } male() { this.gender = 'm'; } female() { this.gender = 'f'; } } 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 { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { AppModule } from './app/app.module'; 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="af2ccf4b5dba59616e92cf1531505af02da8f6d2" datatype="html"> <source>Hello i18n!</source> <target>¡Hola 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>No genero ningún elemento</target> </trans-unit> <trans-unit id="df3cf8b55cb528cf8c00167e0b119bfb828538b5" datatype="html"> <source>I don&apos;t output any element either</source> <target>Yo tampoco genero ningún elemento</target> <note priority="1" from="description">optional description</note> <note priority="1" from="meaning">optional meaning</note> </trans-unit> <trans-unit id="701174153757adf13e7c24a248c8a873ac9f5193" datatype="html"> <source>Angular logo</source> <target>Logo de Angular</target> </trans-unit> <trans-unit id="6e22e74e8cbd3095560cfe08993c4fdfa3c50eb0" datatype="html"> <source/> <target>{wolves, plural, =0 {ningún lobo} =1 {un lobo} =2 {dos lobos} other {una horda de lobos}}</target> </trans-unit> <trans-unit id="61cafedb85466ab789b3ae817bba1a545468ee1c" datatype="html"> <source>The hero is <x id="ICU"/></source> <target>El heroe es <x id="ICU"/></target> </trans-unit> <trans-unit id="14c7055d67771a3b7b6888d282ac092896be06b6" datatype="html"> <source/> <target>{gender, select, m {hombre} f {mujer}}</target> </trans-unit> </body> </file> </xliff>

Merge the completed translation file into the app

合并已经翻译的文件

To merge the translated text into component templates, compile the application with the completed translation file. The process is the same whether the file is in .xlf format or in another format that Angular understands, such as .xlif or .xtb.

要合并已经翻译的文件到组件模板,使用翻译过的文件编译应用。 不管文件是.xlf格式还是其他Angular接受的格式(.xlif.xtb),流程是一样的。

You provide the Angular compiler with three new pieces of information:

你要为Angular编译器提供下列三种新信息:

How you provide this information depends upon whether you compile with the JIT (Just-in-Time) compiler or the AOT (Ahead-of-Time) compiler.

你如何提供这些信息取决于你使用的是JiT(即时)编译器还是AoT(预先)编译器。

Merge with the JIT compiler

用JiT编译器合并

The JIT compiler compiles the application in the browser as the application loads. Translation with the JIT compiler is a dynamic process of:

JiT(即时)编译器在应用程序加载时,在浏览器中编译应用。 在使用JiT编译器的环境中翻译是一个动态的流程,包括:

  1. Determining the language version for the current user。

    决定当前用户的语言,

  2. Importing the appropriate language translation file as a string constant.

    导入合适的语言翻译文件到一个字符串常量,

  3. Creating corresponding translation providers to guide the JiT compiler.

    新建对应的翻译提供商来指导JiT编译器,

  4. Bootstrapping the application with those providers.

    使用这些提供商来启动应用。

Open index.html and revise the launch script as follows:

打开index.html并这样修改加载脚本:

index.html (launch script)

<script> // Get the locale id somehow document.locale = 'es'; // Map to the text plugin System.config({ map: { text: 'systemjs-text-plugin.js' } }); // Launch the app System.import('main.js').catch(function(err){ console.error(err); }); </script>

In this sample, the user's language is hardcoded as a global document.locale variable in the index.html.

在本例中,用户的语言在index.html中被硬编码到一个全局的document.locale变量中。

SystemJS text plugin

SystemJS文本插件

Notice the SystemJS mapping of text to a systemjs-text-plugin.js. With the help of a text plugin, SystemJS can read any file as raw text and return the contents as a string. You'll need it to import the language translation file.

注意SystemJS将text映射为systemjs-text-plug.js。 在这个文本插件的帮助下,SystemJS可以读取任何原始文件并将其内容作为字符串返回。 你需要使用它来导入语言翻译文件。

SystemJS doesn't ship with a raw text plugin but it's easy to add. Create the following systemjs-text-plugin.js in the src/ folder:

SystemJS没有自带原始文本插件,但是我们很容易添加它。 在src/目录新建下面的systemjs-text-plugin.js文件:

src/systemjs-text-plugin.js

/* SystemJS Text plugin from https://github.com/systemjs/plugin-text/blob/master/text.js */ exports.translate = function(load) { if (this.builder && this.transpiler) { load.metadata.format = 'esm'; return 'exp' + 'ort var __useDefault = true; exp' + 'ort default ' + JSON.stringify(load.source) + ';'; } load.metadata.format = 'amd'; return 'def' + 'ine(function() {\nreturn ' + JSON.stringify(load.source) + ';\n});'; }

Create translation providers

新建翻译提供商

Three providers tell the JIT compiler how to translate the template texts for a particular language while compiling the application:

三种提供商帮助JiT编译在编译应用时,将模板文本翻译到某种语言:

The getTranslationProviders() function in the following src/app/i18n-providers.ts creates those providers based on the user's locale and the corresponding translation file:

在下面的src/app/i18n-providers.ts文件的getTranslationProviders()函数中,根据用户的语言环境和对应的翻译文件构建这些提供商:

src/app/i18n-providers.ts

import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID } from '@angular/core'; export function getTranslationProviders(): Promise<Object[]> { // Get the locale id from the global const locale = document['locale'] as string; // return no providers if fail to get translation file for locale const noProviders: Object[] = []; // No locale or U.S. English: no translation providers if (!locale || locale === 'en-US') { return Promise.resolve(noProviders); } // Ex: 'locale/messages.es.xlf` const translationFile = `./locale/messages.${locale}.xlf`; return getTranslationsWithSystemJs(translationFile) .then( (translations: string ) => [ { provide: TRANSLATIONS, useValue: translations }, { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' }, { provide: LOCALE_ID, useValue: locale } ]) .catch(() => noProviders); // ignore if file not found } declare var System: any; function getTranslationsWithSystemJs(file: string) { return System.import(file + '!text'); // relies on text plugin }
  1. It gets the locale from the global document.locale variable that was set in index.html.

    它从在index.html中设置的全局document.locale变量中获取语言环境。

  2. If there is no locale or the language is U.S. English (en-US), there is no need to translate. The function returns an empty noProviders array as a Promise. It must return a Promise because this function could read a translation file asynchronously from the server.

    如果没有语言环境或者语言是美国英语(en-US),则就无需翻译。该函数以Promise的形式返回一个空的noProviders数组。它必须要返回Promise,因为这个函数可能异步从服务器读取翻译文件。

  3. It creates a transaction filename from the locale according to the name and location convention described earlier.

    根据上面描述的名字和本土化的约定,它根据语言环境创建一个合约文件名。

  4. The getTranslationsWithSystemJs() method reads the translation and returns the contents as a string. Notice that it appends !text to the filename, telling SystemJS to use the text plugin.

    getTranslationsWithSystemJs()方法读取翻译并以字符串的形式返回其内容。 注意它在文件名上附加!text,告诉SystemJS使用文本插件

  5. The callback composes a providers array with the three translation providers.

    回调函数使用这三种翻译提供商创建一个提供商数组。

  6. Finally, getTranslationProviders() returns the entire effort as a promise.

    最后,getTranslationProviders()返回以承诺的形式返回全部流程的结果。

Bootstrap the app with translation providers

使用翻译提供商引导应用

The Angular bootstrapModule() method has a second options parameter that can influence the behavior of the compiler.

Angular的bootstrapModule()方法接受可选的第二参数,它可以影响编译器的行为。

You'll create an options object with the translation providers from getTranslationProviders() and pass it to bootstrapModule. Open the src/main.ts and modify the bootstrap code as follows:

getTranslationProviders()返回的翻译提供商创建options对象,并将其传给bootstrapModule。 打开src/main.ts并这样修改引导代码:

src/main.ts

import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; import { getTranslationProviders } from './app/i18n-providers'; import { AppModule } from './app/app.module'; getTranslationProviders().then(providers => { const options = { providers }; platformBrowserDynamic().bootstrapModule(AppModule, options); });

Notice that it waits for the getTranslationProviders() promise to resolve before bootstrapping the app.

注意,它等待getTranslationProviders()承诺的解析完成后,才引导应用。

The app is now internationalized for English and Spanish and there is a clear path for adding more languages.

现在,应用已经被国际化为英语版和西班牙语版,而且我们有了清晰的添加更多语言的方法。

Internationalization with the AOT compiler

使用AoT编译器时的国际化

The JIT compiler translates the application into the target language while compiling dynamically in the browser. That's flexible but may not be fast enough for your users.

JiT编译器在浏览器中动态编译应用时,将其翻译到目标语言。 这样很灵活,但是对用户来讲,可能速度太慢。

The AOT (Ahead-of-Time) compiler is part of a build process that produces a small, fast, ready-to-run application package. When you internationalize with the AOT compiler, you pre-build a separate application package for each language. Then in the host web page, in this case index.html, you determine which language the user needs and serve the appropriate application package.

AoT(预先)编译器是一种构建流程,出产尺寸小、速度快和可执行的应用程序包。 在使用Aot编译器的环境中国际化,你为每种语言预先构建一个单独的应用程序包。然后,在宿主网络页面(index.html)中,你再决定用户需要哪种语言,并选择合适的应用程序包。

This cookbook doesn't cover how to build multiple application packages and serve them according to the user's language preference. It does explain the few steps necessary to tell the AOT compiler to apply a translations file.

本烹饪书不介绍如何构建多种应用程序包和如何根据用户的语言设置推送它们。 它介绍了一些必要的步骤,来告诉AoT采用翻译文件。

Internationalization with the AOT compiler requires some setup specifically for AOT compilation. Start with the application project as shown just before merging the translation file and refer to the AOT cookbook to make it AOT-ready.

使用AoT编译器时的国际化,需要一些针对AoT的设置。 以合并翻译文件之前的应用项目开始,并参见AoT烹饪书,把它变成与AoT兼容的项目。

Next, issue an ngc compile command for each supported language, including English. The result is a separate version of the application for each language.

接下来,为每种支持的语言(包括英语)运行一次ngc编译命令。 结果是每种语言都有自己单独的应用版本。

Tell AOT how to translate by adding three options to the ngc command:

通过添加下面三种选项到ngc命令来告诉AoT编译器如何翻译:

For this sample, the Spanish language command would be:

本西班牙语例子的命令为:

./node_modules/.bin/ngc --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf

Windows users may have to quote the command:

Windows用户可能需要双引号这个命令:

"./node_modules/.bin/ngc" --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf

Translation file maintenance and id changes

As the application evolves, you will change the i18n markup and re-run the ng-xi18n extraction tool many times. The new markup that you add is not a problem; but most changes to existing markup trigger generation of new ids for the affected translation units.

After an id changes, the translation files are no longer in sync. All translated versions of the application will fail during re-compilation. The error messages identify the old ids that are no longer valid but they don't tell you what the new ids should be.

Commit all translation message files to source control, especially the English source messages.xlf. The difference between the old and the new messages.xlf file help you find and update id changes across your translation files.