Angular2 >

Angularで国際化対応

国際化の方法

やり方はいくつかあって、大きく以下の2つに分けられる

  • Angular標準の国際化対応を利用する
  • ngx-translate 等の他のライブラリを利用する

2つの方法を比較した所感

ngx-translate の方が全然使いやすい。

Angular標準

Angular標準の方は、翻訳対象箇所が増える度に、翻訳用のファイルを生成し直す必要がある為、メンテナンス性は良くない。
また、翻訳用のファイルを生成し直した時に、既存の翻訳ファイルの内容を手動でマージする必要があり、かなり手間。
動的な言語切替も出来ない為、それぞれの言語用にビルドを行い、リソース自体を切り替える手法を取るしかなさそう。

ngx-translate

単純な翻訳ならテンプレートの記述がシンプル。(タグに "translate" 属性を付けるだけ)
翻訳辞書もjson記述で、ネストにも対応している為、ページやカテゴリ毎に分類して管理もできそう。
また、動的な言語切替にも対応しており、切り替え方法もシンプル。( TranslateServiceの useメソッドを呼ぶだけ )
無理やりデメリットを挙げるとしたら、言語ファイル(json)の切り替えを行う際に、HTTP通信が発生する事ぐらいだが、
通信が発生するのは最初の1回のみなので、全く気にならない。(サイズが大きくなる場合の確認は必要かもしれないが。)

準備

ng new my-app && cd my-app
ng generate component header
ng generate component top
ng generate component page1
ng generate component page2

src/app/app.module.ts

.
+ import { RouterModule } from '@angular/router';
.
.
@NgModule({
  declarations: [
    AppComponent,
    HeaderComponent,
    TopComponent,
    Page1Component,
    Page2Component
  ],  
  imports: [
    BrowserModule,
+   RouterModule.forRoot([
+    { path: 'top', component: TopComponent },
+    { path: 'page1', component: Page1Component },
+    { path: 'page2', component: Page2Component }
+   ], { useHash: true })
  ],  
  providers: [], 
  bootstrap: [AppComponent]
})
export class AppModule { } 

src/app/app.component.html

<!-- headerコンポーネント -->
<app-header></app-header>

<!-- ルーターがコンポーネントを表示する場所 -->
<div id="content">
  <router-outlet></router-outlet>
</div>

src/app/header/header.component.html

<a routerLink="/top" routerLinkActive="active">Top</a>
<a routerLink="/page1" routerLinkActive="active">page1</a>
<a routerLink="/page2" routerLinkActive="active">page2</a>

Angular標準の国際化対応を利用する場合

Internationalization (i18n) として、公式ドキュメント(※)に記載されている。
https://angular.io/guide/i18n

テンプレートの翻訳対象箇所を修正する

翻訳対象のタグに i18n="@@xxx" を追加する

src/app/header/header.component.html

<a routerLink="/top" routerLinkActive="active" i18n="@@top">Top</a>
<a routerLink="/page1" routerLinkActive="active" i18n="@@page1">page1</a>
<a routerLink="/page2" routerLinkActive="active" i18n="@@page2">page2</a>

翻訳ソースファイルを生成する

ng xi18n --outputPath src/locale
ls -1 src/locale/
messages.xlf

翻訳ソースファイルをコピーして日本語用のファイルを作成

cp src/locale/messages.xlf src/locale/messages.ja.xlf

翻訳内容を記載する

src/locale/messages.ja.xlf

<?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="top" datatype="html">
        <source>Top</source>
+       <target>トップ</target>
        <context-group purpose="location">
          <context context-type="sourcefile">app/header/header.component.ts</context>
          <context context-type="linenumber">1</context>
        </context-group>
      </trans-unit>
      <trans-unit id="page1" datatype="html">
        <source>page1</source>
+       <target>ページ1</target>
        <context-group purpose="location">
          <context context-type="sourcefile">app/header/header.component.ts</context>
          <context context-type="linenumber">2</context>
        </context-group>
      </trans-unit>
      <trans-unit id="page2" datatype="html">
        <source>page2</source>
+       <target>ページ2</target>
        <context-group purpose="location">
          <context context-type="sourcefile">app/header/header.component.ts</context>
          <context context-type="linenumber">3</context>
        </context-group>
      </trans-unit>
    </body>
  </file>
</xliff>

ローカルサーバ起動

ng serve --aot --i18nFile=src/locale/messages.ja.xlf --i18nFormat=xlf --locale=ja

ビルド

ng build --aot --i18nFile=src/locale/messages.ja.xlf --i18nFormat=xlf --locale=ja --output-path=/path_to_www/angular2-ja --bh /angular2-ja/

動的に切り替える場合

