i18n / 国際化システム
i18nextとi18next-cliを使用した国際化対応のワークフローと仕様
07 - i18n / 国際化システム
- 最終更新: 2026-05-02
- 関連Issue: 2026-05-02_1500_issue_i18n-refactoring
- 実装Report: 2026-05-02_1530_report_i18n-refactoring
1. 概要
BluePeriodにおける国際化(i18n)は、i18nextエコシステムを中心に構築されています。本ドキュメントでは、i18next-cliを使用した自動化されたワークフローと、翻訳管理の仕様について記述します。
1.1 i18nextエコシステム
| ライブラリ | 役割 |
|---|---|
i18next | 国際化の基盤フレームワーク |
react-i18next | Reactコンポーネントでのi18next使用 |
i18next-browser-languagedetector | ブラウザ言語の自動検出 |
i18next-cli | 翻訳キーの自動抽出と型定義生成 |
2. i18next-cliによる自動化ワークフロー
2.1 導入の背景
i18next-cliを導入することで、以下の課題を解決しました:
- 翻訳キーの手動管理による肥大化と不整合
- 型定義の欠如による開発効率の低下
- 未使用キーの検出と削除の手動作業
2.2 設定ファイル
ファイル: next-app/i18next.config.ts
import { defineConfig } from 'i18next-cli';
export default defineConfig({
locales: ['en', 'ja', 'zh'],
output: 'src/i18n/locales/{{language}}/translation.json',
input: ['src/**/*.{ts,tsx}', 'app/**/*.{ts,tsx}'],
defaultNamespace: 'translation',
sort: true,
keySeparator: '.',
namespaceSeparator: ':',
removeUnusedKeys: true,
keepRemoved: [],
preservePatterns: [
'agent.tools.*.*', // 動的キーの保護
'home.greeting.*', // GreetingSectionの時間帯挨拶キー保護
'home.greeting.days.*', // GreetingSectionの曜日キー保護
],
TypeScript: {
declarationPath: 'src/types/i18next.d.ts',
enumTypes: false,
arrow: false,
parser: 'ts',
strictKeyNames: true,
}
});2.3 主要コマンド
- next-app から
| コマンド | 説明 |
|---|---|
bun i18n:extract | ソースコードから翻訳キーを抽出 |
bun i18n:types | TypeScript型定義を生成 |
bun i18n:status | 翻訳状況を確認 |
bun i18n:lint | ハードコードされた文字列を検出 |
bun i18n:watch | ファイル変更を監視して自動抽出 |
bun i18n:ci | CI用抽出(変更時に失敗) |
- root から
| コマンド | 説明 |
|---|---|
next:i18n:extract | ソースコードから翻訳キーを抽出 (実行パス: cd next-app && bun i18n:extract) |
next:i18n:types | TypeScript型定義を生成 (実行パス: cd next-app && bun i18n:types) |
next:i18n:status | 翻訳状況を確認 (実行パス: cd next-app && bun i18n:status) |
next:i18n:lint | ハードコードされた文字列を検出 (実行パス: cd next-app && bun i18n:lint) |
next:i18n:watch | ファイル変更を監視して自動抽出 (実行パス: cd next-app && bun i18n:watch) |
next:i18n:ci | CI用抽出(変更時に失敗)(実行パス: cd next-app && bun i18n:ci) |
2.4 開発ワークフロー
i18nの具体的な開発プロセスは以下の通りです:
- 新しいキーの追加: コンポーネント内で
t('new.key')を使用 - 抽出:
bun i18n:extractで翻訳ファイルを更新 - 翻訳: 各言語の
translation.jsonに翻訳を追加 - 型生成:
bun i18n:typesで型定義を更新
2.5 extract実行時の安全手順
removeUnusedKeys: true のもとで bun i18n:extract を実行すると、動的参照されている翻訳キーが削除される危険性があります。extractの実行は以下の手順に従ってください。
事前確認(extractの前に)
- preservePatternsの網羅性確認:
i18next.config.tsのpreservePatternsに、今回の変更で新たに動的参照(t(variable),t(\prefix.${var}`))が追加されていないか確認する。追加されている場合は、対応するパターンを先にpreservePatterns` に追加すること。 - 現在の翻訳状況を記録:
bun i18n:statusを実行し、現状が100%であることを確認する。100%でない場合は、先に欠落キーを翻訳して100%にしてからextractを実行すること。
実行後の検証(extractの後に)
- 翻訳状況の再確認:
bun i18n:statusを実行し、ja/zhが100%であることを確認する。 - 差分の意図性確認:
git diff src/i18n/locales/で、削除されたキーが意図的(デッドコード)であることを確認する。意図しない削除があった場合は、preservePatternsの不足が原因の可能性が高い。git checkoutで復元してからパターンを追加し、再度extractを実行すること。 - 空キーの翻訳: 新規追加されたキー(値が
""のもの)を全言語分、翻訳して埋めること。
よくある動的参照パターンとpreserve例
| 動的参照パターン | preservePatterns | 例 |
|---|---|---|
t(\prefix.${var}`)` | prefix.* | language.en, language.ja |
t(\prefix.${n}.field`)` | prefix.*.* | onboarding.step1.title |
t(\a.b.${x}.${y}`)` | a.b.*.* | agent.tools.*.* |
t(labelKey) (props経由) | parent.* | plotConfig.param.* |
2.7 動的キーの保護
i18next-cliは静的解析で t('key') を検出するため、t(variable) のように変数経由で参照されるキーは「未使用」と判定され、removeUnusedKeys: true のもとで削除されます。
preservePatterns を使うことで、特定パターンのキーを削除対象から除外できます:
preservePatterns: [
'agent.tools.*.*', // agent.tools.<tool_id>.label / .description を保護
'home.greeting.*', // GreetingSectionの時間帯挨择キー保護
'home.greeting.days.*', // GreetingSectionの曜日キー保護
'language.*', // bcp47.ts での言語名動的参照保護
'onboarding.*.*', // OnboardingDialog のステップ番号動的参照保護
'onboarding.*.*.*', // OnboardingDialog step6.links.* の保護
'plotConfig.*', // PlotConfigPanel の props 経由参照保護
'settings.categories.*', // SettingsPageClient のカテゴリ動的参照保護
'agentSettings.categories.*', // AgentSettingsPanel のカテゴリ動的参照保護
'publishWizard.tabs.tabLabels.*', // PublishPage のタブラベル動的参照保護
]パターン構文:
*はキーセパレータ(.)区切りで1セグメントにマッチ- 複数階層のネストには
*を階層数だけ並べる(例:agent.tools.*.*) :を使うとnamespace区切りとして扱われる(例:common:button.*)
2.8 翻訳状況の確認
2026-05-22時点での翻訳状況:
i18next Project Status
------------------------
🔑 Keys Found: 902
📚 Namespaces Found: 1
🌍 Locales: en, ja, zh
✅ Primary Language: en
Translation Progress:
- ja: [■■■■■■■■■■■■■■■■■■■■] 100% (893/893 keys)
- zh: [■■■■■■■■■■■■■■■■■■■■] 100% (893/893 keys)3. 翻訳ファイルの構造
3.1 ディレクトリ構造
next-app/
├── i18next.config.ts # i18next-cli設定
├── src/
│ ├── i18n/
│ │ ├── config.ts # i18next設定
│ │ └── locales/
│ │ ├── en/translation.json
│ │ ├── ja/translation.json
│ │ └── zh/translation.json
│ └── types/
│ └── i18next.d.ts # 自動生成される型定義3.2 型定義
ファイル: next-app/src/types/i18next.d.ts
// NOTE: resources is intentionally omitted from CustomTypeOptions to allow dynamic keys.
// The auto-generated resources.d.ts is kept for reference but not used for strict type checking.
// To restore strict typing, add `resources: Resources;` to the interface below.
declare module 'i18next' {
interface CustomTypeOptions {
enableSelector: false;
defaultNS: 'translation';
}
}※ 動的キー参照(t(variable))を許可するため、resources は意図的に省略されています。
4. i18n設定
4.1 クライアントサイド設定
ファイル: next-app/src/i18n/config.ts
| 設定項目 | 値 |
|---|---|
| フォールバック言語 | en |
| 検出順序 | cookie → navigator → htmlTag |
| Cookie名 | NEXT_LOCALE |
| キャッシュ先 | Cookie |
4.2 ミドルウェア(言語自動検出)
ファイル: next-app/src/proxy.ts
accept-language-parser を使用して、Accept-Language ヘッダーから最適な言語を判定し、Cookieに保存します。
[リクエスト受信]
↓
Accept-Language ヘッダー取得
↓
accept-language-parser で解析
↓
サポート言語から最適なものを選択
↓
Cookie 'NEXT_LOCALE' に保存(1年有効)
↓
[レスポンス返却]5. ベストプラクティス
5.1 新規キーの追加
- コンポーネントで
t('new.key')を使用 bun i18n:extractで翻訳ファイルを更新- 各言語の
translation.jsonに翻訳を追加 bun i18n:typesで型定義を更新
5.2 動的キーの使用
変数経由でキーを参照する場合は、preservePatterns にパターンを追加してください。
5.3 翻訳の不整合検出
PR時には bun i18n:ci を実行し、翻訳の不整合を自動検出してください。
5.4 単一JSON vs Namespace分割
i18nextは標準でnamespace分割をサポートしていますが、現状では単一ファイル(translation.json)を採用しています。
判断理由:
useTranslation()が51箇所すべてnamespace未指定(デフォルトtranslation)- namespace分割には全コンポーネントの修正が必要
- 現時点では単一ファイル +
preservePatternsで十分対応可能
将来の検討: ファイルの肥大化が問題になればnamespace分割を再検討
6. 解決済みの課題
以下はi18nリファクタリング(2026-05-02)により解決された課題の記録:
| 課題 | 解決内容 |
|---|---|
| ネスト競合 | manuscriptPanel.card.delete を文字列値からネスト構造に変更 |
| 未翻訳キー | model.* キーの6個の翻訳を補完 |
| ハードコードされたキー名 | 文章そのままのキー名を適切な名前に変更 |
| 動的キーの削除 | preservePatterns で agent.tools.*.* を保護 |
7. 関連ドキュメント
| ドキュメント | 関連内容 |
|---|---|
| 07_locale_system | BCP 47言語タグの管理 |
| 02_technology_stack | i18next等の技術スタック |
| 06_development_guidelines | i18n実装ガイドライン |
| 2026-05-02_1450_reference_i18next | i18next-cliのリファレンスガイド |
| 2026-05-02_1530_report_i18n-refactoring | i18nリファクタリング完了レポート |