Gatsbyで多言語対応サイトを作る


Gatsbyでの多言語化対応方法を説明していきます。確認環境は下記の通りです。

OS: Windows10
nodeバージョン: 14.15.4
gatsbyバージョン: 2.26.1

# Gatsbyの準備
Gatsby公式チュートリアルのスターター「gatsby-starter-hello-world」をベースに実装していきます。
チュートリアルの内容については公式ページの説明が分かりやすいので割愛し、チュートリアル「0.Set Up Your Development Environment」まで完了した想定で説明していきます。

* Gatsby公式チュートリアル: https://www.gatsbyjs.com/docs/tutorial/part-zero/
* 参考記事: https://qiita.com/irico/items/cf87eb29ecaf7e135fcd


# 多言語化する
## 目指すところ
チュートリアルの「0.Set Up Your Development Environment」まで完了時点で src/pages/index.js が下記のような形になっていると思います。
本記事では現在「Hello world!」となっている部分の文言を日本語ページと英語ページで出し分けるところまで説明していきます。

```jsx:index.js
import React from "react"

export default function Home() {
  return <div>Hello world!</div>
}
```

## gatsby-source-filesystem と gatsby-plugin-react-i18next をインストールする
本記事では gatsby-plugin-react-i18next を使用して実装していきます。
※ gatsby-plugin-react-i18next ですが、2021/02/05 にv1.0.0がリリースされ、大幅な変更があったようなのでv1.0.0未満とv1.0.0以上の両方の説明を書いていきます。

```npm install gatsby-source-filesystem```


```npm install --save gatsby-plugin-react-i18next i18next react-i18next```


* gatsby-source-filesystem: https://www.gatsbyjs.com/plugins/gatsby-source-filesystem/
* gatsby-plugin-react-i18next: https://www.gatsbyjs.com/plugins/gatsby-plugin-react-i18next/

## gatsby-config.js に設定を追加する
gatsby-config.js に gatsby-source-filesystem と gatsby-plugin-react-i18next を追加します。
options に記載する内容が gatsby-plugin-react-i18next v1.0.0未満とv1.0.0以上では異なるのでそれぞれ説明していきます。
### ■ v1.0.0未満の場合
翻訳用ファイルのパスは gatsby-plugin-react-i18next の options > path で指定します。

```js:gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/src/pages/`,
        name: `pages`,
      },
    },
    {
      resolve: `gatsby-plugin-react-i18next`,
      options: {
        path: `${__dirname}/locales`, // ここで翻訳用ファイルのパス指定
        languages: [`ja`, `en`],
        defaultLanguage: `ja`,
      }
    }
  ],
}
```

### ■ v1.0.0以上の場合
翻訳用ファイルのパスは gatsby-source-filesystem の options > path で指定します。
また、 gatsby-plugin-react-i18next の options > localeJsonSourceName に gatsby-source-filesystem で設定した name を指定します。

```js:gatsby-config.js
module.exports = {
  plugins: [
    {
      resolve: `gatsby-source-filesystem`,
      options: {
        path: `${__dirname}/locales`, // ここで翻訳用ファイルのパス指定
        name: `locale` // 任意のnameを指定
      }
    },
    {
      resolve: `gatsby-plugin-react-i18next`,
      options: {
        localeJsonSourceName: `locale`, // gatsby-source-filesystem の options > name と同じ名前を指定
        languages: [`ja`, `en`],
        defaultLanguage: `ja`,
      }
    }
  ],
}
```

## 翻訳用ファイルを作成する
gatsby-source-filesystem もしくは gatsby-plugin-react-i18next の path で指定したディレクトリに翻訳用ファイルを作成していきます。
今回は`${__dirname}/locales`としているので hello-world 直下に locales ディレクトリを作成します。
また、日本語(ja)と英語(en)の2種類を作成するので locales ディレクトリ配下に ja と en ディレクトリを作成します。
翻訳用ファイル自体の名前は translation.json とします。
（翻訳用ファイルの名前は translation.json がデフォルトですが、任意の名称で複数ファイル作成し、条件によって読み込むファイルを変えることもできるようです。 参考: https://www.i18next.com/principles/namespaces ）

ディレクトリ構成は下記の通りです。

```
    .
    ├── node_modules
    ├── locales
    |   ├── en
    |   |   └── translation.json
    |   └── ja
    |       └── translation.json
    ├── src
    ├── .gitignore
    ├── .prettierrc
    ├── gatsby-browser.js
    ├── gatsby-config.js
    ├── gatsby-node.js
    ├── gatsby-ssr.js
    ├── LICENSE
    ├── package-lock.json
    ├── package.json
    └── README.md
