# General Translation Knowledge Base: i18n の翻訳キーはどのように命名すべきですか？
URL: https://generaltranslation.com/ja/kb/i18n-key-naming.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: キーは英語の文言ではなく、テキストが表示される場所と意味に基づいて命名します（例: checkout.summary.title）。英語が同じでも、用途が異なるものにはそれぞれ別のキーを割り当ててください。たとえばドイツ語では、ボタンの Open は Öffnen、ステータスの Open は Offen と訳されます。
Category: 国際化
Last updated: 2026-10-20
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-20

キーとは、`t('summary.title', { ns: 'checkout' })` のように、コードが翻訳を参照する際に使う識別子です。適切に命名されたキーは、文言を修正しても変える必要がなく、テキストの表示箇所を翻訳者に伝えられ、使われなくなったキーも見つけやすくなります。以下の規約は、i18next、react-i18next、Rails I18n、vue-i18n をはじめ、キー付きの JSON や YAML を読み込むあらゆるライブラリに当てはまります。例では i18next の構文を使用しており、i18next 26.5.3 で動作を確認しています。

## 1. 機能や画面ごとに名前空間を分ける

すべてのキーは、それが属するプロダクトの領域から始め、コンポーネント、要素の順に続けます。

* ✅ `checkout.summary.title`, `settings.billing.cancelButton`
* ❌ `title1`, `text_47`, `newString`

先頭のセグメントが別ファイルになっている場合、それはキーのパスの一部ではなく名前空間として扱われます。`summary.title` を `checkout.json` に格納した場合、i18next では `t('summary.title', { ns: 'checkout' })` または `t('checkout:summary.title')` で参照できます。一方、`t('checkout.summary.title')` はデフォルトの名前空間内で `checkout` オブジェクトを探すため、キー文字列がそのまま返されます。

