React Nativeアプリにlocizeとi18nextを入れてi18n対応をいい感じに行う

こんにちは、
この記事はReact Nativeアドベントカレンダーの10日目の記事です。
弊社のアプリに取り入れたlocizeとi18nextの組み合わせが結構いい感じだったので紹介しますね。

サンプルコードはこちらです。
https://github.com/tsukushi0104/react-native-expo-locize-example


# 背景
弊社のサービスはユーザの半数以上が外国人ユーザであり、i18n対応はかなり重要です。しかしこれまで各言語に応じた翻訳ファイルは通常のアプリのソースと一緒にgitで管理されており、簡単な文言修正でも開発者が修正する必要がありました。
簡単な修正なのですがコストは発生しますし、何よりも**文言を変更したい方**からするとわざわざエンジニアにお願いしなければならないという部分で**少し億劫**になるのかな、と感じていました。


# これで何が楽になるのか
### エンジニアにとって
- i18nを含む文言修正全般の業務を翻訳チームやデザイナーに甘える事ができる。

### 翻訳チームにとって
- 強力な翻訳ダッシュボードを獲得できる(検索、バージョン管理、進捗管理 etc..)
- 翻訳チームだけで多言語対応可能になる

### デザイナーにとって
- 文言修正を自分のエンジニア抜き、自分のペースで行うことができる


# 手順
## i18nextを組み込む。
https://www.i18next.com/

``` console
# npm
$ npm install i18next --save

# yarn
$ yarn add i18next
```

初期化処理

``` initI18n.js
import i18next from 'i18next';

export default async () => i18next.init({
  lng: 'ja',
  debug: true,
  resources: {
    en: {
      translation: {
        "key": "hello world"
      }
    },
    ja: {
      translation: {
        "key": "おはよう、ワールド"
      }
    }
  }}
);

```

次に、jsxの中に `i18next.t('key')` とすれば、、

``` xx.js
import i18next from 'i18next'

{...}

<Text>{i18next.t('key')}</Text>

```

<img width="375" alt="IMG_AB8BE4F4166C-1.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/40909/272ab496-b964-14a9-0edf-0f0a305e6ad5.jpeg">



「おはよう、ワールド」が表示されます。なんの驚きもありませんね。
translationファイルを別ファイルにする事もできますが、このままだと文言修正コストがかかってしまいます。次で一気に[locize](https://www.locize.io/)を導入しちゃいましょう。

## locize導入

1. [locize](https://www.locize.io/register?next=/)にアクセス
2. アカウント作成は無料なのでよしなに登録してください。
3. 「Create Demo Project」をクリックしてみてください。
4. そうすると、「en, de, it」の3言語がデモ用で作成されます。
5. 「ADD NEW LANGUAGE」をクリックしてjaを追加してみてください。
6. ![Screen Shot 2018-12-10 at 18.06.57.png](https://qiita-image-store.s3.amazonaws.com/0/40909/248c8ed1-5a55-ca18-3132-bf273adf9327.png)
7. 日本語が進捗0の状態で作成されます。
![Screen Shot 2018-12-10 at 18.07.45.png](https://qiita-image-store.s3.amazonaws.com/0/40909/86812025-6ca4-ef20-9205-0c07e2c341b2.png)

## locizeとアプリをつなぐ
[i18next-locize-backend](https://github.com/locize/i18next-locize-backend)を利用します。

``` console
# npm
$ npm install i18next-locize-backend --save

# yarn
$ yarn add i18next-locize-backend
```

initI18next.jsにて、言語ファイルをlocizeから取得するように修正します。

``` initI18n.js
import i18next from 'i18next';
import LocizeBackend from 'i18next-locize-backend';

export default (callback) => i18next
  .use(LocizeBackend)
  .init({
    lng: 'ja',
    debug: true,
    fallbackLng: {
      // lngに指定した言語が翻訳されていない場合に参照する言語
      default: ['en']
    },
    // locizeに登録されているnamespace。demoの場合はtranslation
    defaultNS: 'translation',
    backend: {
      // locizeのプロジェクトIDです
      projectId: 'your project id',
      // saveMissingがtrueの時に必要です。
      apiKey: 'your api kei',
      // locizeで設定されているreferenceLngを指定してください。saveMissingがtrueのときに必要です。
      referenceLng: 'en',
      // locizeのどのバージョンの言語を取得するのかを指定します。デフォルトはlatestです
      version: 'latest',
    },
  }, callback
);
```
`projectId` と `apiKey` はlocizeのSettingページから確認できます。

ひとまず、これで最低限のつなぎこみは完了です。
この状態で `expo start` すると「おはよう、ワールド」が「key」になっているかと思います。当然です、locizeの中に 'key' というキーに紐づいている言語はありません。

## locizeにキーを登録する
1. locizeにログインしてプロジェクトを選択してください。
2. Reference Languageであるenのパネルを選択してください
3. メニューバーの 「ADD KEY」をクリックしてください
4. Keyに `key` 、 `Value` に 適当な文言を入力して画面上部から愉快なアニメーションで出てくるSaveをクリックしてください。
5. そうするとreference Languageに新規にキーが追加された事でitとdeの進捗が98%になりました。このように、**各言語の進捗**がわかりやすい、というのがlocizeの一つのメリットです。
![Screen Shot 2018-12-10 at 18.37.18.png](https://qiita-image-store.s3.amazonaws.com/0/40909/d379887f-6db5-030c-9001-d7d9173c7f6f.png)
6. なお、今は `fallbackLng` が `en` なので、この状態でexpoをフリフリすれば文言が「Key」から「Value」になっています！
7. `ja` のパネルから日本語の `key` の値を適当な日本語にして保存、expoフリフリすればもちろん文言が変更されます！
![Screen Shot 2018-12-10 at 19.15.31.png](https://qiita-image-store.s3.amazonaws.com/0/40909/dfc9ae61-4e18-5559-d696-7728aa22a542.png)
<img width="375" alt="IMG_0339.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/40909/011de980-1674-ac30-0ae1-7b8bdf094734.png">


## 端末からlocaleを自動取得する
今はi18nextの初期化の時に `ja` を指定していますが、これを端末の言語を使うようにすることもできます。

``` initI18n.js
{...}
import { Localization } from 'expo-localization';
import _ from 'lodash';
import subtag from 'subtag';

export default (callback) => i18next
  // languageDetectorを追加
  .use({
    type: 'languageDetector',
    async: true, // flags below detection to be async
    detect: (callback: string => void) =>
      // 端末から取得出来るlocale情報とlocizeの言語タグに違いがあるのでそのギャップを埋める
      Localization.getLocalizationAsync().then(({ locale }) => {
        const { language, script } = subtag(locale);
        callback(_.concat([language, script]).filter(Boolean).join('-'));
      }),
    init: () => {},
    cacheUserLanguage: () => {},
  })
{...}

```

## 終わりに
実際に端末の言語設定を変更していただければ、その言語をちゃんと読み込んで動作しているはずです。

いかがでしょうか？locizeとi18nextを組み込むことで **エンジニアを飛び越えてi18n対応を含む文言修正が出来るアプリを作り上げることが出来る！** ということが伝わりましたでしょうか。。？
こちらにサンプルソースを置きましたのでlocizeに登録の上、体験してみてください。

https://github.com/tsukushi0104/react-native-expo-locize-example

この記事では紹介ができませんでしたが、これとstorybookも組み合わせるとかなり効率的に翻訳作業を進めることが出来ます。こちらについても近いうちに記事をかければ。。。


明日はハムカツおじさんの記事です。楽しみですね。