NextJSで各国語対応してみた

以前、NextJSといったJavaScriptフレームワークを使ってWEBアプリを作っていたときの話。
メインは日本人だが、外国人も使えるアプリにする必要があった。

1. Google翻訳APIを使う
2. Google以外の自動翻訳してくれるサービスを利用する
3. 各国に対応したページを量産する
4. 指定した文言であって欲しい

色々と実装方法はあるが、どれもマッチしない。
3は論外、4が重要！
適当な直訳ではダメ、言い回しも業界に合わせる必要があった。

さて、どうするか…
無いものは作っちゃえ！（← 好きです。この言葉）
ということで、用意するのはJSONファイルと簡単なスクリプト。

今回は、NextJS を使った実装方法を紹介します。
Next.JS ついては → https://nextjs.org/

環境の準備ですが、事前にNode.jsが動作する環境が必要です。
次にNextJS環境。
こちら最新バージョンではデフォルトでTypeScriptが使えて So Cool!
公式ドキュメントに従い、簡単に環境作っちゃいましょう。


```
> npx create-next-app
```

TypeScriptを有効にするには、ルートに`tsconfig.json`が必要だったり、`別途モジュール`が必要だったり。
ちょっとだけゴニョゴニョして環境出来上がり。

```
> npm run dev
```
とかすると http://localhost:3000 で確認できます。
ウォッチ状態なので、このままコーディングすると自動的に反映され、リアルタイムで動作を確認できます。

では早速、表示するページを用意しましょう。
pagesディレクトリに既に index.js を書き換えちゃいます。

```
export default () => (
  <div>
    <Head>
      <title>Translate</title>
    </Head>
    <p>ここの</p>
    <p>文字列が</p>
    <p>翻訳されます</p>
    <p>ただし、辞書に無いものはそのまま表示されます</p>
  </div>
)
```

言語を変えるためのボタンを用意します。
今回は「日本語」「英語」「中国語」への変換を行うこととします。
同時に、クリックした際のイベントハンドラも用意しましょう。
ボタンをクリックすると、LanguageUtil.setLanguage(...) が呼ばれる仕組みです。

```
<form>
  <button value='ja' onClick={changeLanguage}>日本語</button>
  <button value='en' onClick={changeLanguage}>英語</button>
  <button value='zh' onClick={changeLanguage}>中国語（簡体）</button>
</form>
```
```
const changeLanguage = event => {
  event.preventDefault()
  const language = event.currentTarget.value
  setLanguage(language)
}
```

その LanguageUtil.setLanguage(...) の実体。
URLのクエリ―パラメータに、langとして、押されたボタンのvalue値をセットしています。

```
export const setLanguage = (language: string): void => {
  const { pathname, search } = window.location
  const query = parse(search.replace('?', ''))
  query['lang'] = language
  Router.replace({ pathname, query }).then()
}
```

次に、翻訳の中心的な存在となるJSONファイルを用意しましょう。
翻訳したい文字列をキーにして、各国コード用の文言を用意します。

↓適当な翻訳です。

```
{
  "ここの": {
    "en": "This",
    "zh": "这个"
  },
  "文字列が": {
    "en": "string is",
    "zh": "字符串是"
  },
  "翻訳されます": {
    "en": "translated",
    "zh": "已翻译"
  }
}
```

キーの値（文言）と、国コードを渡すと、その国コードに対応した文言が返るメソッドを用意します。
その際、国コードはクエリ―ストリングから取得するようにします。
NextJSはサーバ上でも動作するため、Windowオブジェクトが有るか事前にチェックする必要があったりします。

```
export const getLanguage = (): string => {
  if (!hasWindow()) return 'ja'
  const { search } = window.location
  const query = parse(search.replace('?', ''))
  return _.get(query, 'lang', 'ja') as string
}

export const translate = (word: string): string => {
  const lang = getLanguage()
  return _.get(_translates, `${word}.${lang}`, word)
}
```

最後にページを修正します。
翻訳したい文字列を translate(...) で囲うだけです。

```
export default () => (
  <div>
    <Head>
      <title>Translate</title>
    </Head>
    <form>
      <button value='ja' onClick={changeLanguage}>日本語</button>
      <button value='en' onClick={changeLanguage}>英語</button>
      <button value='zh' onClick={changeLanguage}>中国語（簡体）</button>
    </form>
    <p>{translate('ここの')}</p>
    <p>{translate('文字列が')}</p>
    <p>{translate('翻訳されます')}</p>
    <p>{translate('ただし、辞書に無いものはそのまま表示されます')}</p>
  </div>
)
```

それぞれの言語ボタンをクリックすると、URLのパラメータが変わり
指定の言語に切り替わることが確認できると思います。

![ja.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212841/4f7386c2-f87f-97ba-a275-59fae5690751.png)
![en.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212841/76941bb6-5fd4-befd-9829-388738a6f5b0.png)
![zh.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212841/9993b9df-f545-fa71-56cb-6673bde79b36.png)

![Translate.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/212841/e76dd056-d99f-80bf-bcc0-f4e3fd4db702.gif)

長文やページデザインも変更するような場合は、今回紹介した内容では対応できませんが、
簡単な翻訳機能であれば、外部の翻訳サービスを一切使わずに実装できちゃいました。

本記事で使ったソースは、GitHubで公開しています。
https://github.com/wild-lycaon/poc-nextjs-translate

では、またどこかで。