プレフィックスがあれば、テキストがどこに表示されるのかが翻訳者に伝わり、カタログをファイルごとに分割することもできます。i18next ではこれらのファイルを[名前空間](https://www.i18next.com/principles/namespaces)と呼び、ビュー、機能、遅延読み込みモジュールの単位で分割したうえで、「保存」や「キャンセル」などのラベル用に `common` 名前空間を用意することを推奨しています。React では、react-i18next の `useTranslation('checkout')` で名前空間を読み込めます。また、[`keyPrefix` オプション](https://react.i18next.com/latest/usetranslation-hook)を使えば深いパスを短く書けます。

## 2. 文言ではなく意味を表す

キー名は、マーケティング担当者が文章を書き換えても通用するものにしましょう。

* ✅ `auth.login.submit`
* ❌ `auth.login.clickHereToSignInNow`

後でボタンの表示が「Continue」に変わっても、1つ目のキーは正確なままです。一方、2つ目のキーはもう存在しないテキストを表すことになり、いずれ誰かがキー名を変更することになります。その結果、すべての参照が壊れ、翻訳が宙に浮いてしまいます。

## 3. キーは英語の文字列ごとではなく、文脈ごとに1つ用意する

英語では同じ表記の文字列でも、翻訳が異なることはよくあります。ボタン上の「Open」は動詞ですが、チケットのステータスとしての「Open」は形容詞です。ドイツ語では前者に *Öffnen*、後者に *Offen* を使います。

* ✅ `files.actions.open` と `tickets.status.open`
* ❌ 1つの `common.open` を両方で使い回す

共有の `common` 名前空間は、キャンセルボタンのように、どこで使っても意味が変わらないラベルだけに使ってください。翻訳元テキストをキーとするシステムでは、同じ問題を文脈によって解決します。GNU gettext の [`msgctxt`](https://www.gnu.org/software/gettext/manual/html_node/Contexts.html) を使えば、1つの英語の文字列に2つの翻訳を持たせられます。

## 4. JSONはネスト形式かフラット形式のどちらかに統一し、混在させない

`checkout.json` 内では、i18next の `keySeparator` のデフォルトが `.` であるため、`summary.title` はパスとして解釈されます。どちらの形式でも動作しますが、すべてのファイル、レビュアー、ツールの間で認識がずれないよう、どちらか一方に統一してください。

```json title="locales/en/checkout.json (nested)"
{
  "summary": {
    "title": "Order summary",
    "taxNotice": "Tax is calculated at checkout."
  }
}
```

```json title="locales/en/checkout.json (flat)"
{
  "summary.title": "Order summary",
  "summary.taxNotice": "Tax is calculated at checkout."
}
```

フラットなファイルの場合、i18next の[設定ドキュメント](https://www.i18next.com/overview/configuration-options)では `keySeparator` を `false` にすることが推奨されています。あわせて、大文字・小文字の表記規則 (`camelCase` または `snake_case` のセグメント) も1つに決め、すべてのファイルで統一してください。

## 5. ライブラリの複数形サフィックスと文脈サフィックスを使用する

i18next はサフィックスで複数形を選択するため、変数名は `count` にする必要があります。`_zero` エントリは、count が 0 のときに言語の複数形規則を上書きします。また、序数の場合は `_ordinal` を付加します。

```json title="locales/en/checkout.json"
{
  "cart": {
    "itemCount_zero": "Your cart is empty",
    "itemCount_one": "{{count}} item",
    "itemCount_other": "{{count}} items"
  }
}
```

`t('cart.itemCount', { count: 0 })` は「Your cart is empty」を返し、1 の場合は「1 item」、5 の場合は「5 items」を返します。複数形カテゴリがより多い言語では、`itemCount_few` や `itemCount_many` などのキーが追加されます。 ([i18next の複数形ドキュメント](https://www.i18next.com/translation-function/plurals)を参照してください。各言語のカテゴリについては [ICUメッセージ形式とは？](/kb/icu-message-format) を参照してください。) 

* ✅ `itemCount_one`、`itemCount_other`、および性別によって変わるテキストでは `friend_male` や `friend_female` のような [文脈](https://www.i18next.com/translation-function/context) キー
* ❌ `itemCount_singular` や `itemCount_plural` のような独自のサフィックス (ライブラリに選択されません) 

一方、ICUメッセージ形式を基盤とするライブラリ (react-intl、next-intl、Lingui) では、すべての複数形を1つのキーの1つのメッセージ内にまとめて保持します。

## 6. 複数のキーを組み合わせて文を作らない

語順は言語によって異なるため、複数のキーに分割された文は正しく翻訳できません。

* ❌ `t('account.hello') + name + t('account.welcomeBack')`
* ✅ プレースホルダーを含む1つのキーにする: `"account.welcome": "Hello, {{name}}! Welcome back."`

メッセージに数量が含まれる場合も同様に、規約5のサフィックスを使い、各複数形で文全体をまとめて記述してください。

[GNU gettext マニュアル](https://www.gnu.org/software/gettext/manual/html_node/Preparing-Strings.html)でも、カタログについて同じルールが示されています。つまり、文は丸ごと翻訳し、連結ではなく書式文字列を使用するということです。

## 7. 安定したキーを使うか、原文をキーにするかを決める

すべてのシステムで名前を考える必要があるわけではありません。重要なのは、識別子を誰が管理するかです。

| アプローチ                           | 例                                        | 長所                              | コスト                                             |
| ------------------------------- | ---------------------------------------- | ------------------------------- | ----------------------------------------------- |
| セマンティックキー (i18next、Rails I18n)  | `t('summary.title', { ns: 'checkout' })` | 文言を修正してもコードに影響しない。キーが使用箇所を表す    | 誰かがすべてのキーに名前を付け、分類し、不要なものを削除し続ける必要がある           |
| 原文をキーにする (gettext)              | `_("Order summary")`                     | コードの可読性が保たれる。命名の手間がない           | 英語を修正すると新しいエントリが作成される。同一テキストの衝突には `msgctxt` が必要 |
| インラインテキストから生成される ID (FormatJS)  | `defaultMessage="Order summary"`         | メッセージが使用箇所のそばに置かれる。ID は自動で付与される | ビルドプラグインと抽出ステップが必要                              |

文言をコードベースの外で管理する場合 (たとえば、コンテンツチームが TMS で文字列を編集する場合) や、Web アプリとモバイルアプリで 1 つのカタログを共有する場合は、セマンティックキーを使用してください。開発者自身が文言を書き、ユーザーに表示される言葉をコードレビューで確認したい場合は、原文またはインラインメッセージを使用してください。

## 8. キーをURL、分析、ロジックに使わない

キーと翻訳済みの文字列は表示専用です。`t('checkout:cta')` を分析イベント名として送信しないでください (ロケールごとに別々のイベントとして記録されてしまいます) 。また、キーからルートのスラッグを生成したり、`label === t('status.open')` で条件分岐したりするのも避けてください。代わりに、固定のイベント名、自分で管理するスラッグ、enum やステータスコードを使いましょう。そうすれば、キー名を変更したり翻訳を編集したりしても、ダッシュボードやリンク、条件分岐が壊れることはありません。

## 9. 未使用・未翻訳のキーを自動でクリーンアップする

カタログは時間とともに実態とずれていきます。コンポーネントを削除してもキーは残り、新しいキーは未翻訳のままリリースされます。CI でチェッカーを実行しましょう。

* **i18next**: [`i18next-cli`](https://github.com/i18next/i18next-cli) は、非推奨となった `i18next-parser` の後継ツールです。小規模なテストプロジェクトで試したところ、`npx i18next-cli status --unused` はファイルを一切変更せずに、孤立した `oldPromoBanner` キーを報告しました。続けて `npx i18next-cli extract` を実行するとそのキーが削除され (`removeUnusedKeys` オプションのデフォルトは `true`) 、`itemCount_one` や `itemCount_other` を含むすべてのキーについて、空のドイツ語エントリが書き込まれました。`npx i18next-cli status` は未翻訳のキーが残っている間はエラーで終了します。また、`rename-key` を使うと、翻訳元ファイルとロケールファイルの両方でキー名をまとめて変更できます。``t(`status.${code}`)`` のように実行時に組み立てられるキーは静的解析では検出できないため、`extract` はこれらを未使用とみなして削除してしまいます。こうしたプレフィックスは `preservePatterns` オプションに列挙する (例: `'status.*'`) か、コード内で各キーを省略せずに記述してください。
* **Rails**: i18n-tasks は、Ruby や ERB のコードを解析して未翻訳および未使用のキーを報告します。 ([General Translation と i18n-tasks の比較](/kb/general-translation-vs-i18n-tasks)を参照してください。)

## General Translation におけるキーの扱い

`gt-react` または `gt-next` の [`<T>`](/docs/react/reference/components/t) コンポーネントを使えば、英語のテキストはコンポーネント内にそのまま記述でき、キーに名前を付ける必要もありません：

```tsx title="CheckoutSummary.tsx"
import { T } from 'gt-react';

export function CheckoutSummary() {
  return (
    <T>
      <h2>Order summary</h2>
      <small>Tax is calculated at checkout.</small>
    </T>
  );
}
```

[`npx gt translate`](/docs/cli/reference/commands/translate) は翻訳元に現在残っているコンテンツを抽出するため、コンポーネントを削除すれば、そのキーを手作業で管理する必要もなくなります。ただし、「Open」を異なる意味で使い分ける場合は、引き続き文脈が必要です。`<T context="Ticket status">Open</T>` と記述するか、[`useGT`](/docs/react/reference/hooks/use-gt) で `gt('Open', { $context: 'Ticket status' })` と記述してください。[`<T>`](/docs/react/reference/components/t) の任意の [`id`](/docs/react/reference/components/t#id) プロパティ、または翻訳関数の `$id` オプションを使うと、翻訳エディターで使う安定した識別子をエントリに付与できます。 ([翻訳ファイルなしで i18n はできますか？](/kb/i18n-without-translation-files)を参照してください。) 

キーを使いたいチームは、引き続きキーを使えます。`dictionary.json` などの翻訳元辞書を 1 つ作成し、[`useTranslations`](/docs/react/reference/hooks/use-translations) で読み込みます。この辞書も同じコマンドで翻訳されます。また、辞書に存在しない id を参照した場合は、キーがそのままレンダリングされるのではなく、例外をスローします。 ([辞書を使った翻訳](/docs/react/guides/translating-with-dictionaries)を参照してください。) 既存の i18next や next-intl の JSON ファイルはそのままの形式で翻訳できます。さらに、対応ファイルである [`.metadata.json` ファイル](/docs/cli/reference/keyed-metadata) を使えば、キーごとに文脈や文字数制限を追加できます。これは慣例 3 をキーベースで実現する方法にあたります。

## 重要なポイント

* キーは配置場所と意味に基づいて命名します (`checkout.summary.title`) 。文言や位置に基づく命名 (`text_47`) は避けてください。
* 動詞の「Open」とステータスの「Open」には別々のキーを割り当てます。キーを共有するのは、意味がまったく同じ場合に限ります。
* 複数形のサフィックスは、ライブラリの規則に厳密に従います。i18next では `_one`、`_other`、`_zero` を使い、ICU 系のライブラリでは複数形を 1 つのメッセージにまとめます。
* CI で `i18next-cli status --unused` や i18n-tasks を実行し、未使用のキーや不足しているキーが溜まらないようにします。
* General Translation の [`<T>`](/docs/react/reference/components/t) ならキーは不要です。キーを使いたいチーム向けには、[`useTranslations`](/docs/react/reference/hooks/use-translations) による辞書モードも用意されています。

## Related questions

- [翻訳ファイルなしでi18nは実現できますか？](https://generaltranslation.com/ja/kb/i18n-without-translation-files.mdx): はい。General Translationの gt-react と gt-next ライブラリを使えば、翻訳キーも、言語ごとに管理するJSONファイルもなしで、ReactとNext.jsのi18nを実現できます。文言は `<T>` コンポーネント内のJSXにインラインで記述したままで、gt translate コマンドがコードから得た文脈をもとに、ビルド時に各言語の翻訳を生成します。さらにLocadexを使えば、プルリクエストを通じて翻訳を常に最新の状態に保てます。
- [General Translation と i18n-tasks：どちらを使うべきか？](https://generaltranslation.com/ja/kb/general-translation-vs-i18n-tasks.mdx): i18n-tasks は、Rails I18n の不足キーや未使用キーを検出し、ロケールファイルを整理し、Google Translate、DeepL、OpenAI、Yandex、watsonx を使って不足キーを補完できる Ruby gem です。General Translation は、用語集、カスタムプロンプト、ダッシュボードでのレビューを活用してロケールファイル全体を翻訳します。両者は役割が異なるため、多くのチームにとっては併用も有効です。
- [i18next の代替：General Translation と i18next の比較](https://generaltranslation.com/ja/kb/general-translation-vs-i18next.mdx): テキストを React コンポーネント内にインラインで記述したまま、JSX 構造とプロダクトの文脈を活かして翻訳を生成したい場合は、General Translation を選びましょう。i18next を使い続けながら、General Translation で既存のカタログを翻訳することもできます。i18next はメッセージのレンダリングと複数形の選択を担いますが、翻訳の生成には別のサービスが必要です。
- [ICUメッセージ形式とは？](https://generaltranslation.com/ja/kb/icu-message-format.mdx): ICUメッセージ形式は、変数、複数形、select による選択、序数を1つの翻訳可能な文字列で表現するための構文です（例：{count, plural, one {# file} other {# files}}）。各言語は必要な CLDR の複数形カテゴリだけを使用します。英語では one と other を使い、ポーランド語ではさらに few と many が加わります。
- [翻訳されていないハードコードされた文字列を見つけるにはどうすればよいですか？](https://generaltranslation.com/ja/kb/find-hardcoded-strings.mdx): CI でリンターを実行し、ユーザー向けの文字列リテラルを検出します。たとえば JSX なら eslint-plugin-i18next の no-literal-string ルール、Android なら Android Lint の HardcodedText チェック、Rails なら erb_lint の HardCodedString リンターが使えます。さらに、疑似ロケールでアプリを一通り操作し、静的チェックでは追跡できないテキストを洗い出します。

## Previous and next questions

- Previous question: [i18n の JSON ファイルを翻訳するには？](https://generaltranslation.com/ja/kb/translate-json-files.mdx)
- Next question: [ICUメッセージ形式とは？](https://generaltranslation.com/ja/kb/icu-message-format.mdx)

## Sitemap

See the [Knowledge Base sitemap](https://generaltranslation.com/ja/kb/sitemap.md) for every article.
