BluePeriod Docs
開発

i18n / 国際化システム

i18nextとi18next-cliを使用した国際化対応のワークフローと仕様

07 - i18n / 国際化システム


1. 概要

BluePeriodにおける国際化(i18n)は、i18nextエコシステムを中心に構築されています。本ドキュメントでは、i18next-cliを使用した自動化されたワークフローと、翻訳管理の仕様について記述します。

1.1 i18nextエコシステム

ライブラリ役割
i18next国際化の基盤フレームワーク
react-i18nextReactコンポーネントでの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:typesTypeScript型定義を生成
bun i18n:status翻訳状況を確認
bun i18n:lintハードコードされた文字列を検出
bun i18n:watchファイル変更を監視して自動抽出
bun i18n:ciCI用抽出(変更時に失敗)
  • root から
コマンド説明
next:i18n:extractソースコードから翻訳キーを抽出 (実行パス: cd next-app && bun i18n:extract)
next:i18n:typesTypeScript型定義を生成 (実行パス: 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:ciCI用抽出(変更時に失敗)(実行パス: cd next-app && bun i18n:ci)

2.4 開発ワークフロー

i18nの具体的な開発プロセスは以下の通りです:

  1. 新しいキーの追加: コンポーネント内で t('new.key') を使用
  2. 抽出: bun i18n:extract で翻訳ファイルを更新
  3. 翻訳: 各言語の translation.json に翻訳を追加
  4. 型生成: bun i18n:types で型定義を更新

2.5 extract実行時の安全手順

removeUnusedKeys: true のもとで bun i18n:extract を実行すると、動的参照されている翻訳キーが削除される危険性があります。extractの実行は以下の手順に従ってください。

事前確認(extractの前に)

  • preservePatternsの網羅性確認: i18next.config.tspreservePatterns に、今回の変更で新たに動的参照(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
検出順序cookienavigatorhtmlTag
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 新規キーの追加

  1. コンポーネントで t('new.key') を使用
  2. bun i18n:extract で翻訳ファイルを更新
  3. 各言語の translation.json に翻訳を追加
  4. 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個の翻訳を補完
ハードコードされたキー名文章そのままのキー名を適切な名前に変更
動的キーの削除preservePatternsagent.tools.*.* を保護

7. 関連ドキュメント

ドキュメント関連内容
07_locale_systemBCP 47言語タグの管理
02_technology_stacki18next等の技術スタック
06_development_guidelinesi18n実装ガイドライン
2026-05-02_1450_reference_i18nexti18next-cliのリファレンスガイド
2026-05-02_1530_report_i18n-refactoringi18nリファクタリング完了レポート

On this page