填寫這份《一分鐘調查》,幫我們(開發組)做得更好!去填寫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 extract-i18n 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 extract-i18n
      
      ng extract-i18n
    

xi18n 命令使用 XML 本地化交換檔案格式(XLIFF 版本 1.2)在專案的根目錄下建立一個名為 messages.xlf 的源語言檔案。

The extract-i18n 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 extract-i18n 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).

修改源語言檔案的位置

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 extract-i18n --output-path src/locale
      
      ng extract-i18n --output-path src/locale
    

修改源語言檔案格式

Change the source language file format

xi18n 命令可以用三種翻譯格式讀寫檔案:

The extract-i18n 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 extract-i18n --format=xlf ng extract-i18n --format=xlf2 ng extract-i18n --format=xmb
      
      ng extract-i18n  --format=xlf
ng extract-i18n  --format=xlf2
ng extract-i18n  --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 extract-i18n --out-file source.xlf
      
      ng extract-i18n --out-file source.xlf
    

為每種語言建立一個翻譯檔案

Create a translation file for each language

ng xi18n 命令(不帶選項時)會在專案的 src 資料夾下產生一個名為 messages.xlf 的源語言檔案。透過複製源語言檔案為每種語言建立一個翻譯檔案。為了避免混淆這麼多翻譯檔案,你應該把這些語言的翻譯檔案整理到 src/ 下的一個專用 locale 資料夾中。這些檔案使用與相關的本地環境匹配的副檔名,例如 messages.fr.xlf

The ng extract-i18n 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 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 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 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 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": { "translation": "src/locale/messages.fr.xlf", "baseHref": "" } } }, "architect": { ... } }
angular.json
      
      ...
"projects": {
  "angular.io-example": {
    ...
    "i18n": {
      "sourceLocale": "en-US",
      "locales": {
        "fr": {
          "translation": "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

多語言的典型部署方式是為不同子目錄中的每種語言提供服務。使用 HTTP 標頭 Accept-Language 將使用者重新導向到瀏覽器中定義的首選語言。如果使用者尚未定義首選語言或首選語言不可用,伺服器將回退到預設語言。使用者也可以導航到其它子目錄來更改語言,這通常使用應用中的選單實現。

Typical deployment of multiple languages serve each language from a different subdirectory. Users are redirected to the preferred language defined in the browser using the Accept-Language HTTP header. If the user has not defined a preferred language, or if the preferred language is not available, then the server falls back to the default language. Users can change the language by navigating to other subdirectories, which often occurs using a menu implemented in the application.

要了解如何把應用部署到遠端伺服器的更多資訊,請參閱部署

For more information on how to deploy apps to a remote server, see Deployment.

Nginx

下面是 Nginx 的配置範例。

The following is an example of an Nginx configuration.

http { # Browser preferred language detection (does NOT require AcceptLanguageModule) map $http_accept_language $accept_language { ~*^de de; ~*^fr fr; ~*^en en; } # ... } server { listen 80; server_name localhost; root /www/data; # Fallback to default language if no preference defined by browser if ($accept_language ~ "^$") { set $accept_language "fr"; } # Redirect "/" to Angular app in browser's preferred language rewrite ^/$ /$accept_language permanent; # Everything under the Angular app is always redirected to Angular in the correct language location ~ ^/(fr|de|en) { try_files $uri /$1/index.html?$args; } # ... }
      
      http {

    # Browser preferred language detection (does NOT require AcceptLanguageModule)
    map $http_accept_language $accept_language {
        ~*^de de;
        ~*^fr fr;
        ~*^en en;
    }
    # ...
}

server {
    listen 80;
    server_name localhost;
    root /www/data;

    # Fallback to default language if no preference defined by browser 
    if ($accept_language ~ "^$") {
        set $accept_language "fr";
    }
    
    # Redirect "/" to Angular app in browser's preferred language
    rewrite ^/$ /$accept_language permanent;

    # Everything under the Angular app is always redirected to Angular in the correct language
    location ~ ^/(fr|de|en) {
        try_files $uri /$1/index.html?$args;
    }
    # ...
}
    

Apache

下面是 Apache 的配置範例。

The following is an example of an Apache configuration.

<VirtualHost *:80> ServerName localhost DocumentRoot /www/data <Directory "/www/data"> RewriteEngine on RewriteBase / RewriteRule ^../index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule (..) $1/index.html [L] RewriteCond %{HTTP:Accept-Language} ^de [NC] RewriteRule ^$ /de/ [R] RewriteCond %{HTTP:Accept-Language} ^en [NC] RewriteRule ^$ /en/ [R] RewriteCond %{HTTP:Accept-Language} !^en [NC] RewriteCond %{HTTP:Accept-Language} !^de [NC] RewriteRule ^$ /fr/ [R] </Directory> </VirtualHost>
      
      <VirtualHost *:80>
    ServerName localhost
    DocumentRoot /www/data
    <Directory "/www/data">
        RewriteEngine on
        RewriteBase /
        RewriteRule ^../index\.html$ - [L]
        
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteCond %{REQUEST_FILENAME} !-d
        RewriteRule (..) $1/index.html [L]
        
        RewriteCond %{HTTP:Accept-Language} ^de [NC]
        RewriteRule ^$ /de/ [R]
        
        RewriteCond %{HTTP:Accept-Language} ^en [NC]
        RewriteRule ^$ /en/ [R]
        
        RewriteCond %{HTTP:Accept-Language} !^en [NC]
        RewriteCond %{HTTP:Accept-Language} !^de [NC]
        RewriteRule ^$ /fr/ [R]
    </Directory>
</VirtualHost>
    

瀏覽已翻譯的範例應用

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