```

翻訳用ファイルの中身を作成します。任意のキーと値を入れていきます。

``` locales/ja/translation.json
{"titleTxt": "こんにちは"}
```

``` locales/en/translation.json
{"titleTxt": "Hello"}
```

## index.jsを書き換える
翻訳用ファイルに設定した文言を表示できるように index.js を書き換えていきます。

まず言語スイッチャーを追加します。
useI18next の languages から gatsby-config.js の languages で指定した言語リストを取得し、各言語ページへのリンクを作成します。

```jsx:index.js
import React from "react"
import {Link, useI18next} from "gatsby-plugin-react-i18next"

export default function Home() {
  const {languages, originalPath} = useI18next();
  return (
    <div>
      <ul className="languages">
        {languages.map((lng) => (
          <li key={lng}>
            <Link to={originalPath} language={lng}>
              {lng}
            </Link>
          </li>
        ))}
      </ul>
      <div>Hello world!</div>
    </div>
  )
}
```

次に「Hello world!」の部分を、各翻訳用ファイルに設定した文言を表示するように変更します。
### ■ v1.0.0未満の場合
useTranslation の t から translation.json に設定した文言を取得できます。
今回は titleTxt というキーの値を取得するため「Hello world!」の部分を`{t("titleTxt")}`に変更しました。
（対象がオブジェクトの場合は`t("titleTxt", { returnObjects: true })`で取得できます）

```jsx:index.js
import React from "react"
import {Link, useI18next, useTranslation} from "gatsby-plugin-react-i18next"

export default function Home() {
  const {languages, originalPath} = useI18next();
  const {t} = useTranslation();
  return (
    <div>
      <ul className="languages">
        {languages.map((lng) => (
          <li key={lng}>
            <Link to={originalPath} language={lng}>
              {lng}
            </Link>
          </li>
        ))}
      </ul>
      <div>{t("titleTxt")}</div>
    </div>
  )
}
```

### ■ v1.0.0以上の場合
v1.0.0 からはquery 部分の記載が必要になっています。

```jsx:index.js
import React from "react"
import {Link, useI18next, useTranslation} from "gatsby-plugin-react-i18next"

export default function Home() {
  const {languages, originalPath} = useI18next();
  const {t} = useTranslation();
  return (
    <div>
      <ul className="languages">
        {languages.map((lng) => (
          <li key={lng}>
            <Link to={originalPath} language={lng}>
              {lng}
            </Link>
          </li>
        ))}
      </ul>
      <div>{t("titleTxt")}</div>
    </div>
  )
}

export const query = graphql`
query($language: String!) {
  locales: allLocale(filter: {language: {eq: $language}}) {
    edges {
      node {
        ns
        data
        language
      }
    }
  }
}
`;
```

## 確認する
以上で設定は完了です。
`gatsby develop`を実行し、http://localhost:8000/ より確認すると、言語ごとに翻訳用ファイルに設定した文言を表示するようになっていると思います。（今回は defaultLanguage を ja にしているためルートパスが日本語ページになっています）

![gatsby_test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216973/7d4048e8-4cc1-09aa-770b-e073d3e37684.png)

v1.0.0以降のほうが全体的に記述量が増えている印象ですが、ホットリロード対応となっているため transition.json の内容を書き換えた後`gatsby develop`を実行し直す手間が無くなっています。

## 注意点
翻訳用ファイルのディレクトリ名に「-(ハイフン)」が含まれるとファイルが正常に読み込めなくなるようです。
良い回避策を見つけられたらこちらの記事に追記したいと思います。
issue: https://github.com/microapps/gatsby-plugin-react-i18next/issues/42