Skip to content

多言語対応 ​

Castor の UI は简体中文(zh-CN)、English(en-US)、日本語(ja-JP)に対応しています。ユーザーはトップバーの言語切り替えから言語を選び、選択内容はブラウザに保存されます。初回アクセス時はブラウザの言語に合わせて自動で選ばれ、一致するものがなければ英語になります。

基本の規約:中国語の原文がそのままキー ​

コードには中国語の原文を直接書き、その原文を翻訳キーとしても使います。

tsx
const { t } = useTranslation()

t('保存')
t('共 {{count}} 条', { count })
  • 中国語には翻訳ファイルが不要です。訳文が見つからない場合はキーそのもの、つまり中国語がそのまま表示されます。
  • 英語と日本語の訳文は JSON ファイルに「中国語 → 訳文」の形式で書きます。

こうすることで、コードを書くときに文言ごとにキー名を考える必要がなくなり、コードの読み心地も画面と一致します。

フロントエンド ​

翻訳ファイル ​

場所内容
ページディレクトリ内の locales/en-US.json、locales/ja-JP.jsonそのページの文言。例:apps/web/src/modules/admin/pages/users/locales/
apps/web/src/locales/en-US.json、ja-JP.json共通の文言
apps/web/src/locales/menus/en-US.json、ja-JP.jsonメニュー名。メニューの code をキーに翻訳

