# General Translation Knowledge Base: ICUメッセージ形式とは？
URL: https://generaltranslation.com/ja/kb/icu-message-format.mdx
Docs index: https://generaltranslation.com/llms.txt
Description: ICUメッセージ形式は、変数、複数形、select による選択、序数を1つの翻訳可能な文字列で表現するための構文です（例：{count, plural, one {# file} other {# files}}）。各言語は必要な CLDR の複数形カテゴリだけを使用します。英語では one と other を使い、ポーランド語ではさらに few と many が加わります。
Category: ロケール別フォーマット
Last updated: 2026-10-20
Authors: Kevin Wu, Jackie Chen
Published: 2026-10-20

この構文は、Unicode Consortium による C/C++ および Java 向けの国際化ライブラリ ICU (International Components for Unicode) の MessageFormat クラスに由来します。FormatJS などの JavaScript ライブラリも同じ文法を実装しています。再設計版の MessageFormat 2 が登場したため、現在では MessageFormat 1 とも呼ばれます。

## ICUメッセージ形式はどのような問題を解決するのか？

断片をつなぎ合わせて文を組み立てるコードは、英語では動作しても、他の言語では破綻します。`'You have ' + n + ' files'` は、英語の語順と英語の2つの複数形をハードコードしています。ポーランド語では、同じ文に4つの形が必要です (1 plik、2 pliki、5 plików、1,5 pliku) 。また、性別によって変わる文 (「She replied」や「He replied」) では、多くの言語で他の単語も変化します。序数 (1st、2nd、3rd) にも独自の規則があります。

ICUメッセージ形式では、こうしたケースをすべて1つの文字列にまとめられます。翻訳者はすべての分岐を含めて文全体を確認し、自分の言語に合わせて書き直したうえで、文法上必要であれば分岐を追加・削除できます。[ICU ユーザーガイド](https://unicode-org.github.io/icu/userguide/format_parse/messages/)が各分岐に完結した文を書くよう推奨しているのも、同じ理由からです。翻訳者は、目に見えない断片の文法を直すことはできません。

## 構文と実行可能な例

以下の例はすべて、Node.js 24 上で FormatJS の [`intl-messageformat`](https://formatjs.github.io/docs/intl-messageformat) 12.1.4 を使って実行したものです。メッセージは一度だけ解析され、その後、値を渡して書式設定されます。

```js
import { IntlMessageFormat } from 'intl-messageformat';

const msg = new IntlMessageFormat(
  '{count, plural, =0 {You have no messages.} one {You have # message.} other {You have # messages.}}',
  'en'
);

msg.format({ count: 0 });    // 'You have no messages.'
msg.format({ count: 1 });    // 'You have 1 message.'
msg.format({ count: 1234 }); // 'You have 1,234 messages.'
```

### 引数

`{name}` は値を挿入します。`Hello, {name}!` に `{ name: 'Ada' }` を渡すと「Hello, Ada!」になります。型付き引数では値がロケールに合わせて書式設定されます。たとえば `Total: {price, number, ::currency/EUR}` に `1234.5` を渡すと、英語では「Total: €1,234.50」になります。

### plural、`#`、完全一致

`{count, plural, ...}` は、ロケールの複数形カテゴリ (`zero`、`one`、`two`、`few`、`many`、`other`) に応じて分岐を選択します。分岐内の `#` は、ロケールに合わせて書式設定された数値に置き換えられます。たとえば、ドイツ語のメッセージ `{count, plural, one {Sie haben # Nachricht.} other {Sie haben # Nachrichten.}}` は「Sie haben 1.234 Nachrichten.」と出力します。`=0` のような完全一致はカテゴリーよりも優先されます。上の例で「0 messages」ではなく「no messages」と表示されるのはこの仕組みによるものです。

同じ文を、ポーランド語で使われる分岐を使ってポーランド語で記述すると次のようになります：

```text
{count, plural, one {# plik} few {# pliki} many {# plików} other {# pliku}}
```

`pl` の場合、1、2、5、22、1.5 はそれぞれ &quot;1 plik&quot;、&quot;2 pliki&quot;、&quot;5 plików&quot;、&quot;22 pliki&quot;、&quot;1,5 pliku&quot; と書式設定されます。

### select

`select` は文字列値に応じて分岐を選択し、それ以外の値はすべて `other` の分岐で処理されます：

```text
{gender, select,
  female {She replied to your comment.}
  male {He replied to your comment.}
  other {They replied to your comment.}}
```

`{ gender: 'female' }` の場合は &quot;She replied to your comment.&quot;、`{ gender: 'nonbinary' }` の場合は &quot;They replied to your comment.&quot; になります。各分岐には文全体を含めてください。言語によっては、性別に応じて代名詞だけでなく動詞も変化するためです。

### selectordinal

`selectordinal` は序数のルールを使用します。英語の場合、序数のカテゴリは次の4つです：

```text
{place, selectordinal,
  one {You finished #st.}
  two {You finished #nd.}
  few {You finished #rd.}
  other {You finished #th.}}
```

順位が 1、2、11 の場合、出力はそれぞれ `You finished 1st.`、`You finished 2nd.`、`You finished 11th.` となります。3、4、22、103 の接尾辞は、それぞれ `rd`、`th`、`nd`、`rd` です。

### offset

`offset:1` は、カテゴリを選択して `#` を出力する前に数値から 1 を引くため、「あなたと他 N 人」のようなメッセージに適しています。完全一致の判定には元の値が使われます:

```text
{guests, plural, offset:1
  =0 {Nobody is going.}
  =1 {{host} is going.}
  one {{host} and # other person are going.}
  other {{host} and # other people are going.}}
```

`host: 'Mia'` の場合、ゲストが 0、1、2、5 人のときの出力は、それぞれ &quot;Nobody is going.&quot;、&quot;Mia is going.&quot;、&quot;Mia and 1 other person are going.&quot;、&quot;Mia and 4 other people are going.&quot; になります。

### ネストされた引数

引数はネストできます。ICU のガイドでは、`select` を外側、`plural` を内側に置き、各分岐には文全体を記述することが推奨されています：

```text
{gender, select,
  female {{count, plural, one {She has # new follower} other {She has # new followers}}}
  other {{count, plural, one {They have # new follower} other {They have # new followers}}}}
```

### アポストロフィとエスケープ

ASCII のアポストロフィは構文文字をクォートするために使われ、アポストロフィを 2 つ重ねると 1 つのアポストロフィとして出力されます。ICU 4.8 以降では、単独のアポストロフィがクォートの開始とみなされるのは、クォートが必要な文字の直前に置かれた場合に限られます。そのため、英語の通常の短縮形 (contraction) はそのまま問題なく使えます:

```text
It's {name}'s turn. Type '{name}' to insert a name. I''m here.
```

`{ name: 'Ada' }` を渡すと、`It's Ada's turn. Type {name} to insert a name. I'm here.` と出力されます。plural 内では、`'#'` はリテラルの `#` として出力されます。FormatJS の [ICU 構文ガイド](https://formatjs.github.io/docs/core-concepts/icu-syntax)では、human-readable なテキストにはタイポグラフィ用のアポストロフィ (’) を使うよう推奨しています。そうすれば、この問題そのものを避けられます。

## CLDR の複数形カテゴリとは？

これらのカテゴリは [Unicode CLDR の複数形規則](https://cldr.unicode.org/index/cldr-spec/plural-rules)で定義されており、JavaScript の `Intl.PluralRules` も同じデータに基づいています。いくつかの言語について、`Intl.PluralRules` が返すカテゴリは次のとおりです。

| 言語                        | 基数のカテゴリ                                      |
| ------------------------- | -------------------------------------------- |
| 英語 (`en`)                 | `one`, `other`                               |
| ポーランド語 (`pl`)、ロシア語 (`ru`) | `one`, `few`, `many`, `other`                |
| アラビア語 (`ar`)              | `zero`, `one`, `two`, `few`, `many`, `other` |
| 日本語 (`ja`)                | `other`                                      |

`one` は「ちょうど 1」を意味するわけではありません。たとえばロシア語では、21 も `one` に分類されます。数値の 1 そのものを指定したい場合にのみ `=1` を使用してください。React でコンポーネントを使って対応する方法については、[React で複数形を扱うには？](/kb/how-to-handle-plurals-in-react)を参照してください。

## よくある問題

* **構文エラーが後になって発覚する。** 波括弧が欠けていても、解析されるまではただの文字列にすぎず、解析の段階で `intl-messageformat` が `EXPECT_ARGUMENT_CLOSING_BRACE` という例外をスローします。CI でメッセージを解析または lint するか、事前にコンパイルしておきましょう。
* **`other` 分岐がない。** `other` のない plural に対して `intl-messageformat` は `MISSING_OTHER_CLAUSE` という例外をスローします。また、FormatJS では `select` にも `other` が必須です。
* **対象言語に合わない分岐。** 英語のメッセージには `one` と `other` がありますが、ポーランド語の翻訳ではさらに `few` と `many` が必要になり、日本語の翻訳では `other` だけで済みます。翻訳プロセスでは、分岐内のテキストを翻訳するだけでなく、分岐の追加や削除も行う必要があります。
* **断片化。** `{count} {count, plural, one {file} other {files}} deleted` のような書き方では、翻訳者が断片を並べ替えて訳すことになります。各分岐には文全体を入れてください。
* **方言の混在。** i18next のデフォルト構文は ICU ではなく、`{{name}}` 形式の変数と `key_one` のような複数形キーを使います。i18next で ICU を使いたい場合は、[`i18next-icu`](https://github.com/i18next/i18next-icu) プラグインを追加します。

## ICUメッセージ形式をサポートしているライブラリは？

* **ICU4J と ICU4C** は、それぞれ Java と C/C++ によるリファレンス実装です。
* **FormatJS**: [`intl-messageformat`](https://formatjs.github.io/docs/intl-messageformat) は react-intl の内部で使われているパーサー兼フォーマッターで、`::currency/EUR` のような数値・日付の skeleton やリッチテキストタグをサポートしています。 ([General Translation と react-intl の比較](/kb/general-translation-vs-react-intl)を参照してください。) 
* **messageformat**: [`@messageformat/core`](https://messageformat.github.io/messageformat/) は ICU メッセージを JavaScript 関数にコンパイルします。なお、`messageformat` パッケージのバージョン 4 では、ICU MessageFormat ではなく MessageFormat 2 が実装されています。
* **i18next-icu**: i18next で ICU 構文を使えるようにする i18next プラグインで、`intl-messageformat` をベースに構築されています。
* **Lingui**: [マクロ](https://lingui.dev/ref/macro)を使うと、JSX やタグ付きテンプレートがコンパイル時に ICU MessageFormat のメッセージへ変換されます。
* **next-intl**: [メッセージは ICU 構文で記述します](https://next-intl.dev/docs/usage/messages)。

## MessageFormat 2 では何が変わるのか？

MessageFormat 2 (MF2) は Unicode Consortium が再設計したもので、`.input` や `.match` といった宣言や、二重波括弧で囲むパターンなど、新しい構文を採用しています。仕様は [Unicode LDML の Part 9](https://www.unicode.org/reports/tr35/tr35-messageFormat.html) に定められており、安定版ドキュメントとして位置づけられています (一部の関数にはまだ Draft の表記があります) 。また、ICU4C と ICU4J にはすでに組み込まれています。JavaScript では、TC39 の [`Intl.MessageFormat` プロポーザル](https://github.com/tc39/proposal-intl-messageformat) がまだ Stage 1 の段階にあり、JavaScript の標準には含まれていません。`messageformat` 4.x パッケージは、そのポリフィルにあたります。MF2 で複数形の例を書くと、次のようになります。

```text
.input {$count :number}
.match $count
0   {{You have no messages.}}
one {{You have {$count} message.}}
*   {{You have {$count} messages.}}
```

`messageformat` 4.1.0 で実行すると、0、1、1234 に対してそれぞれ &quot;You have no messages.&quot;、&quot;You have 1 message.&quot;、&quot;You have 1,234 messages.&quot; と出力されます。MF2 のメッセージは MessageFormat 1 の文字列と互換性がありませんが、上記のほかのライブラリはいずれも MessageFormat 1 を読み込む仕様です。

## General Translation における ICU の扱い

`gt-react` と `gt-next` では、[`useGT`](/docs/react/reference/hooks/use-gt) が ICU メッセージとその値を受け取る関数を返します。

```tsx title="Inbox.tsx"
import { useGT } from 'gt-react';

export function Inbox({ count }: { count: number }) {
  const gt = useGT();
  return (
    <p>
      {gt('{count, plural, =0 {You have no messages.} one {You have # message.} other {You have # messages.}}', {
        count,
        $context: 'Unread message count in the inbox',
      })}
    </p>
  );
}
```

[`npx gt translate`](/docs/cli/reference/commands/translate) はこれらの文字列を抽出し、`$context`、用語集、カスタムプロンプトを文脈として利用して、各対象ロケールの翻訳を生成します。ソースロケールでは、`gt-react` 11.4.12 は上記の `intl-messageformat` の例と同じ3つの出力を表示します。

* **辞書。** [`useTranslations`](/docs/react/reference/hooks/use-translations) で読み込むエントリでは、`{dollars, number, ::currency/USD}` のような ICU 書式設定を使用できます。
* **既存の JSON カタログ。** CLI は `package.json` から next-intl と i18next (`i18next-icu` を含む) を検出し、各ライブラリの構文を維持したまま JSON ファイルを翻訳します。 ([JSON ファイル](/docs/cli/reference/formats/json-files)を参照してください。) 
* **翻訳を伴わないフォーマット。** Core ライブラリの [`formatMessage`](/docs/platform/core/reference/utility-functions/formatting/format-message) は、ICU メッセージを指定したロケール向けに書式設定します。
* **Lint。** `@generaltranslation/react-core-linter` の `static-string` ルールは、不正な形式の ICU メッセージを検出して報告します。 ([Lint ルール](/docs/react/reference/lint-rules#static-string)を参照してください。) 

ただし、すべての API が ICU を解析するわけではありません。`gt-node` の [`tx`](/docs/node/reference/functions/tx) は波括弧をそのままのテキストとして扱います。JSX では、[`<T>`](/docs/react/reference/components/t) 内で [`<Plural>`](/docs/react/reference/components/plural) や [`<Branch>`](/docs/react/reference/components/branch) を使えば、構文を手書きしなくても同様の複数形や選択のケースに対応できます。

## 重要なポイント

* ICUメッセージ形式では、変数、`plural`、`select`、`selectordinal`、`offset` を1つの翻訳可能な文字列にまとめて記述できます。書式設定された数値は `#` で表し、完全一致は `=0` のような形式で指定します。
* 複数形カテゴリはCLDRで定義されています。基数の形は英語が2つ、ポーランド語とロシア語が4つ、アラビア語が6つ、日本語が1つです。そのため、翻訳時には言語に応じて分岐を追加または削除する必要があります。
* すべての分岐には完全な文を記述し、`other` を必ず含めてください。また、本番環境に反映される前に構文を検証しましょう。
* MessageFormat 2 はICU4CおよびICU4Jに組み込まれた安定版のUnicode仕様ですが、`Intl.MessageFormat` はまだTC39のStage 1提案にとどまっています。
* General Translation の [`useGT`](/docs/react/reference/hooks/use-gt) は `gt-react` と `gt-next` でICU文字列に対応しており、[`npx gt translate`](/docs/cli/reference/commands/translate) で翻訳を生成できます。

## Related questions

- [React で複数形を扱うにはどうすればよいですか？](https://generaltranslation.com/ja/kb/how-to-handle-plurals-in-react.mdx): React で複数形を扱うには、各言語の複数形ごとに文を 1 つずつ用意し、その言語の複数形規則に従って選択します。英語の複数形は 2 種類ですが、ロシア語は 4 種類、アラビア語は 6 種類あるためです。gt-react と gt-next に含まれる General Translation の `<Plural>` コンポーネントに翻訳元の形を渡せば、各対象言語に必要な形は General Translation が生成します。
- [react-intl の代替：General Translation と react-intl の比較](https://generaltranslation.com/ja/kb/general-translation-vs-react-intl.mdx): General Translation なら、React チームは ICU メッセージ構文をそのまま使いながら、翻訳の生成、用語の共有、ダッシュボード でのレビューを追加できます。react-intl が提供するのはフォーマット機能と FormatJS のカタログツールですが、General Translation は翻訳そのものも生成します。
- [i18n の JSON ファイルを翻訳するには？](https://generaltranslation.com/ja/kb/translate-json-files.mdx): JSON ロケールファイルでは、文字列の値だけを翻訳します。複数形以外のキー、{{name}} などのプレースホルダー、タグは変更せずに残しますが、複数形のキーは言語によって異なる点に注意が必要です。たとえばポーランド語では inbox_few と inbox_many が必要になります。ファイル形式に対応したツールや API を使い、レビューの前に出力をパースして検証してください。
- [i18next の代替：General Translation と i18next の比較](https://generaltranslation.com/ja/kb/general-translation-vs-i18next.mdx): テキストを React コンポーネント内にインラインで記述したまま、JSX 構造とプロダクトの文脈を活かして翻訳を生成したい場合は、General Translation を選びましょう。i18next を使い続けながら、General Translation で既存のカタログを翻訳することもできます。i18next はメッセージのレンダリングと複数形の選択を担いますが、翻訳の生成には別のサービスが必要です。
- [i18n の翻訳キーはどのように命名すべきですか？](https://generaltranslation.com/ja/kb/i18n-key-naming.mdx): キーは英語の文言ではなく、テキストが表示される場所と意味に基づいて命名します（例: checkout.summary.title）。英語が同じでも、用途が異なるものにはそれぞれ別のキーを割り当ててください。たとえばドイツ語では、ボタンの Open は Öffnen、ステータスの Open は Offen と訳されます。

## Previous and next questions

- Previous question: [i18n の翻訳キーはどのように命名すべきですか？](https://generaltranslation.com/ja/kb/i18n-key-naming.mdx)
- Next question: [Markdown と MDX の構文を壊さずに翻訳するには？](https://generaltranslation.com/ja/kb/translate-markdown-files.mdx)

## Sitemap

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