Reactで簡単に多言語対応する方法は?react-i18nextの使い方
目次
はじめに
こんにちは。フロントエンドエンジニアのKimuraです。
アトラスが展開する大会事業サービスConfitは、国内大会のみではなく、国際大会でも数多くご利用いただいています。このため、各種画面は日本語のみでなく英語表示にも対応しています。
React上の多言語対応ライブラリとしては、react-i18nextがよく取り上げられるかと思います。アトラスでも、react-i18nextを利用して多言語対応を実装しています。 本記事では、react-i18nextの基本的な利用方法と、Jestによるテスト実装をご紹介いたします。
なおテストについては、公式がJest + Enzymeを利用したサンプルコードを公開しています。本記事ではそちらを参考に、React Testing Libraryを使用していきます。
利用技術
React
Create React Appを利用したTypeScriptプロジェクト上で実装を進めていきます。プロジェクトは下記のコマンドを利用して生成しています。
1 |
npx create-react-app react-i18next-sample --template typescript |
react-i18next
i18nextのReact用ライブラリです。
i18nextは多言語対応ライブラリであり、react-i18nextではAPIとしてReact Hooksが提供されています。
Jest
Create React Appにデフォルトとして採用されているテスティングライブラリです。
React Testing Library
Testing Libraryが提供するReactコンポーネント用テスティングライブラリです。こちらもCreate React Appにデフォルトとして採用されています。
類似ライブラリにEnzymeがあります。
react-i18nextの利用方法
今回は、useTranslation
を利用してメッセージを取得する方法を扱います。
インストール
まずは、関連するnpmパッケージをインストールします。
1 |
npm install react-i18next i18next i18next-http-backend i18next-browser-languagedetector |
メッセージjson作成
言語ごとに、メッセージを定義したjsonファイルを作成します。今回は例として、日本語と英語の定義を用意します。
1 2 3 4 5 |
{ "test": { "message": "テストメッセージ" } } |
1 2 3 4 5 |
{ "test": { "message": "test message" } } |
初期化
メッセージ取得を利用する前に、初期化を実装したi18n.ts
を作成します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import i18n from 'i18next'; import Backend from 'i18next-http-backend'; import LanguageDetector from 'i18next-browser-languagedetector'; import { initReactI18next } from 'react-i18next'; i18n .use(Backend) .use(LanguageDetector) .use(initReactI18next) .init({ fallbackLng: 'ja', ns: ['translations'], defaultNS: 'translations', debug: true, interpolation: { escapeValue: false, } }); export default i18n; |
本記事は、React Suspenseを利用する前提の実装となります。利用しない場合は、初期化時に追加設定が必要となります。
1 2 3 4 5 6 7 8 |
i18n // (中略) .init({ // (中略) react: { useSuspense: false } }); |
作成したi18n.ts
をindex.tsx
内に読み込みます。これにより初期化が実行され、コンポーネント内でuseTranslation
を利用可能となります。
1 |
import './i18n'; |
コンポーネント作成
実際にメッセージを取得するコンポーネントを作成します。
1 2 3 4 5 6 7 |
import React from 'react'; import { useTranslation } from 'react-i18next'; export const TestComponent = () => { const { t } = useTranslation(); return <div>{t('test.message')}</div>; } |
上記のコンポーネントは、<div>
内にreact-i18next経由で取得した文字列を表示します。
メッセージキーをt
に渡すことで、jsonファイルに定義されたメッセージが返却されます。json上の階層は.
で表現されています。
App.tsx
内に<TestComponent>
を配置して、表示を確認してみます。
1 2 3 4 5 6 7 8 9 10 |
import React, { Suspense } from 'react'; import { TestComponent } from './components/TestComponent'; function App() { return ( <Suspense fallback={<p>Loading...</p>}> <TestComponent /> </Suspense> ); } |
この状態で開発サーバを立ち上げると、<TestComponent>
が画面表示されます。
1 |
npm start |
言語切替実装
デフォルトの日本語表示から、英語表示に切り替えるボタンを実装していきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import { useTranslation } from 'react-i18next'; const AppPage = () => { const { i18n } = useTranslation(); const changeLanguage = (lng: string) => { i18n.changeLanguage(lng); }; return ( <div className="App"> <div> <button onClick={() => changeLanguage('ja')}>ja</button> <button onClick={() => changeLanguage('en')}>en</button> </div> <TestComponent /> </div> ); } function App() { return ( <Suspense fallback={<p>Loading...</p>}> <AppPage /> </Suspense> ); } |
画面を確認すると、ja
とen
のボタンが追加されています。これらを押下することにより、<TestComponent>
の表示言語が切り替わります。
テスト
最後に、JestとReact Testing Libraryを利用してテストを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import { render } from "@testing-library/react"; import { TestComponent } from './TestComponent'; jest.mock('react-i18next', () => ({ useTranslation: () => { return { t: (str: string) => str, i18n: { changeLanguage: () => new Promise(() => {}), }, }; }, })); it('test render', () => { const { getByText } = render(<TestComponent />); expect(getByText('test.message')); }); |
モック実装が存在しない場合、実行時に警告が表示されます。react-i18nextの初期化処理が行われていないため、useTranslation()
などAPIのインスタンスが取得できないことが原因です。
なお、上記のモックはt
の引数をそのまま返却しています。json定義したメッセージは、コンポーネント上に表示されません。
メッセージが表示されているかを確認するため、getByText
にメッセージキー(test.message
など)を引き渡します。これにより、任意のメッセージが出力対象となっているか検証可能となります。
下記のコマンドで、テストを実行します。
1 |
npm test src/components |
最後に
react-i18next + Jest による多言語対応の実装方法、いかがでしたでしょうか。
グローバル化が進む昨今、多言語対応サービスも数多く存在しております。アトラスでも引き続き、国内外のお客様にご利用いただけるサービスを目指していきたいと思います。