AngularJSとAngularJSモジュールでi18nを実現する(2) 

AngulaｒJSとAngular Translatorを利用したI18nの実現をテーマにした投稿の2回目になります。

今回実際にTutorialのstep-9の仕組みを元にスマホ詳細画面のI18n対応を実現します。
実現したソースはgithub上に公開します。

https://github.com/abikoka/angular-test.git

## 設計方針

今回、目的はI18nを実現する方法についてAngular Tranlatorでどのように実装するかを考えるところに焦点を置きます。
そのため、フィーチャ部分はTutorialをそのまま利用します。

### Database(jsonファイル)

step-9の任意のPhone詳細データ(motorola-xoom.json)を流用して、locate ID別に2種類(enとｊｐ)を用意。
その際のURIは下記とする。

URI: /locale/:localeId/phones/:phoneId.json
（実ファイルはapp/locale以下にパス通りに保存します。)

### 画面仕様

* step-9の詳細画面そのまま。
* ボタンでlocale IDを切り替えるようにする。
* 表示項目名の部分がlocale IDに合わせて切り替わる。
* データの表示もlocale IDに合わせて取得URIが切り替わり、表示が切り替わる


### 作成結果レポート

Angular Translatorは想像以上に使いやすく、実装自体はデバッグ作業を除くと、作業時に要した時間のほぼすべてがTemplateとデータを変換用に作成することだけでした。

行ったことを順にご説明します。

#### AngularのTutorial step-9のソースを取り込む

ベースはAngularのTutorial step-9のソースを利用するため、そのソースを落としてきました。
そして、公開する用のgitリポジトリに移設させました。

#### angular-translator用のモジュールJSファイルを読み込む

bowerで下記を実行。

```
bower install angular-translate
```

ちょっとbowerについて理解していないところもあり、落としてきたファイルの場所を移してindex.htmlに下記のJSファイルを読み込むようにしました。

```html:app/index.html
<script src="lib/angular-translate/angular-translate.js"></script>
```

リポジトリ上のindex.htmlには、静的ファイルから変換定義ファイルを読み込めるモジュールもロードしていますが使っていません。

#### app.jsにAngula Translatorサービスの追加

まず、Angular Translatorの[Getting Started](http://angular-translate.github.io/docs/#/guide/02_getting-started)の通り、Tutorial step-9のapp.jsを下記のように修正。

```js:app/js/app.js
var phonecatApp = angular.module('phonecatApp', [
  'ngRoute',
  'phonecatControllers',
  'phonecatFilters',
  'pascalprecht.translate'
]);
```

#### app.jsに詳細画面の項目名の変換ルール定義を追加

それから詳細画面変換する個所に用いるキーワード定義を追記。

```js:app/js/app.js
phonecatApp.config(['$translateProvider', function ($translateProvider) {
  $translateProvider.translations('en', {
  .... 英語用
  });
  $translateProvider.translations('jp', {
  .... 日本語用
  });
  $translateProvider.preferredLanguage('en');
}]);
```

#### スマホ詳細画面のlocaleに合わせた変換個所を差し替え

Angular Translatorでは、localeに合わせて変換してほしいキーワードを囲むタグにtranslate属性を追加します。

たとえば、リポジトリのサンプルでは、バッテリの説明部分は英語表記でBatteryとなっています。これを日本でも表示できるように下記のように置き換えます。

```html:app/partials/phone-detail.html
    <span translate="SPEC_BATTERY">Battery</span>
```

こちらで確認したうえでは、残念ながら変換する文字列がないとtranslateで指定したキーワードに置き換わってしまいますので、何らかの変換設定が必ずいるようです。

#### 詳細画面のデータに日本用と英語用を準備

今回、翻訳作業を軽くするため、Tutorialのmotorola-xoom.jsonだけを英語用と日本語用として、「app/locale/en」とapp/locale/jp」に保存することにしました。

こうして、URI上では「locale/:localeId/phones/:phoneId.json」でデータを取得できるようになります。
これは、実際サーバーがデータを返す時にもこのURIにするつもりで設計しました。

#### 詳細画面のデータの取得する$httpのURL記述を変更

もともとのTutorialのスマホ詳細画面のデータ取得処理の$httpのURL値を下記のように修正しました。

```js:app/js/constrollers.js
phonecatControllers.controller('PhoneDetailCtrl', ['$scope', '$routeParams', '$http', '$translate',
  function($scope, $routeParams, $http, $translate) {
    $http.get('locale/'+ $translate.uses() + '/phones/' + $routeParams.phoneId + '.json').success(function(data) {
      $scope.phone = data;
    });
  }]);
```

$translate.uses()で、現在設定されているlocale値を取得できます。

#### localeの切り替え用ボタンの配置

今回は切り替えでることを確認するだけなため、ブラウザのロケール情報を見て切り替えるのではなく、ボタンで切り替えるようになっています。
そのため、下記のHTMLを実装しています。

```html:app/partials/phone-detail.html
<div ng-controller="Ctrl" class="ng-scope">

 ..............省略 .................

<div>
  <button id="BUTTON_LANG_EN" class="btn ng-scope" ng-click="changeLanguage('en')" translate="BUTTON_LANG_EN">english</button>
  <button id="BUTTON_LANG_JP"  class="btn ng-scope" ng-click="changeLanguage('jp')" translate="BUTTON_LANG_JP">Japanese</button>
</div>

 ............ 省略 ..............

</div>
```

そして、app/js/app.jsに下記を追加しています。

```js:app/js/app.js
phonecatApp.controller('Ctrl', ['$scope', '$translate', '$controller', function ($scope, $translate, $controller) {
  $scope.changeLanguage = function (key) {
    $translate.uses(key);
    var ctrl = $controller('PhoneDetailCtrl', {$scope: $scope});
  };
}]);
```
以上の実装は、下記を実現します。

1. HTML上のボタンにマッピングされたchangeLanguage()が呼び出されたら、
1. $tranlate.uses()を利用して表示上のlocale情報を更新
1. 詳細画面の情報を変更されたｌocaleで読み込みし直し

#### e2eテストに日本語変換されているかどうか確認記述を追記

テストで確認するのは、翻訳の処理が動いているかどうかです。各項目が正しく変換されているかどうかは目視でする前提です。

```js:test/e2e/scenarios.js
    it('should display translating', function() {
      expect(element('span[translate="SPEC_BATTERY"]').text()).toBe('Battery');
      element('#BUTTON_LANG_JP').click();
      expect(element('span[translate="SPEC_BATTERY"]').text()).toBe('バッテリ');
    });
```

上記を追加しました。

---------------------------

以上の通り、変更を加えることで、無事Tutorialのstep-9のスマホ詳細画面が日本語でも英語でも表記されるようになりました(ただし、motorola-xoomのページ限定)。

最初に、localeに合わせた表示切り替えを意識して作っておいて、ひとまず日本語ページの情報だけをつくるようにすすめられれば、時間に余裕ができたら他の言語を用意するだけになります。

以上です。
ソースの詳しい内容は、ページ先頭で紹介したgitリポジトリページを参照してください。