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>
)
}
翻訳ファイルを用意
任意の場所に翻訳ファイルを用意。
*
└── 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.js
とgatsby-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>
)
}
ユーザーの言語設定を検知する
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対応することができる。