すべての locales/*.json はビルド時に 1 つの名前空間にマージされます(locales/menus/ 配下のメニューのファイルは別の menu 名前空間に入ります)。同じディレクトリにある en-US.json と ja-JP.json には、同じキーが含まれていなければなりません。

ページの翻訳の例(locales/en-US.json):

json
{
  "导入用户": "Import users",
  "删除用户 {{name}}?": "Delete user {{name}}?"
}

t() が必要な文言 ​

共通コンポーネントは、渡された文字列のプロパティを自動で翻訳します。中国語をそのまま書き、訳文を補うだけで済みます。

  • PageHeader、Panel のタイトル
  • DataTable の列の title
  • FormFields の label、placeholder、options、rules 内の文言
  • FilterSelect、SegmentedTabs、StatusBadge、StatCard、RowActions、ConfirmAction、FormDialog などのコンポーネントの文言プロパティ
  • toast.success('固定中文') のような固定の文言

次の場合は必ず t() で囲みます。

  • JSX に直接書いた中国語のテキスト
  • ネイティブ要素の aria-label、title、placeholder
  • 変数を含む文言:t('删除用户 ?', { name }) のように書き、中国語のテンプレート文字列は使わない
  • グラフの軸や凡例など、その他の表示経路

デモ用のコンテンツは翻訳しない

サンプルデータやサンプルドキュメントなどのデモ用コンテンツは UI の文言ではなくデータなので、コメントで印を付けておくとスキャン時にスキップされます。

  • 1 行単位:直前の行に // i18n-ignore-next-line を書く
  • ファイル全体:ファイル内に i18n-ignore-file コメントを書く

メニュー名の翻訳 ​

メニュー名は(中国語で)データベースに保存されています。フロントエンドはメニューの code をもとに apps/web/src/locales/menus/<lang>.json から訳名を探し、見つからない場合はデータベース上の名前を表示します。

json
{
  "system_users": "Users",
  "system_roles": "Roles"
}

メニューを追加するときは、en-US.json と ja-JP.json の両方に対応する code を追加してください。フロントエンドのテストが、seed-rbac.ts のすべてのメニューコードに英語と日本語の訳名があることをチェックします。

バックエンドのエラーメッセージの翻訳 ​

バックエンドのコードでは、これまでどおり中国語のエラーをスローします。

ts
throw new ServiceError('用户名已存在')

フロントエンドの request.ts は、すべてのリクエストに Accept-Language ヘッダーを付けます。バックエンドはレスポンスを送る前に、このヘッダーに従って JSON レスポンスの error、message、およびインポートのエラー行の error_rows[].reason を対応する言語に翻訳します。対応言語を指定していないリクエスト(curl や API トークンのクライアントなど)には英語で返します。訳文が登録されていない文言は中国語のまま返され、エラーにはなりません。

新しく追加したエラーや通知の文言は、apps/api/src/i18n/messages.ts に英語と日本語の訳文を登録してください。

ts
// Exact messages
export const MESSAGES = {
  '用户名已存在': { 'en-US': 'Username already exists', 'ja-JP': 'ユーザー名は既に存在します' },
}

// Messages built from template literals: regex on the Chinese text, $1… in the translation
export const PATTERNS = [
  { re: /^菜单编码 (.+) 已存在$/, 'en-US': 'Menu code $1 already exists', 'ja-JP': 'メニューコード $1 は既に存在します' },
]

上記は説明用の例です。実際のエントリーはモジュールごとにグループ分けして messages.ts に書かれています。

インポート / エクスポートの列見出しは中国語のまま

インポート / エクスポートするファイルの列見出しは UI の言語によって変わらず、常に中国語です。列見出しを含むエラーメッセージでも、列見出しの部分は中国語のままです。

スキャンとテストによるガード ​

フロントエンドのスキャン ​

apps/web/scripts/i18n-scan.mjs は 3 種類の問題をスキャンします。

問題意味
missing中国語の文字列に対して、どの locales/*.json にも英語または日本語の訳文がない
jsx-text中国語が JSX テキストに直接書かれていて、t() を通していない
templateテンプレート文字列に中国語が含まれている
bash
node apps/web/scripts/i18n-scan.mjs                                  # src 全体をスキャン。問題があれば終了コード 1
node apps/web/scripts/i18n-scan.mjs src/modules/admin/pages/users    # 特定のディレクトリだけをスキャン(apps/web からの相対パス)
node apps/web/scripts/i18n-scan.mjs --json src/modules/admin/pages/users   # JSON で出力

新しいページのスキャン結果は、問題 0 件でなければなりません。

テスト ​

テストチェック内容
apps/web/test/i18n.test.ts各 locales/ ディレクトリの en-US と ja-JP のキーが同じであること。同じキーの訳文がファイル間で食い違っていないこと。seed-rbac.ts のすべてのメニューコードに英語と日本語の訳名があること。フロントエンドのソース全体のスキャンで問題がないこと
apps/api/test/i18n-messages.test.tsバックエンドのソースを解析して、ユーザーに返される可能性のある中国語の文言をすべて洗い出し、いずれも messages.ts に登録されていることをチェック

これらのテストは pnpm test と pnpm verify に含まれているため、訳文の書き漏れがあると検証ゲートで失敗します。

コードコメントは英語で書く ​

コードコメントは、フロントエンド、バックエンド、スクリプト、テスト、scaffold が生成するコードを含め、すべて英語で書きます。UI の文言は引き続き中国語の原文をキーとして書きます。

コメントの中でコードに実在する中国語の文字列(エラーメッセージ、翻訳キーなど)に触れる必要がある場合は、引用符またはバッククォートで囲んでください。apps/web/test/english-comments.test.ts が apps/api、apps/web、apps/mcp、docs/templates 配下のコメントをチェックします。

ページを追加するときのチェックリスト ​

  1. 画面の文字は中国語の原文で書く。
  2. JSX テキスト、ネイティブ属性、変数を含む文言には t() を使う。
  3. ページディレクトリに locales/en-US.json と locales/ja-JP.json を作成する。
  4. 新しいメニューは apps/web/src/locales/menus/ の 2 つのファイルに訳名を追加する。
  5. バックエンドで追加したエラーは apps/api/src/i18n/messages.ts に登録する。
  6. node apps/web/scripts/i18n-scan.mjs <ページディレクトリ> を実行し、問題が 0 件であることを確認する。

Released under the MIT License.