Next.js × react-i18next で始める Web アプリの多言語対応
はじめに
データサイエンティストの小畑です。
MCD3 では、 Tachyon 生成AI をはじめ、様々な Web アプリの開発を行っております。非日本語話者にも Web アプリをご利用いただく場合、多言語化対応が一つの重要な課題となります。
本記事では特に Next.js
を用いて開発されている Web アプリについて、 react-i18next
を用いた多言語化対応について紹介します。
使用するライブラリについて
本記事では、以下のライブラリについて説明をします。
ライブラリ | 用途 | 使用バージョン |
---|---|---|
react-i18next | 多言語化ライブラリである i18next を React で扱うためのバインディング | 14.1.3 |
i18next-browser-languagedetector | ブラウザの言語設定の検出、及びその結果の LocalStorage への保存 | 8.0.0 |
i18next-parser | コードを元にした辞書ファイルの自動生成 | 9.0.1 |
多言語化に必要な設定ファイル群について
ディレクトリ構成の一例を示します。
frontend/
├── src/
│ ├── i18n
│ │ ├── locales
│ │ │ ├── en.json
│ │ │ └── ja.json
│ │ └── config.ts
│ ├── app
│ └── …
└── …
config.ts
ファイルについて
config.ts
ファイルの一例を示します。
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
import translationEn from "i18n/locales/en.json";
import translationJa from "i18n/locales/ja.json";
i18n
.use(
new LanguageDetector(null, {
order: ['querystring', 'cookie', 'localStorage', 'sessionStorage', 'navigator', 'htmlTag'],
}),
)
.use(initReactI18next)
.init({
fallbackLng: "en",
returnEmptyString: false,
resources: {
en: {
translation: translationEn,
},
ja: {
translation: translationJa,
},
},
});
export { i18n };
これを layout ファイルで import します。
...
import "i18n/config";
...
order
以下の言語検出方法について、使用する優先順位を付けることができます。(i18next-browser-languageDetector
README より引用)
- cookie (set cookie i18next=LANGUAGE)
- sessionStorage (set key i18nextLng=LANGUAGE)
- localStorage (set key i18nextLng=LANGUAGE)
- navigator (set browser language)
- querystring (append ?lng=LANGUAGE to URL)
- htmlTag (add html language tag <html lang="LANGUAGE” …)
- path (http://my.site.com/LANGUAGE/…)
- subdomain (http://LANGUAGE.site.com/…)
- hash (append #lng=LANGUAGE or #/LANGUAGE to URL)
デフォルトの設定では、一度設定された言語情報は localStorage に保存されます。
fallbackLng
LanguageDetector
による言語検出に失敗した場合に使用される言語を指定できます。
returnEmptyString
false
の場合、後に記載する辞書ファイルにて value が空文字列であった場合に、key の値がそのまま value として使用されます。
value の値を設定し忘れた場合に気付きやすくなる為、 false にすることを推奨します。
その他
i18next-browser-languageDetector のオプションについては READMEを、 react-i18next のオプションについてはi18next documentationをご参照ください。
辞書ファイルについて
ja.json
, en.json
の一例を示します。
{
"message": {
"loadingFiles": "{{fileNames}}を読み込み中…",
},
"UserButton": {
"language": "言語",
"logout": "ログアウト"
}
}
{
"message": {
"loadingFiles": "Loading {{fileNames}}...",
},
"UserButton": {
"language": "Language",
"logout": "Logout"
}
}
上記のように適当にネストさせることで、コンポーネント毎に要素をグルーピングするような定義が可能です。
また、modal.loadingFiles
に示すように、適当な文字列をコード内で与えて、それを埋め込むことも可能です。
尚、後に紹介する i18next-parser
にて雛形は自動生成される為、 value 以外の部分を書く必要はありません。
多言語化の記法について
react-i18next
が提供する useTranslation
フックから t関数
を取得し、翻訳キーを渡します。
import { Button } from '@chakra-ui/react';
import { useTranslation } from 'react-i18next';
export const UserButton = () => {
const { t } = useTranslation();
const handleLogout = () => {};
return (
<Button onClick={handleLogout}>
{t('UserButton.logout')}
</Button>
);
};
また、次に示すように、適当な文字列を渡し、それを埋め込むようにして翻訳処理を行うことも可能です。
<Text>
{t("message.loadingFiles", {
fileNames: "sample1, sample2, sample3",
})}
</Text>
この場合、日本語における表示は以下の通りとなります。
sample1, sample2, sample3を読み込み中…
言語設定の切り替えについて
useTranslation
フックから i18n
オブジェクトを取得し、i18n.changeLanguage
を利用することで、言語設定を切り替えることが出来ます。
const languageMenuItems: Array<{
value: string;
label: string;
}> = [
{
value: "ja",
label: "日本語",
},
{
value: "en",
label: "English",
},
];
import { FC } from "react";
import { languageMenuItems } from "@/languages";
import { Select } from "@chakra-ui/react";
export const ChangeLanguage: FC<{
selectDefaultLanguage: string;
}> = ({ selectDefaultLanguage }) => {
const { i18n } = useTranslation();
const onChangeLanguage = (language: string) => {
i18n.changeLanguage(language);
};
return (
<Select
defaultValue={selectDefaultLanguage}
onChange={(e) => onChangeLanguage(e.target.value)}
>
{languageMenuItems.map(({ value, label }) => (
<option key={value} value={value}>
{label}
</option>
))}
</Select>
);
};
i18next-parser について
i18next-parser を用いることで、以下を行うことが出来ます。
- コード内に存在する t 関数で使用されている key の集合を key に持つ辞書ファイルの生成
- 新規追加された key に対応する要素の追加
- 削除された key に対応する要素の削除
- コード内に存在する t 関数で使用されている key の集合と、辞書ファイル内に存在する key の集合が一致していることのチェック
更に、本チェックを CI に導入することで、辞書ファイルの key の追加・削除忘れを防ぐことができます。
i18next-parser.config.js
ファイルについて
新しく、 i18next-parser.config.js
ファイルを配置します。
frontend/
├── src/
│ ├── i18n
│ │ ├── locales
│ │ │ ├── en.json
│ │ │ └── ja.json
│ │ └── config.ts
│ ├── app
│ └── …
├── i18next-parser.config.js
└── …
i18next-parser.config.js
の一例を示します。
module.exports = {
locales: ["ja", "en"],
sort: true,
createOldCatalogs: false,
output: "i18n/locales/$LOCALE.json",
};
locales
, output
は、 config.ts
やディレクトリ構成に合わせてください。
sort
true にすると、辞書ファイルの key が辞書式順序でソートされます。
createOldCatalogs
true の場合、削除された key の情報が別ファイルにエクスポートされます。
その他
その他のオプションについては、READMEをご参照ください。
i18next-parser
を用いた、辞書ファイルの自動生成について
以下のコマンドにより、辞書ファイルの自動生成を行うことが出来ます。(対象ファイルは一例です。ディレクトリ構成に合わせて、適切に設定してください。)
i18next 'src/**/*.{tsx,ts}'
i18next-parser
を用いた、辞書ファイルのチェックについて
以下のコマンドにより、辞書ファイルの key の集合が、コード内に現れる t 関数の key の集合と一致しているか、確かめることが出来ます。(対象ファイルは一例です。ディレクトリ構成に合わせて、適切に設定してください。)
i18next 'src/**/*.{tsx,ts}' --fail-on-update
react-i18next の Storybook 対応について 1
Storybook とは、様々なコンポーネントを独立してチェックする「UIカタログ」を作成するライブラリです。 適切に設定を行うことで、 Storybook にて他言語でのコンポーネントの表示を確認することが出来ます。
preview.tsx
を適切に編集することで、ツールバーから locale
を設定できるようにし、それに基づいて言語設定を行います。
export const globalTypes = {
locale: {
name: "Locale",
description: "Internationalization locale",
toolbar: {
icon: "globe",
items: [
{ value: "ja", title: "日本語" },
{ value: "en", title: "English" },
],
showName: true,
},
},
};
...
const i18nextDecorator = (Story, context) => {
const { locale } = context.globals;
useEffect(() => {
i18n.changeLanguage(locale);
}, [locale]);
return (
<Suspense fallback={<div>loading translations...</div>}>
<I18nextProvider i18n={i18n}>
<Story />
</I18nextProvider>
</Suspense>
);
};
...
const preview: Preview = {
...
decorators: [i18nextDecorator] // i18nextDecorator を追加する
...
}
以上の設定により、Storybook 内のツールバーから言語設定を行うことができます。
まとめ
本記事では、 react-i18next
, i18next-browser-languagedetector
, i18next-parser
を用いて、 Next.js
で開発された Web アプリを多言語化対応する方法について解説しました。
本記事の内容が皆様の助けになれば幸いです。
MCD3 では、技術力向上のためのイベントや勉強会なども定期的に実施しています。 もし MCD3 で働くことに興味を持っていただいた方がいらっしゃいましたら、カジュアル面談も受け付けておりますので、お気軽にお声掛けください! 採用情報や面談申込みはこちらから