ICU MessageFormatは、数量、性別、その他の変数に応じて内容が変わる、単一の翻訳可能な文字列を書くためのUnicode標準です。今も翻訳が難しいのは、その構文がローカライズを担う人々ではなく、コードのために設計されているからです。この仕様は10年以上前から存在していますが、最も苦労しているのは、入れ子になった波括弧を前にした非技術者の翻訳者たちです。globalize.nowは、この問題の一段下の層に位置するAI駆動のローカリゼーションインフラです:文字列を抽出し、これらのICUパターンが存在するロケールファイルを生成し、Gitへのプッシュのたびにそれらを同期させ続けます。
ICU MessageFormatとは何か
ICU MessageFormatは、最終的な文言が実行時のデータに依存するメッセージを表現するための構文です。コード内で断片を連結する代わりに、ひとつのパターンを書き、フォーマッターにロケールごとの正しい分岐を選ばせます。
最もよく使われるのは複数形の処理です:
{count, plural,
one {You have # message}
other {You have # messages}
}
#は数値に置き換えられ、one / otherの分岐がその言語の複数形カテゴリに対応します。英語には2種類ありますが、ポーランド語、ロシア語、アラビア語にはもっと多くの種類があります。ICUはselectを通じて性別やその他の選択も扱います:
{gender, select,
male {He liked your post}
female {She liked your post}
other {They liked your post}
}
これがICUが事実上の複数形標準となった理由です:文法的な複雑さを、書いた言語でしか動かない分岐ロジックの中に押し込めるのではなく、言語ごとに変化し得るデータの中に押し出しているのです。FormatJS、i18next、next-intlといったランタイムライブラリはどれもこれを理解します。
ICU MessageFormatはなぜこれほど翻訳しづらいのか
翻訳が難しいのは、その構文が開発者向けに作られたものであり、実際に文字列を翻訳する人々は大抵開発者ではないからです。
ロケールファイルを開いた翻訳者には「You have 3 messages.」という文には見えません。目に映るのは波括弧、pluralやselectといったキーワード、聞き覚えのないかもしれない複数形のカテゴリ、そしてタイプミスのように見える#のプレースホルダーです。括弧をひとつ消してしまったり、カテゴリの名前をひとつ変えてしまったりするだけで、その文字列は描画されるどころか実行時にエラーを起こします。ICUをエンジニアにとって強力なものにしている構造こそが、言語の専門家の手にかかると脆いものになってしまうのです。
これは、ローカリゼーション業界が何年もの間ひっそりと抱えてきた溝です。ほとんどのツールは、生のパターンをそのまま表示して翻訳者が間違った文字に触れないことを願うか、あるいは複数形の処理を別のエディタの裏に隠す形で対処していますが、それでも翻訳者は複数形のカテゴリを理解する必要があります。仕様の複雑さと、非技術者の翻訳者の思考モデルとの間の距離を、完全に埋め切ったベンダーはまだ存在しません。
MessageFormat 2.0で何が変わったのか
MessageFormat 2.0は構文をゼロから再設計したものであり、2025年には草案ではなく安定した標準となりました。
MF2は2025年3月にFinal Candidateの段階に達し、現在はCLDRの安定した一部として、Unicode LDML技術標準の一部として公開されており、LDML 47およびLDML 48のリリースを通じて改良が重ねられています。リファレンス実装は、2026年初頭にリリースされたLDML 48.2の時点での仕様に準拠しています。新しい構文は入力とマッチロジックを分離し、名前付きのフォーマット関数をサポートすることで、複雑なメッセージをより読みやすくしています:
.input {$count :number}
.match $count
one {{You have {$count} message}}
* {{You have {$count} messages}}
目指しているのは、より拡張しやすく、元の入れ子になった波括弧よりもいくらか読みやすいパターンです。
MessageFormat 2.0は翻訳者側の問題を解決するのか
まだです。理由は2つあります。
第一に、MF2は構文の使い勝手を改善していますが、それでも構文であることに変わりはありません。翻訳者は依然として.match、複数形のキー、波括弧に出くわします。認知負荷はMF1より軽くなりましたが消えたわけではなく、非技術者の翻訳者が誤ったトークンを編集してメッセージを壊してしまうことは今も起こり得ます。
第二に、これを本番環境で実際に使っている人はほとんどいません。2026年に入っても採用は限定的なままです:JavaScript側のTC39プロセスでは、さらに先へ進める前に、本番環境でMF2を使っている組織がおおよそ十数団体は必要だとされていますが、その基準にはまだ達していません。実際のところ、今日出荷されているほとんどのアプリは、今でもFormatJSやi18nextといったライブラリを通じて元々のICU MessageFormatの上で動いています。つまり翻訳者向けの問題は、仕様によって解決されるのではなく、その構文がどこで生成され、どこで維持管理されるかによって解決されるのです。
AI生成アプリにおいて、ICU MessageFormatはどこで壊れるのか
早い段階で壊れます。なぜなら、AIコーディングツールがそもそも正しいICUを出力すること自体がまれだからです。
Cursor、Claude Code、あるいはLovableで開発していると、生成されたコードは数量の扱いを素朴なやり方で処理しがちです:
// What an AI coding tool often generates
const label = count + " " + (count === 1 ? "message" : "messages");
そのロジックは英語では正しくても、ほとんどの他言語では成立しません。複数形が2種類しかないという前提に立っているからです。しかも文章がアプリケーションコードに直書きされてしまうため、翻訳者が編集すべきICUパターンがロケールファイルにそもそも存在しません。文字列はローカライズ層から見えないまま本番環境に出て、誰かが不自然な文法に気づくまで放置されます。AIツールもキーを重複生成したり、ハードコードされたテキストをコンポーネントに散らかしたりするため、ICUを使いたいチームですら、翻訳可能なファイルに一度も入らなかった文字列を抱えることになります。globalize.now developer overviewは、まさにこの種の文字列をリリース前に検出するために作られています。
2026年、開発者はICU MessageFormatをどう扱うべきか?
ICUは手書きするコンテンツではなく、自動生成されるインフラとして扱うべきです。
実践的なルールはこうです。開発者やAIツールがコード内で複数形の文字列連結を書くべきではなく、翻訳者も生のICU中括弧を手作業で編集すべきではありません。ICUパターンは自動生成・自動更新されるロケールファイルに置かれ、FormatJSやi18next、next-intlのようなライブラリによって実行時にレンダリングされるべきものです。そうすることで、構文は生成された時点から正しく保たれ、アプリが変化してもすべてのロケールで一貫性が維持されます。ICUがランタイム層とどう役割分担するか気になる方は、globalize.now vs i18next comparisonでインフラとランタイムの分業について解説しています。
これがglobalize.nowが動作する層です。コードベースからハードコードされた文字列を抽出し、ICUパターンが置かれるキーとロケールファイルを生成し、Gitへのプッシュのたびに再同期します。手動でのエクスポート作業なしに、構造が正しい状態を保てます。翻訳者のエディタになろうとしたり、ランタイムライブラリを置き換えたりするものではありません。それらのツールが依存するICU形式のファイルが、確実に存在し、同期され続けるようにするものです。vibe-coders guideでは、Lovable、Bolt、Replitで構築されたアプリでも同じセットアップ手順を紹介しています。より広範なワークフローについてはglobalize.now homepageをご覧ください。
globalize.nowは、ハードコードされたアプリ内テキストを翻訳可能なロケールファイルに変換し、リリースのたびに自動で最新の状態を保ちます。
globalize.nowを無料で試す