翻訳ファイルの構造、キー命名規則、補間構文、複数形ルール、UI設計ガイドライン。すべてのプロダクトで一貫した多言語体験を実現する。
ロケールファイルは JSON 形式で i18n/locales/ に配置する。TypeScript ヘルパーは i18n.ts にシングルトンとして提供。
各ロケールファイルは $meta ブロックとネストされた翻訳キーで構成される。キーはドット区切りでアクセスする。
| フィールド | 型 | 説明 | 例 |
|---|---|---|---|
locale | string | BCP 47 ロケールコード | "ja", "en", "zh-Hans" |
name | string | 英語名 | "日本語" |
nativeName | string | 母語表記 | "日本語" |
direction | "ltr" | "rtl" | テキスト方向 | "ltr" |
pluralRule | string | 複数形ルール | "other" (ja), "one_other" (en) |
version | string | 翻訳バージョン | "1.0.0" |
lastUpdated | string | 最終更新日 | "2026-04-15" |
キーはドット区切りの階層構造。camelCase で統一し、画面やコンポーネントごとにグループ化する。
| ルール | 説明 | 例 |
|---|---|---|
| camelCase | すべてのキーは camelCase | settings.general.startOnBoot |
| 画面名.セクション.項目 | 3〜4階層以内に収める | dashboard.stats.totalRequests |
| _label / _accel | メニュー項目のラベルとアクセラレータ | menu.file._label → "ファイル(F)" |
| _one / _other | 英語など複数形ルールのあるロケール用サフィックス | minutesAgo_one / minutesAgo_other |
| 共通キーは common.* | OK / Cancel など複数画面で使うもの | common.save, common.cancel |
| a11y.* で分離 | スクリーンリーダー用テキストは専用名前空間 | a11y.skipToContent |
画面・機能ごとに名前空間を分ける。dashboard.activity.titlesettings.notifications.enabled
フラットに並べて衝突させる。dashboardActivityTitlesettingsNotificationsEnabled
意味のあるキー名にする。errors.validation.required
キー名だけで文脈がわかる。
連番や略語を使う。err.v.001
メンテナンスが困難になる。
{{変数名}} 構文で翻訳テキスト内に動的な値を埋め込む。変数名は英字の camelCase。
日本語には複数形がないため、1つのキーで済む。英語など複数形のある言語では _one / _other サフィックスで分岐する。
| pluralRule | 対象言語 | サフィックス | 説明 |
|---|---|---|---|
"other" |
JA 日本語、中国語、韓国語 | なし(キーそのまま) | 数量に関わらず同じ表現 |
"one_other" |
EN 英語、ドイツ語、フランス語 | _one / _other |
count === 1 なら _one、それ以外は _other |
翻訳するとテキスト長が変化する。UIが壊れないよう、レイアウトに余裕を持たせる設計が必須。
| 日本語 → 言語 | 伸長率目安 | 対策 |
|---|---|---|
| 英語 (EN) | +20〜40% | ボタンやラベルは min-width ではなく padding で余裕を確保 |
| ドイツ語 (DE) | +30〜50% | カラム幅を固定しない。flex-shrink / text-overflow: ellipsis を活用 |
| フランス語 (FR) | +25〜40% | ツールチップやメニューは最大幅を設けて折り返し可能に |
| 中国語 (ZH) | -10〜+10% | 日本語と近い長さだが漢字密度が異なる場合あり |
| 韓国語 (KO) | -5〜+15% | 日本語と同程度 |
| アラビア語 (AR) | +20〜30% | RTL レイアウト対応が必須(後述) |
ボタンは padding: 8px 20px で伸縮可能にする。テキストが長くなっても自然にフィット。
ボタンに width: 120px と固定幅を指定する。ドイツ語で文字が溢れる。
アラビア語やヘブライ語に対応する場合、レイアウトをミラーリングする必要がある。CSS 論理プロパティを活用する。
| 物理プロパティ(避ける) | 論理プロパティ(推奨) |
|---|---|
margin-left | margin-inline-start |
margin-right | margin-inline-end |
padding-left | padding-inline-start |
padding-right | padding-inline-end |
text-align: left | text-align: start |
text-align: right | text-align: end |
left: 0 | inset-inline-start: 0 |
border-left | border-inline-start |
Intl API を使い、ロケールに応じたフォーマットを適用する。翻訳ファイルにフォーマットをハードコードしない。
各言語に適したフォントスタックを定義し、文字化けや見た目の不統一を防ぐ。
| 言語 | font-family |
|---|---|
| JA 日本語 | 'Inter', 'Hiragino Sans', 'Yu Gothic UI', 'Meiryo', system-ui, sans-serif |
| EN 英語・欧州 | 'Inter', system-ui, -apple-system, sans-serif |
| 🇨🇳 簡体字中国語 | 'Inter', 'PingFang SC', 'Microsoft YaHei', system-ui, sans-serif |
| 🇰🇷 韓国語 | 'Inter', 'Apple SD Gothic Neo', 'Malgun Gothic', system-ui, sans-serif |
| RTL アラビア語 | 'Inter', 'SF Arabic', 'Segoe UI', 'Tahoma', sans-serif |
i18n.ts が提供するシングルトン API のリファレンス。フレームワーク非依存で Electron / Tauri / Web どこでも動く。
| メソッド / プロパティ | 説明 | 戻り値 |
|---|---|---|
i18n.init(options) | 初期化。loader 関数とデフォルトロケールを設定 | void |
i18n.load(locale) | ロケールを読み込み・切替。DOM の lang / dir も更新 | Promise<void> |
i18n.t(key, params?) | 翻訳テキストを取得。見つからなければキーを返す | string |
i18n.tp(key, count, params?) | 複数形を自動解決して翻訳を取得 | string |
i18n.has(key) | キーが存在するか確認 | boolean |
i18n.locale | 現在のロケール | string |
i18n.dir | テキスト方向("ltr" | "rtl") | string |
i18n.locales | 読み込み済みロケール一覧 | string[] |
i18n.meta | 現在ロケールのメタデータ | LocaleMeta |
| 関数 | 説明 |
|---|---|
detectLocale(supported, default?) | ブラウザ / OS の言語設定から最適なロケールを自動選択 |
extractKeys(obj, prefix?) | JSON から全キーパスを配列で抽出($meta を除外) |
compareLocales(base, target) | 2つのロケール間の翻訳カバレッジを比較。missing / extra / coverage% を返す |
新しいUIテキストを追加する際の手順。一貫性を保つために、必ずベースロケール(日本語)から開始する。
新しいキーをまず ja.json に追加する。キーの命名規則に従い、適切な名前空間に配置。
同じキーを en.json に追加し、英語翻訳を記述。複数形がある場合は _one / _other サフィックスを忘れずに。
対応しているすべてのロケールファイルに翻訳を追加。未翻訳のまま残すとフォールバックが効く。
compareLocales() でカバレッジを確認。100% でなければ不足キーを特定して追加する。
各ロケールに切り替えて表示を確認。テキスト伸長でレイアウトが崩れていないかチェック。
翻訳を更新したロケールの lastUpdated と version を更新して完了。
ベースロケールとターゲットロケールの JSON を貼り付けて、不足キーとカバレッジ率をリアルタイムで確認。
多言語対応で守るべき基本ルール。
UIテキストはすべてロケールファイルに外出しする。コード内にハードコードしない。
コード内に "保存しました" と直書きする。翻訳できなくなる。
日付・数値は Intl API でフォーマットする。ロケールが変わっても正しく表示される。
日付を "2026/04/15" とハードコードする。US では "04/15/2026" が期待される。
CSS 論理プロパティ(margin-inline-start)を使い、RTL でも自動でミラーリング。
margin-left / padding-right など物理プロパティで RTL 対応をサボる。
文字列連結ではなく補間を使う。"{{field}}は必須です" — 語順が異なる言語にも対応可能。
field + "は必須です" と文字列結合する。英語では "is required" が後に来るとは限らない。
ボタンやラベルは padding ベースで伸縮可能に。テキスト伸長に自然に対応。
固定幅 width: 100px でボタンを作る。ドイツ語に切り替えたら溢れる。
Senastra Design System — i18n Guide v1.0.0