[i18next] GatsbyやReactで多言語対応する

May 18, 2021

programming
article cover

i18nライブラリの選択肢

Reactでi18n対応しようとするとざっと調べたところ以下の3つに絞られてくる。

React-intl

12.5k stars on Github
Format.jsの一部であり、Yahoo製のオープンソースライブラリ。

React-i18next

5.6k stars on Github
React用のi18nフレームワーク

LinguiJS

3.1k stars on Github
i18nフレームワーク。おそらく3つの中で一番軽量?

手軽さや柔軟性を考えた結果、React-i18nextがバランスが取れていて非常に良さそうなので、今回はこれでi18n対応していく。

Gatsbyの場合の選択肢

Gatsbyを使う場合、ご多分に漏れずすでにプラグインが用意されている。

gatsby-plugin-react-i18next

Seamless integration with react-i18next

このプラグインは各言語ごとにSSRして静的ファイルを生成した上で、言語ごとにURLもええ感じに設定してくれる。 例えば英語のページならhttps://sample.com/en/profile、日本語ページならhttps://sample.com/ja/profileという具合。

しかし今回はURLを別に設定するほどのことでもなく、このプラグインだと煩わしそうだったので、これを使わずにReact-i18nextをGatsbyに実装していくことにした。

コンポーネントの作成

GatsbyにしろReactにしろ既にプロジェクトはあるものとして進めていく。 サンプルとして簡単なコンポーネントを作成する。

// index.js

import React from 'react'

export const Index = () => {
  return (
    <div>
      <h1>Have a nice day!</h1>
      <ul>
        <li><button>EN</button></li>
        <li><button>DE</button></li>
        <li><button>JA</button></li>
      </ul>
    </div>
  )
} 

screenshot

翻訳ファイルを用意

任意の場所に翻訳ファイルを用意。

*
└── locales/
     ├── en/
     │    └── translation.json
     │
     ├── de/
     │    └── translation.json
     │
     └── ja/
          └── translation.json

翻訳ファイルはjsonで記述する。同じ文章なら全ての言語ファイルでKeyが同じである必要があるので注意。 入れ子にして記述することも可能。

en/translation.json

{
  "topPage": {
    "greeting": "Have a nice day"
  }
}

de/translation.json

{
  "topPage": {
    "greeting": "Schönen tag noch"
  }
}

ja/translation.json

{
  "topPage": {
    "greeting": "よい1日を"
  }
}

React-i18nextを設定

まずはインストール。

npm install --save react-i18next i18next

or 

yarn add react-i18next i18next

任意の場所にi18n.jsファイルを作ってinitする。

import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'

i18n
  .use(initReactI18next)
  .init({
  resources: { // 自分の用意した翻訳ファイルを任意の場所から読み込む
    en: {
      translation: require('../../static/locales/en/translation.json')
    },
    de: {
      translation: require('../../static/locales/de/translation.json')
    },
    ja: {
      translation: require('../../static/locales/ja/translation.json')
    }
  },
  debug: process.env.NODE_ENV === "development",
  fallbackLng: 'en', // デフォルトの言語を設定する
  interpolation: {
    escapeValue: false,
  },
})

export default i18n

最後にi18nをアプリケーション全体に流し込む。 I18nextProviderなるものが用意されているので、これでアプリを包めばOK。

import React from 'react'
import ReactDOM from 'react-dom'
import { I18nextProvider } from 'react-i18next'
import i18n from './src/providers/i18n'

const App =() => {
  return (
    <I18nextProvider i18n={i18n}>
      <Index />
    </I18nextProvider>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))

Gatsbyの場合はgatsby-browser.jsgatsby-ssr.jsで記述する。

// gatsby-wrapper.js

import React from 'react'
import { I18nextProvider } from 'react-i18next'
import i18n from './src/providers/i18n'

export const rootWrapper = ({ element }) => (
  <>
    <I18nextProvider i18n={i18n}>
      {element}
    </I18nextProvider>
  </>
)
// gatsby-ssr.js

import { rootWrapper } from './gatsby-wrapper'

export const wrapRootElement = rootWrapper
// gatsby-browser.js

import { rootWrapper } from './gatsby-wrapper'

export const wrapRootElement = rootWrapper

言語の切り替え

i18nextでの翻訳の仕方は非常にシンプルで、専用のhooksを使い t()関数 でkeyとなるストリングを囲むだけ。
言語の変更する際はi18n.changeLanguage()で言語を指定すれば良い。

// index.js

import React from 'react'
import { useTranslation } from 'react-i18next'

export const Index = () => {
  const { t, i18n } = useTranslation()
  
  const changeLang = (lang) => {
    i18n.changeLanguage(lang)
  }

  return (
    <Div>
      <h1>{t('topPage.greeting')}</h1>
      <ul>
        <li><button onClick={() => changeLang('en')}>EN</button></li>
        <li><button onClick={() => changeLang('de')}>DE</button></li>
        <li><button onClick={() => changeLang('ja')}>JA</button></li>
      </ul>
    </Div>
  )
} 

screen shot

ユーザーの言語設定を検知する

i18nextにはもう一つ便利な機能があり、ユーザーの言語設定を検知して自動で言語を変更してくれる。
これを有効にするには専用の2つのパッケージをインストールしてinit時に読み込むだけ。

npm install --save i18next-http-backend i18next-browser-languagedetector

or 

yarn add i18next-http-backend i18next-browser-languagedetector
// i18n.js

import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
import Backend from 'i18next-http-backend' // new
import LanguageDetector from 'i18next-browser-languagedetector' //new 

i18n
  .use(Backend)  // new
  .use(LanguageDetector) // new
  .use(initReactI18next)
  .init({
  resources: {
    en: {
      translation: require('../../static/locales/en/translation.json')
    },
    de: {
      translation: require('../../static/locales/de/translation.json')
    },
    ja: {
      translation: require('../../static/locales/ja/translation.json')
    }
  },
  debug: process.env.NODE_ENV === "development",
  fallbackLng: 'en',
  interpolation: {
    escapeValue: false,
  },
})

export default i18n

以上!
React-i18nextを使うことでシンプルかつ簡単にi18n対応することができる。


Profile picture

元カメラマン。今はベルリンで働くWEBエンジニア。
スロバキア人の妻とドイツ猫二匹の多国籍家族。