angular.io Guide: Internationalization (i18n)

これは、Angular の公式ドキュメントの [Internationalization (i18n)](https://angular.io/guide/i18n) の章を意訳したものです｡所々抜け落ち、翻訳モレがありますがあしからずご了承を｡
バージョン 4.3.4 のドキュメントをベースにしています｡

# Internationalization (i18n)

Angularの国際化ツール（i18n）は、アプリを複数の言語で利用できるようにします。

スペイン語に翻訳された、JITコンパイルされたアプリケーションの[ライブサンプル](https://angular.io/generated/live-examples/i18n/eplnkr.html)/[サンプルダウンロード](https://angular.io/generated/zips/i18n/i18n.zip)を試してみてください。

## Angularとi18nテンプレートの翻訳

アプリケーションの国際化は、献身と永続的なコミットメントを必要とする、チャレンジングで多面的な取り組みです。Angularの国際化機能が役立ちます。

このページでは、コンポーネントテンプレートテキストの複数の言語への翻訳を支援するために利用できるi18nツールについて説明します。

国際化の実践者は、翻訳可能なテキストを「メッセージ」と呼んでいます。このページでは、「テキスト」と「メッセージ」という言葉を区別なく使用し、「テキストメッセージ」の組み合わせで使用します。

i18nテンプレートの翻訳プロセスには4つのフェーズがあります。

1. コンポーネントテンプレートの静的テキストメッセージを翻訳用にマークします。
2. Angularのあるi18nツールはマークされたメッセージを業界標準翻訳ソースファイルに抽出します。
3. 翻訳者がそのファイルを編集し、抽出されたテキストメッセージをターゲット言語に翻訳し、それをあなたに返します。
4. Angularコンパイラは、完成した翻訳ファイルをインポートし、元のメッセージを翻訳されたテキストに置き換え、ターゲット言語で新しいバージョンのアプリケーションを生成します。

サポートされている言語ごとに別々のバージョンのアプリケーションをビルドして展開する必要があります。

## i18n属性のテキストにマークを付ける

Angular i18n属性は、翻訳可能なコンテンツのマーカーです。固定テキストを翻訳する必要のあるすべての要素タグに配置します。

i18nはAngularディレクティブではありません。 Angularツールやコンパイラによって認識されるカスタム属性です。変換後、コンパイラはそれを削除します。
付随するサンプルでは、​​`<h1>` タグはスペイン語に翻訳される簡単な英語の挨拶を表示します。

*src/app/app.component.html*

```
<h1>Hello i18n!</h1>
```

`i18n`属性をタグに追加して、翻訳用にマークします。

*src/app/app.component.html*

```
<h1 i18n>Hello i18n!</h1>
```


### *description*と*meaning*で翻訳者を助ける

翻訳者がテキストを適切に翻訳するために、補足説明を必要とするかもしれません。その場合は、`i18n`属性に説明を割り当てることができます。

*src/app/app.component.html*

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

正しい翻訳を提供するために、翻訳者は、この特定のアプリケーションの文脈内のテキストの意味または意図を知る必要があり得る。

意味を持つ文字列を始めることによってコンテキストを追加し、`|` 文字（`<meaning>|<description>`）:

*src/app/app.component.html*

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

同じ意味を持つメッセージの出現はすべて同じ翻訳をしますが、さまざまな意味のメッセージが異なる翻訳を持つ可能性があります。Angular 抽出ツールは、翻訳ソースファイルの意味と説明の両方を保存して、文脈に特有の翻訳を容易にします。

### 検索と保守を改善するカスタム*ID*を設定する

Angular i18n抽出ツールは、テンプレート内のi18n属性ごとに翻訳単位エントリを含むファイルを生成します。デフォルトでは、各翻訳単位に次のような一意のIDを割り当てます。

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

この`id`は、人間が読んだり覚えたりするのが難しく、難しいものです。

さらに悪い話として、例えばタイプミスを修正するために翻訳可能なテキストを変更を加えると、抽出ツールがその翻訳の新しいIDを生成します。新しいIDで更新しない限り、翻訳は失われます。そのためメンテナンスは複雑なものになります。

この問題を回避するには、独自の意味のあるIDを`i18n`属性に指定することをお勧めします。プレフィックスは`@@`です。

*app/app.component.html*

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

これで、抽出ツールとコンパイラはカスタムIDを持つtrans-unitを生成するので、idを変更することはありません。

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

ここに定義を持つ`i18n`属性があり、その後にカスタム`id`が続きます。

*app/app.component.html*

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

ここに意味と説明と最後に*id*があります：

*app/app.component.html*

```
<h1 i18n="site header|An introduction header for this sample@@introductionHeader">Hello i18n!</h1>
```

> 一意のカスタムIDを必ず定義してください。2つの異なるテキストブロックに同じidを使用すると、最初の方だけ読み込まれて、両方のテキストブロックで表示されることになります。
> 
> 例えば：
> 
> ```
> <p i18n="@@myId">Hello</p>
> <p i18n="@@myId">Good bye</p>
> ```
> 
> 翻訳では：
> 
> ```
> <trans-unit id="myId" datatype="html">
>  <source>Hello</source>
>  <target state="new">Hola</target>
> </trans-unit>
> ```
> 
> 両方の`<p>`要素には、テキスト`Hola`が含まれます。

### 要素を作成せずにテキストを翻訳する

翻訳したいテキストがあるとします。`<span>`タグでそれを囲むこともできますが、何らかの理由で（例えば、CSSに対する恐れ）、翻訳を容易にするために新しいDOM要素を作成したくないケースもあるでしょう。

試すには2つの方法があります。

(1) `<ng-container>` 要素にテキストをラップします。`<ng-container>` はレンダリングされません：

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

(2) テキストをHTMLコメントのペアで囲みます。

*src/app/app.component.html*

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

## *i18n* translation属性を追加する

テンプレートに画像を追加しました。あなたはアクセシビリティにも気を配り、title属性を追加したとしましょう：

*src/app/app.component.html*

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

こうなると、`title`属性を翻訳する必要があります。Angular i18nサポートには、より多くの変換を行える属性として`i18n-x`があります。ここでの `x` は変換する属性の名前です。 前の例の`img`タグのタイトルを翻訳するには、次のように記述します。

*src/app/app.component.html*

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

また、`i18n-x="<meaning>|<description>"` の構文で意味と説明を割り当てることもできます。

## 単数形と複数形を扱う

言語にはそれぞれ異なる単数形・複数形のルールがあります。

あなたのアプリケーションがオオカミのコレクションについて何かを言うとします。 英語では、オオカミの数に応じて、 "no wolves", "one wolf", "two wolves", もしくは "a wolf pack" と表示できます。他の言語では、カーディナリティが異なって表現されることがあります。

オオカミの数に適したフレーズを表示するためにコンポーネントテンプレートをマークアップする方法は次のとおりです。

*src/app/app.component.html*

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

- 最初のパラメータはキーです。 これは、オオカミの数を決定するコンポーネントプロパティ（`wolves`）に拘束されています。
- 第2のパラメータ`plural`は、これを複数の翻訳タイプとして識別します。
- 第3のパラメータは、複数のカテゴリとその一致する値からなる複数のパターンを定義します。

複数のカテゴリには、下記のものが含まれています

- =0 (もしくは0以外の他の数値)
- zero
- one
- two
- few
- many

複数のカテゴリの横にある括弧（`{}`）でデフォルトの英語の翻訳を配置できます。

- あなたが1つのオオカミについて話しているとき、`=1` {1つのオオカミ}と書くことができます。
- 0オオカミの場合、`=0` {オオカミなし}と書くことができます。
- 2つのオオカミにとって、あなたは `=2` {2つのオオカミ}と書くことができます。

あなたは3, 4、および他の数のオオカミのためにこれを保持することができます。あるいは、他のカテゴリーを、他に類のない基数のキャッチオールとして指定して、他の{a wolf pack}のように書くことができます。

この構文は、複数化規則を指定するCommon Locale Data Repository（CLDR）から派生したICUメッセージフォーマットに準拠しています。

## 代替テキストから選択する

ヒーローが男性か女性かによって、アプリケーションは異なるテキストを表示する必要があります｡これらは代替テキストとして翻訳が必要です。

翻訳の選択でこれを処理できます。[ICUのメッセージ構文](http://userguide.icu-project.org/formatparse/messages)の後にもselectが続きます。数値の代わりに文字列値に基づいて代替翻訳を選択します。

コンポーネントテンプレートの次の形式メッセージは、コンポーネントの`gender`プロパティにバインドされ、 "m"または "f"のいずれかを出力します。メッセージは、これらの値を適切な翻訳にマッピングします。

*src/app/app.component.html*

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

## 複数形と選択式を組み合わせる

異なるICU式を一緒にネストすることもできます。例えば：

*src/app/app.component.html*

```
<span i18n>Here we have: {count, plural,
  =0 {no one}
  =1 {one {gender, select, male {man} female {woman}}}
  other {{{heroes.length}} {gender, select, male {men} female {women}}}
}</span>
```

## `ng-xi18n`ツールを使用して翻訳ソースファイルを作成する

ng-xi18n抽出ツールを使用して、業界標準形式の翻訳ソースファイルにi18nマークのテキストを抽出します。

これは、`@angular/compiler-cli` npmパッケージのAngular CLIツールです。 CLIとそのプラットフォームとサーバー間のPeer Dependenciesをまだインストールしていない場合は、ここで実行してください。

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

アプリケーションプロジェクトのルートにあるターミナルウィンドウを開き、`ng-xi18n`コマンドを入力します。

```
./node_modules/.bin/ng-xi18n
```

> Windowsユーザーは次のようにコマンドを引用する必要があります。`"./node_modules/.bin/ng-xi18n"`

デフォルトでは、[XML ローカリゼーションインターチェンジ ファイル フォーマット（XLIFF、バージョン1.2）](https://en.wikipedia.org/wiki/XLIFF) に準拠した`messages.xlf` という名前の変換ファイルが生成されます。

### その他の翻訳フォーマット

Angular i18nツールは、XLIFF 1.2とXLIFF 2、およびXML Message Bundle（XMB）をサポートしています。

これらのコマンド例に示すように、`-i18nFormat` フラグを使用して明示的にフォーマットの選択を指定することができます。

```
./node_modules/.bin/ng-xi18n  --i18nFormat=xlf  --outFile=messages.xlf
./node_modules/.bin/ng-xi18n  --i18nFormat=xlf2 --outFile=messages.xliff2.xlf
./node_modules/.bin/ng-xi18n  --i18nFormat=xmb  --outFile=messages.xmb
```

このガイドのサンプルは、デフォルトのXLIFF 1.2形式を採用しています。

### その他のオプション

追加のオプションを指定する必要があるかもしれません。たとえば、tsconfig.json TypeScript構成ファイルがルートフォルダ以外の場所にある場合は、`-p` オプションを使用してパスを指定する必要があります。

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

利便性のためにnpmスクリプトを追加する

コマンドを覚えやすく実行するために、`package.json`の`scripts`セクションに便利なショートカットを追加することを検討してください。

```
"scripts"：{
  "i18n"： "ng-xi18n"、
  ...
}
```

これで、次のようなコマンドバリエーションを発行できます。

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

オプションの前に `--` フラグを付与することに注意してください。`ng-xi18n`にすべてのフラグを渡すようにnpmに指示します。

## テキストメッセージを翻訳する

`ng-xi18n`コマンドは、プロジェクトルートフォルダ`messages.xlf`に翻訳ソースファイルを生成します。次のステップは、英語のテンプレートテキストを特定の言語翻訳ファイルに翻訳することです。ガイドサンプルはスペイン語の翻訳ファイルを作成します。

### ローカリゼーションフォルダを作成する

おそらく複数の言語に翻訳されるので、プロジェクト構造があなたの国際化の成果全体を反映することは良いアイデアです。

1つのアプローチは、フォルダをローカリゼーション専用にして、国際化ファイルなどの関連するアセットをそこにまとめて格納することです。

ローカリゼーションとインターナショナリゼーションは異なりますが、密接に関連する用語です。

このガイドはその提案に従います。 `src/` の下にロケールフォルダがあります。フォルダー内のアセットは、よく知られているコードセットの言語文化コードに一致するファイル名拡張子を持ちます。

`messages.xlf`ファイルのコピーを作成し、ロケールフォルダに置き、スペイン語の`messages.es.xlffor`という名前に変更します。それぞれのターゲット言語について同じことをします。

### テキストノードを翻訳する

現実の世界では、`messages.es.xlf`ファイルをスペイン語の翻訳者に送信し、多数あるXLIFFファイルエディタを使用して翻訳を入力していきます。

このサンプルファイルは、特別な編集者やスペイン語の知識がなければ翻訳が簡単です。 `messages.es.xlf`を開き、最初の`<trans-unit>`セクションを見つけます：

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

```
<trans-unit id="introductionHeader" 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>
```

このXML要素は、`i18n`属性でマークした`<h1>`挨拶タグの翻訳を表します。

> translation unit `id=introductionHeader`は、以前に設定した[カスタムID](https://angular.io/guide/i18n#custom-id)から派生したものですが、ソースHTMLに** @@ プレフィックスは不要**です。

source、description、およびmeaning要素を使用して翻訳をガイドするには、`<target/>` タグをスペイン語の挨拶に置き換えます。

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

```
<trans-unit id="introductionHeader" 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>
```

他のテキストノードも同じ方法で翻訳します。

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

> ツールは、これらの翻訳単位ごとに`id`を生成しました。**それらは編集しないでください。** 各`id`は、メッセージの内容と割り当てられた意味に依存します。factorと`id`の変更も同様に変更してください。 [翻訳ファイルのメンテナンスについては、説明を参照](https://angular.io/guide/i18n#maintenance)してください。
> 
> このため、[カスタムIDを指定](https://angular.io/guide/i18n#custom-id)して、ツールがIDを自動生成するのを回避する必要があります。

## *複数形*と*選択肢*を翻訳

`<source>`タグは、複数の翻訳単位と選択された翻訳単位では空白なため、元のテンプレートとの関連付けが困難です。`XLIFF`形式はまだICUルールをサポートしていません。ただし`XMB`形式はICUルールをサポートしています。

ソーステンプレートの他の場所から認識している他の翻訳単位に関して、それらを探すだけで済みます。この例では、`select`の翻訳単位は、ロゴの翻訳単位のすぐ下になければなりません。

### 複数形を翻訳する

複数形を翻訳するには、そのICU形式の一致値を翻訳します。

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

### 選択肢を翻訳する

`select`の動作は少し異なります。ここでも、コンポーネントテンプレートのICU形式メッセージがあります。

*src/app/app.component.html*

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

抽出ツールはそれを2つの翻訳単位に分割しました。

最初の単位には、選択範囲外のテキストが含まれています。 selectの代わりに、選択メッセージを表すプレースホルダ`<x id="ICU">`があります。 テキストを翻訳し、プレースホルダをそのままにしておきます。

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

最初の翻訳ユニットのすぐ下にある第2の翻訳ユニットは、`select `メッセージを含んでいます。これを翻訳してみましょう｡

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

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

ここで彼らは一緒にいます｡翻訳後を見てみましょう：

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


## ネストされた式を翻訳する

ネストされた式は前の式と変わりません。前の例と同様に、2つの翻訳単位があります。
最初の例は、ネストされた式の外側のテキストが含まれます。

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

```
<trans-unit id="2cf9a08c5b6e3612572a2a36dd46563013848382" datatype="html">
  <source>Here we have: <x id="ICU"/></source>
  <target>Aquí tenemos: <x id="ICU"/></target>
</trans-unit>
```

2番目のユニットには、完全なネストされた式が含まれます。

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

```
<trans-unit id="db1b921b55301ce3957e382090729562002da036" datatype="html">
  <source/>
  <target>
    {count, plural,
      =0 { nadie }
      =1 {{gender, select, m {un hombre} f {una mujer}}}
      other {{{heroes.length}} {gender, select, m {hombres} f {mujeres}}}
    }
  </target>
</trans-unit>
```

両方を見てみましょう:

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

```
<trans-unit id="2cf9a08c5b6e3612572a2a36dd46563013848382" datatype="html">
  <source>Here we have: <x id="ICU"/></source>
  <target>Aquí tenemos: <x id="ICU"/></target>
</trans-unit>
<trans-unit id="db1b921b55301ce3957e382090729562002da036" datatype="html">
  <source/>
  <target>
    {count, plural,
      =0 { nadie }
      =1 {{gender, select, m {un hombre} f {una mujer}}}
      other {{{heroes.length}} {gender, select, m {hombres} f {mujeres}}}
    }
  </target>
</trans-unit>
```

テンプレートの翻訳全体が完了しました｡いよいよ翻訳をアプリケーションに組み込む時です。

## 翻訳前のアプリ

前の手順が完了すると、サンプルアプリとその翻訳ファイルは次のようになります。

> *ソースは省略します｡[こちらを参照](https://angular.io/guide/i18n#the-app-before-translation)してください*

## 完成した翻訳ファイルをアプリケーションにマージする

翻訳されたテキストをコンポーネントテンプレートにマージするには、完成した翻訳ファイルでアプリケーションをコンパイルします。このプロセスは、ファイルが`.xlf`形式であるか、Angularが理解できる別の形式（`.xtb`など）であっても同じです。

Angularコンパイラには、次の3つの新しい情報が提供されます。

- 翻訳ファイル
- 翻訳ファイルフォーマット
- [Locale ID](https://en.wikipedia.org/wiki/XLIFF)（たとえば、`en`または`en-US`）

この情報の提供方法は、JIT（Just-In-Time）コンパイラまたはAOT（Ahead-of-Time）コンパイラでコンパイルするかどうかによって異なります。

- JITでは、ブートストラップ時に情報を提供します。
- AOTを使用するときは、情報を`ngc`オプションとして渡します。

### JITコンパイラとのマージ

JITコンパイラは、アプリケーションのロード時にブラウザでアプリケーションをコンパイルします。 JITコンパイラを使用した翻訳は、次のような動的プロセスです。

1. 現在のユーザーの言語バージョンを確認します。
1. 適切な言語翻訳ファイルを文字列定数としてインポートする。
1. 対応する翻訳プロバイダを作成して、JITコンパイラをガイドします。
1. これらのプロバイダを使用してアプリケーションをBootstrapします。

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

このサンプルでは、​​ユーザーの言語は、index.htmlのglobal document.locale変数としてハードコードされています。

### SystemJS テキストプラグイン

> このプラグインは、SystemJSを使用するアプリケーションにのみ適用されます。Angular CLIを使用している場合は、[ドキュメントを参照](https://github.com/angular/angular-cli/wiki/xi18n)してください。

`systemjs-text-plugin.js`へのテキストのSystemJSマッピングに注目してください。 テキストプラグインの助けを借りて、SystemJSは任意のファイルを生のテキストとして読み込み、その内容を文字列として返すことができます。 言語翻訳ファイルをインポートする必要があります。

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});';
}
```

### translation providersを作成する

3つのプロバイダは、アプリケーションのコンパイル中に特定の言語のテンプレートテキストを翻訳する方法をJITコンパイラに指示します。

- `TRANSLATIONS`は、翻訳ファイルの内容を含む文字列です。
- `TRANSLATIONS_FORMAT`は、`xlf`、`xlf2`、または`xtb`のファイル形式です。
- `LOCALE_ID`は、ターゲット言語のロケールです。

次の`src/app/i18n-providers.ts`の`getTranslationProviders()`関数は、ユーザーのロケールと対応する変換ファイルに基づいてこれらのプロバイダを作成します。

*src/app/i18n-providers.ts*

```
import { TRANSLATIONS, TRANSLATIONS_FORMAT, LOCALE_ID, MissingTranslationStrategy } from '@angular/core';
import { CompilerConfig } from '@angular/compiler';

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. これは、`index.html`で設定されたグローバル`document.locale`変数からロケールを取得します。
1. ロケールが存在しない場合、または言語が米国英語（`en-US`）の場合、翻訳する必要はありません。この関数は空の`noProviders`配列を`Promise`として返します。この関数は、サーバーから変換ファイルを非同期に読み取る可能性があるため、`Promise`を返す必要があります。
1. [前述の](https://angular.io/guide/i18n#localization-folder)名前と場所の規則に従って、ロケールからトランザクションファイル名を作成します。
1. `getTranslationsWithSystemJs()`メソッドは変換を読み取り、その内容を文字列として返します。テキストがファイル名に追加され、[テキストプラグイン](https://angular.io/guide/i18n#text-plugin)を使用するようにSystemJSに通知します。
1. コールバックは、3つの翻訳プロバイダを使用してプロバイダ配列を構成します。
1. 最後に、`getTranslationProviders()`はすべての努力を約束として返します。

> `LOCALE_ID`は、[ここ](http://userguide.icu-project.org/locale)で説明する有効なロケールIDでなければなりません。

### translation providers の Bootstrap

Angular `bootstrapModule()`メソッドには、コンパイラの動作に影響する可能性のある第2のオプションパラメータがあります。

`getTranslationProviders()`の翻訳プロバイダを使用してオプションオブジェクトを作成し、それを`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);
});
```

アプリケーションを起動する前に`getTranslationProviders()`が解決するのを待つことに注意してください。

アプリは現在英語とスペイン語で国際化されており、さらに多くの言語を追加する明確な道があります。

### AOTコンパイラによる国際化

JITコンパイラは、ブラウザで動的にコンパイルしながら、アプリケーションをターゲット言語に変換します。柔軟性はありますが、ユーザーにとっては十分に速いとは限りません。

AOT（Ahead-of-Time）コンパイラは、小型で高速ですぐに実行できるアプリケーションパッケージを作成するビルドプロセスの一部です。 AOTコンパイラーで国際化すると、言語ごとに個別のアプリケーション・パッケージが事前にビルドされます。次に、ホストWebページ（この場合はindex.html）で、ユーザーが必要とする言語を決定し、適切なアプリケーションパッケージを提供します。

このガイドでは、複数のアプリケーションパッケージを作成し、ユーザーの言語設定に従ってそれらを提供する方法については説明しません。これは、AOTコンパイラに翻訳ファイルを適用するよう指示するために必要ないくつかのステップを説明しています。

AOTコンパイラーによる国際化には、AOTコンパイル専用の設定が必要です。[翻訳ファイルをマージする直前に](https://angular.io/guide/i18n#app-pre-translation)示すように、アプリケーションプロジェクトから始め、[AOTガイド](https://angular.io/guide/aot-compiler)を参照してAOT対応にしてください。

次に、英語を含むサポートされている言語ごとに`ngc compile`コマンドを実行します。その結果、言語ごとに別々のバージョンのアプリケーションが作成されます。

`ngc`コマンドに3つのオプションを追加して翻訳する方法をAOTに伝えてください：

`--i18nFile`：翻訳ファイルへのパス。
`--locale`：ロケールの名前。
`--i18nFormat`：ローカリゼーションファイルの形式。

このサンプルでは、​​スペイン語のコマンドは次のようになります。

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

> Windowsユーザーはコマンドを引用する必要があります：
> 
> ```
> "./node_modules/.bin/ngc" --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf
> ```

### 不足している翻訳をレポートする

翻訳を提供するのを忘れてしまった場合、簡単に間違っているかもしれないという警告とともにビルドが成功します。Angularコンパイラは、さまざまな「missing translation」ビヘイビアに対して構成できます。

- Error エラー
- Warning 警告（デフォルト）
- Ignore 無視

JITの動作を変更するには、次の構成を使用します。

```
{ provide: CompilerConfig, useValue: new CompilerConfig({ missingTranslation: MissingTranslationStrategy.Error }) }
```

これを使用する良い場所は翻訳プロバイダです：

*src/app/i18n-providers.ts*

```
return getTranslationsWithSystemJs(translationFile)
  .then( (translations: string ) => [
    { provide: TRANSLATIONS, useValue: translations },
    { provide: TRANSLATIONS_FORMAT, useValue: 'xlf' },
    { provide: LOCALE_ID, useValue: locale },
    { provide: CompilerConfig, useValue: new CompilerConfig({ missingTranslation: MissingTranslationStrategy.Error }) }
  ])
  .catch(() => noProviders); // ignore if file not found
```

AOTの動作を変更するには、`--missingTranslation` フラグをcompilationコマンドに追加します。

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

## ファイルのメンテナンスと*id*の変更

アプリケーションが進化するにつれて、*i18n*マークアップを変更し、`ng-xi18n`抽出ツールを何度も再実行します。追加する新しいマークアップは問題ではありません。しかし、`id`は*深刻な問題になる*可能性があります！

`id`がツールによって生成された場合、*既存の*マークアップを変更すると、影響を受ける翻訳単位の新しい`id`が生成されます。

`id`が変更されると、変換ファイルは同期しなくなります。そのため、再コンパイル時に警告メッセージが表示されます。警告メッセージには、一部の翻訳が欠落していることが示されていますが、古い`id`がもう有効ではないことはわかりません。

[カスタムID](https://angular.io/guide/i18n#custom-id)を使用する場合、対応する翻訳単位を変更する際にツールでカスタムIDが保持されます。**他に行う理由がない限り、カスタム`id`を使用してください。**

生成IDまたはカスタムIDのどちらを使用する場合でも、**すべての翻訳メッセージファイルをソース管理にコミットしてください**（特に英語のソース`messages.xlf`）｡古い`messages.xlf`ファイルと新しい`messages.xlf`ファイルの違いは、翻訳ファイル全体で`id`やその他の変更を見つけて更新するのに役立ちます。