概要
-
React
コンポーネントに多言語対応(i18n
)を導入する手順をまとめた -
i18next
,react-i18next
を活用し、Storybook
上で翻訳内容を確認できる環境を構築した -
Docker
を活用し、環境差異を抑えたローカル開発が可能な構成にした
実施条件
- React + TypeScript プロジェクトがすでに構築されている
- Storybook が導入済みで
npm run storybook
にて起動確認ができる - Docker / Docker Compose を使用した開発環境が用意されている
参考リンク
[Docker][React] DockerでReactプロジェクトを起動する
[Storybook][React][TypeScript] Storybookの導入手順
[Docker][Storybook] DockerでStorybookを起動する
環境
ツール | バージョン | 目的 |
---|---|---|
Node.js | 22.5.1 | React や Storybook の実行環境 |
npm | 10.8.2 | パッケージ管理 |
React | 19.1.0 | UI コンポーネントの開発 |
TypeScript | 5.x.x | 型安全な開発を行う |
Storybook | 最新安定版(9.0) | UI コンポーネントの確認とテスト |
i18next | 最新安定版(2025年時点) | 多言語対応(翻訳処理の導入) |
Docker | 28.1.1 | ローカル環境の構築と再現性の確保 |
手順
1. i18nライブラリをインストール
npm install i18next react-i18next
2. 翻訳ファイルを作成
以下のように翻訳ファイルを用意する
src/locales/en/translation.json
:
{
"description_text": "This is a description"
}
src/locales/ja/translation.json
:
{
"description_text": "これは説明文です"
}
3. i18n 初期化ファイルを作成
src/i18n.ts
:
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import enTranslation from './locales/en/translation.json';
import jaTranslation from './locales/ja/translation.json';
i18n.use(initReactI18next).init({
resources: {
en: { translation: enTranslation },
ja: { translation: jaTranslation },
},
lng: 'ja', // 翻訳キーを解決する際の初期言語
fallbackLng: 'en', // 翻訳キーが見つからない場合の代替言語
interpolation: { escapeValue: false },
});
export default i18n;
4. エントリポイントで i18n を import
src/index.tsx
or src/main.tsx
or .storybook/preview.ts
にて初期化ファイルを読み込む
import './i18n'; // i18nの初期化
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
import './i18n'; // i18nの初期化
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<App />,
document.getElementById('root')
);
// .storybook/preview.ts
import '../src/i18n';
5. コンポーネントで useTranslation を使用
Description.tsx
を多言語対応にする
import React from 'react';
+ import { useTranslation } from 'react-i18next';
import './description.css';
export type DescriptionProps = {
- text: string;
+ textKey: string;
color?: string;
align?: 'left' | 'center' | 'right';
style?: React.CSSProperties;
};
export const Description: React.FC<DescriptionProps> = ({
- textKey,
+ textKey,
color,
align = 'left',
style,
}) => {
+ const { t } = useTranslation();
return (
<p
className="description"
style={{ color, textAlign: align, ...style }}
data-testid="description"
>
- {text}
+ {t(textKey)}
</p>
);
};
6. Storybookで動作確認
Description.stories.tsx
:
import React from 'react';
import { Description } from './Description';
export default {
title: 'Example/Description',
component: Description,
};
export const Default = () => (
<Description textKey="description_text" />
);
DockerでStorybook起動
起動コマンド:
docker-compose up --build
localhost:6006 にアクセスして、i18nが反映されているかを確認する
翻訳(変換)プロセス
1. stories
から翻訳キーが渡される
Description.stories.ts
などの親コンポーネント
からProps
として翻訳キー
がDescription.tsx
へ渡す
import React from 'react';
import { Description } from './Description';
export default {
title: 'Example/Description',
component: Description,
};
export const Default: Story = {
args: {
textKey: 'description_text' // ← 翻訳キー,
color: '#666',
align: 'left',
},
};
2. Description.tsx
内でt()
関数が呼ばれる
Description.tsx
内でt()
関数が呼ばれる = useTranslation
フックが呼ばれる
import React from 'react';
import { useTranslation } from 'react-i18next'; // ←react-i18nextのフック
import './description.css';
export type DescriptionProps = {
textKey: string;
color?: string;
align?: 'left' | 'center' | 'right';
style?: React.CSSProperties;
};
export const Description: React.FC<DescriptionProps> = ({
textKey,
color,
align = 'left',
style,
}) => {
const { t } = useTranslation(); // ←react-i18nextのフックを関数化
return (
<p
className="description"
style={{ color, textAlign: align, ...style }}
data-testid="description"
>
{t(textKey)} //// ←t()(react-i18nextのフックの関数)を実行
</p>
);
};
3. i18n.ts
が設定を提供
i18n.ts
がuseTranslation
フックへ翻訳(変換)プロセスを提供
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import enTranslation from './locales/en/translation.json';
import jaTranslation from './locales/ja/translation.json';
i18n.use(initReactI18next).init({
resources: {
en: { translation: enTranslation },
ja: { translation: jaTranslation },
},
lng: 'ja', // 翻訳キーを解決する際の初期言語
fallbackLng: 'en', // 翻訳キーが見つからない場合の代替言語
interpolation: { escapeValue: false },
});
export default i18n;
4. t()
関数がtranslation.json
ファイルを参照
i18n.ts
の設定に基づき、t()
(react-i18next
フックの関数)がsrc/locales/ja/translation.json
を参照
{
"description_text": "これは説明文です"
}
5. translation.json
から変換後の文字列を出力
src/locales/ja/translation.json
に基づき、description_text
がこれは説明文です
に変換される
おわりに
Reactでの多言語対応は、i18nextとStorybookを組み合わせることで、UIごとに簡単に確認できました。
特にチーム開発においては、Storybookによる翻訳確認が非常に有効だと思われます。