BCP 47 言語タグを正しく理解する — ja-JP・zh-Hans・pt-BR の意味
「どの言語タグを使えばいいか」は些細な質問に見えますが、コードベースの中で ja_JP、ja-jp、JA といった3通りの答えが散らばっているのを見た瞬間、そうでもないことに気づきます。BCP 47(IETF の仕様で、ISO 639・ISO 15924・ISO 3166 のレジストリの上に構築されている)が、あらゆる言語タグの背後にある実際の標準規格であり、混乱の多くはどのサブタグがどんな役割を持つかを知らないことから来ています。
サブタグとそれぞれの意味
BCP 47 タグは、決まった文法に従ってハイフンでつながれたサブタグの並びです。ゲームのローカライズで頻繁に出てくる3種類は次の通りです。
- 言語主サブタグ — ISO 639 の2文字または3文字コード。例: ja(日本語)、en(英語)、zh(中国語)。必ず必要で、常に先頭に来る。
- スクリプト(文字体系)サブタグ — ISO 15924 の4文字コード。例: Hans(簡体字)、Hant(繁体字)。ある言語が複数の文字体系で書かれ、区別が必要な場合にのみ付く。
- 地域サブタグ — ISO 3166-1 の2文字コード(あるいはより広い地域を表す3桁の UN M49 コード)。例: JP、US、BR。言語そのものではなく、地域による変種を示す。
実例を読み解く
ja は単に「日本語」を表し、それ自体で十分です。日本語には、コンテンツの観点で意味のある地域変種というものが基本的にないからです。ja-JP は地域サブタグを付け足していますが、同じ理由でほぼ冗長です。実際に見かけることはありますが、ja が既に持っている以上の情報を運んでいることはほとんどありません。
重要なのは zh-Hans と zh-Hant です。中国語は言語サブタグとしては1つですが、実際に使われている文字体系が2つあり、テキストがどちらの文字集合で書かれるべきかを実際に決めているのはスクリプトサブタグの方です。pt-BR は逆のケースで、ポルトガル語はどこでも同じ文字体系で書かれますが、ブラジルとヨーロッパのポルトガル語は語彙や綴りが十分に異なるため、地域サブタグが実際の情報を運びます。es-419 は特定の1国ではなく UN M49 の地域コード(419 = ラテンアメリカとカリブ海地域)を使っており、特定国の方言ではなく地域全体を対象にしたコンテンツに使われます。
中国語で region より script が優先される理由
zh-Hans や zh-Hant の代わりに zh-CN や zh-TW と書きたくなる気持ちは分かります。それぞれの文字体系と最も結びつきの強い地域だからです。しかしこれは2つの異なる軸を混同しています。地域タグは地理を表し、スクリプトタグはテキストが実際にどの文字集合で書かれているかを表します。シンガポールやマレーシアのユーザーが読む簡体字中国語のリリースも、やはり zh-Hans です。地域でタグ付けしてしまうと、そうしたユーザーとミスマッチを起こすか、簡体字中国語が読まれるあらゆる場所ごとに地域タグを新設する羽目になります。
ここから一般化できる原則はこうです。コンテンツを実際に区別する性質(付随的な地理ではなく文字体系)でタグ付けし、地域そのものがテキストを変える場合(pt-BR のように)にのみ地域サブタグを追加する、ということです。
マッチングとフォールバック
タグは、末尾からサブタグを順に外していきながら、一致するものが見つかるまで照合されます。ja-JP へのリクエストが完全一致を見つけられなければ、既定のロケールにフォールバックする前に ja にフォールバックします。だからこそ言語主サブタグを省略してはいけませんし、リソースファイル側に対応する広いフォールバックがない過度に具体的なタグは、静かにまったく一致しないまま失敗することがあります。
// naive fallback resolution
function resolve(tag, available) {
const parts = tag.split("-");
while (parts.length > 0) {
const candidate = parts.join("-");
if (available.includes(candidate)) return candidate;
parts.pop();
}
return null; // caller falls back to a hardcoded default
}よくある間違い
下流でマッチングのバグを確実に引き起こすものを挙げます。
- レジストリを使わずタグを自作する — 日本の言語を jp とするのは誤り。言語は ja、JP は地域
- ハイフンの代わりにアンダースコアを使う(ja_JP) — 一部の古いロケール識別子の慣習では有効だが BCP 47 タグではなく、厳密にパースするライブラリでは拒否されるか誤って処理される
- 言語とロケールを混同する — ロケールは言語タグにとどまらず、書式の慣習なども含むより広い概念であり、言語だけで足りるコードで両者を混用すべきではない
- 必要もなく習慣で地域サブタグを付ける — 不要なサブタグが増えるほど、マッチングが静かに失敗する経路も増える