メインコンテンツへ

i18n

Astar Management のロケールは ja と ja-plain(やさしい日本語)のみ です。英語ロケールは存在しません。en キーを追加しないでください。

原則は i18n-first: ユーザーに見えるすべての文字列は、必ず i18n キー経由で書きます。テンプレートに直書きした文字列は、ja-plain の差し替えや将来の用語統一を素通りしてしまいます。

一次資料は frontend/i18n/CONVENTIONS.md です。新しい key をどこに置くか迷ったときは、必ずこのページより先にそちらを確認してください。ここではその要点と、実際に事故が起きた罠を説明します。

二層 + グロッサリーの構造

frontend/i18n/locales/ja/
├── glossary.json              ← Astar 固有 entity 名の SSoT(最上位)
├── general.json
├── foundation/                ← 横断的な共通 UI 文言
│   ├── actions.json           ← 動詞 / ボタン
│   ├── common.json            ← フィールド名 / 一般語 / ステータス
│   ├── form.json              ← バリデーション / submit / cancel
│   ├── table.json             ← ソート / フィルター / ページネーション
│   ├── navigation.json        ← サイドバー / breadcrumb
│   ├── messages.json          ← トースト / 確認ダイアログ
│   ├── pickers.json           ← icon picker / color picker
│   ├── search.json
│   └── datetime.json
└── modules/{name}/domain.json ← module 固有のドメイン文言のみ

新しい key を追加するときの参照優先順序は次の3段階です。

  1. glossary.entities に該当があれば @:glossary.entities.X で参照する
  2. foundation.{section} に該当があれば @:foundation.{section}.X で参照する
  3. どちらにも無ければ modules/{name}/domain.json に新規追加する

module の domain.json に書いてよいのは、foundation のテンプレートでは表現できない、その module 固有のドメイン文言だけです。共通語彙を module 側で再定義しないでください。

glossary — entity 名の唯一の出所

glossary.entities は Astar 固有の18個の正準名詞(table / workspace / dashboard / record / template / role / user / member / widget / property / calendarEvent / storageDevice / tenant / folder / resource / document / file / view)の SSoT です。これらの語は 他のどこにも bare 文字列で書きません

// ❌ module 内で entity 名を hardcode
{ "modules": { "table": { "title": "テーブル" } } }

// ✅ linked message 経由
{ "modules": { "table": { "title": "@:glossary.entities.table" } } }

vue-i18n の @:foo.bar 構文で別 key を参照します。

{
  "modules": {
    "table": {
      "title": "@:glossary.entities.table",
      "subtitle": "{count}個の@:glossary.entities.table",
      "actions": {
        "create": "@:glossary.entities.table を作成"
      }
    }
  }
}
  • 単独参照: "@:glossary.entities.table"
  • 文中埋込: "新しい@:glossary.entities.table"
  • 補間との併用: "{count}個の@:glossary.entities.table"
  • ネストした linked message は使いません(深さ1まで)

entity 名を hardcode してはいけない理由は実利的です。glossary を linked message 化しておけば、ja-plain 側は glossary.entities を上書きするだけで全 module の用語が一括で切り替わります。 module 内に bare 文字列で書いてしまうと、その module だけ ja-plain の用語統一から漏れます。

foundation — 共通語彙の SSoT

エンティティに紐づかない属性名や動詞は foundation 側に集約します。

  • フィールド名(名前・説明・ステータス・タイプ・カテゴリ・タグ・アイコン・作成日時 …)→ foundation.common.fields が SSoT。各 module で再定義しません。
  • 動詞・ボタン文言(保存・キャンセル・削除・編集・新規作成・追加・検索・フィルター・エクスポート・コピー・複製 …)→ foundation.actions が SSoT。
// Do: foundation テンプレート + glossary entity の組み合わせ
toast.success(t('foundation.messages.success.targetCreated', { target: t('glossary.entities.table') }))

// Don't: foundation で表現できるテキストを module domain.json に書く
toast.success(t('modules.table.messages.created'))  // ❌

ja/index.ts マウント漏れの罠

frontend/i18n/locales/ja/index.ts は、foundation/*.jsonmodules/*/domain.json を1ファイルずつ import し、最終的な messages オブジェクトへ 手作業で列挙して マウントするファイルです。

// import 部分
import tagDomain from './modules/tag/domain.json'

// マウント部分(messages オブジェクトの組み立て)
modules: {
  // ...
  tag: tagDomain.modules.tag,
  // ...
}

i18n キーが JSON ファイルに存在していても、この index.ts の import / マウント列挙に追加されていなければ、そのキーは実行時に解決されません。t('modules.newFeature.title') は生のキー文字列がそのまま画面に表示され、値は空になります。

これは lint(missing-key チェック)では検出できません。JSON ファイル上はキーが存在しているため、静的解析からは問題なく見えるからです。新しい module の domain.json を追加したときは、必ず ja/index.ts の import とマウントの両方に追記し、実際に画面を目視で確認してください。 L3 のビジュアル検証が唯一の実効的な検知手段です。

動的キー namespace

t() に動的に組み立てたキー(t(modules.${moduleName}.title) のような形)を使う場合、ESLint の usedKeys リストへの登録が必要です。登録漏れは missing-key lint で検知されます。

過剰和訳禁止

ja-plain(やさしい日本語)は ja の差分 overlay ですが、ユーザーがすでに知っている外来語まで無理に和訳しません。次のカテゴリは 横文字のまま残します

  • 人系: メンバー / ユーザー
  • 装飾系: アイコン / タグ / バッジ
  • 記録系: メモ / ノート / コメント
  • 分類系: タイプ / カテゴリ / ステータス
  • 動作系: コピー / ペースト / キャンセル / プレビュー
  • ファイル系: ファイル / フォルダ / ダウンロード / アップロード
  • UI系: メニュー / サイドバー / ボタン / リンク / ログイン / パスワード
  • 意味ズレ語: ストレージデバイス / リソース / クラウドストレージ

和訳を採用してよいかどうかは次の3条件が すべて YES の場合のみです。1つでも NO なら横文字のままにします。

  1. Excel / freee / kintone 日本語版に一般化された置換語があるか
  2. 法律事務員(紙文化が長い人)にとって紙文化と繋がる語か
  3. 意味のズレや概念の欠落が起きないか

新しい module を追加するときの手順

  1. i18n/locales/ja/modules/{name}/domain.json を作成する
  2. entity 名は @:glossary.entities.X 経由で参照し、bare 文字列で書かない
  3. 共通フィールド名・動詞は @:foundation.{section}.X 経由で参照する
  4. module 固有のドメイン文言だけを domain.json に書く
  5. ja/index.ts の import とマウント列挙の両方に追記する(上記の罠を参照)
  6. ja-plain 側は基本的に書かない(主要 module 以外は ja に fall back する)

次の一歩