動的に言語を切り替える方法で見つかったのは、それぞれの言語用にビルドして別のディレクトリに配意するやり方だけだった。
https://medium.com/@feloy/deploying-an-i18n-angular-app-with-angular-cli-fc788f17e358

ng build --aot --i18nFile=src/locale/messages.en.xlf --i18nFormat=xlf --locale=en --output-path=/path_to_www/angular2-en --bh /angular2-en/
ng build --aot --i18nFile=src/locale/messages.ja.xlf --i18nFormat=xlf --locale=ja --output-path=/path_to_www/angular2-ja --bh /angular2-ja/
ng build --aot --i18nFile=src/locale/messages.fr.xlf --i18nFormat=xlf --locale=fr --output-path=/path_to_www/angular2-fr --bh /angular2-ja/


ngx-translateを利用する場合

https://github.com/ngx-translate/core

インストール

npm install @ngx-translate/core --save
npm install @ngx-translate/http-loader --save

ローダーを使用して翻訳できるようにソース変更

src/app/app.module.ts

 .
 .
+ import {HttpClientModule, HttpClient} from '@angular/common/http';
+ import {TranslateModule, TranslateLoader} from '@ngx-translate/core';
+ import {TranslateHttpLoader} from '@ngx-translate/http-loader';
 .
 .

+ export function createTranslateLoader(http: HttpClient) {
+     return new TranslateHttpLoader(http, './assets/i18n/', '.json');
+ }

@NgModule({
    .
    .
  imports: [
      .
      .
+    HttpClientModule,
+    TranslateModule.forRoot({
+        loader: {
+            provide: TranslateLoader,
+            useFactory: (createTranslateLoader),
+            deps: [HttpClient]
+        }
+    }), 
      .
      .

src/environments/environment.ts

export const environment = { 
  production: false,
+  defaultLang: 'en'
};

src/app/app.component.ts

+import {TranslateService} from '@ngx-translate/core';
+import { environment } from '../environments/environment';

export class AppComponent {
  title = 'app';
+  constructor(private translate: TranslateService) {
+    translate.setDefaultLang(environment.defaultLang);
+    translate.use(environment.defaultLang);
+  }
}

辞書ファイルの作成

mkdir -p src/assets/i18n

src/assets/i18n/en.json

{
    "top":"top",
    "page1":"page1",
    "page2":"page2"
}

src/assets/i18n/ja.json

{
    "top":"トップ",
    "page1":"ページ1",
    "page2":"ページ2"
}

HTMLテンプレートを修正

タグの内容をそのまま翻訳する場合は translate 属性をつけるだけでOK。
spanなどのインライン要素をうまく利用すれば、殆どこれだけでいけそう。

src/app/header/header.component.html

<a routerLink="/top" routerLinkActive="active" translate>top</a>
<a routerLink="/page1" routerLinkActive="active" translate>page1</a>
<a routerLink="/page2" routerLinkActive="active" translate>page2</a>

※その他のケースは https://github.com/ngx-translate/core を参照。

サーバ起動

普通にサーバを起動するだけ

ng serve

動的に切り替える場合

TranslateService.use で普通に切り替えられる
ここでは、ヘッダに言語切替用のプルダウンを用意して動的に切り替えられるようにする。

src/environments/environment.ts

export const environment = { 
  production: false,
  defaultLang: 'en',
+ languages: [ {'lang': 'en', 'label': 'English'}, {'lang': 'ja', 'label': 'Japanese'} ]
};

src/app/header/header.component.html[

<select (change)="changeLang($event.target.value)">
<option *ngFor="let lang of languages; let i = index;" [value]="lang.lang" [selected]="isCurrentLang(lang.lang)">
<span translate>{{lang.label}}</span>
</option>
</select>

src/assets/i18n/en.json

{
    "English": "English",
    "Japanese": "Japanese",
    "top":"Top",
    "page1":"Page1",
    "page2":"Page2"
}

src/assets/i18n/ja.json

{
    "English": "英語",
    "Japanese": "日本語",
    "top":"トップ",
    "page1":"ページ1",
    "page2":"ページ2"
}

src/app/header/header.component.ts

import {TranslateService} from '@ngx-translate/core';
import { environment } from '../../environments/environment';

export class HeaderComponent implements OnInit {
  .
  .

+  languages = environment.languages;
+  currentLang: string = environment.defaultLang;
+  constructor(private translate: TranslateService) {}
+
+  changeLang(lang){
+    if (lang !== this.currentLang) {
+      this.translate.use(lang);
+      this.currentLang = lang;
+    }   
+  }
+
+  isCurrentLang(lang){
+    return lang === this.currentLang;
+  }


トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2018-02-24 (土) 23:11:13 (2250d)