l10n のだいたいの形が決まったので、その通りに組んでみた。
おさらいする。3 種のブラウザで同様に動く l10n の仕組みを wasavi に組み込むのが目的。3 種のブラウザがそれぞれ l10n の仕組みを備えているが、wasavi 上では Chrome のそれを基本にし、他のブラウザでは Chrome の仕組みをエミュレートする形。Chrome の l10n の仕組みとは、エクステンションのアーカイブ内に _locales/[localeCode]/messages.json といったファイルを配置し、その json ファイルにメッセージ ID とそれに対応する各言語のテキストを格納し、変換は、wasavi 実行中に動的に行うというもの。
それに加えて、wasavi 独自の仕組みがある。
- メッセージへのパラメータの埋め込み。平たく言うと sprintf() だ。これは Chrome が提供する i18n にも用意されているが、wasavi 側で行う。メッセージ中の {0} といった部分は、パラメータで置き換えられる(数値はパラメータのインデックス)。
- メッセージ中、複数形になりうる名詞の変換。1 行削除したときは
deleted 1 line.
それ以上の行を削除したときは
deleted 10 lines.
のように自然な形のメッセージを生成する。ソース上は、メッセージは “deleted {0} {line:0}.” と記述する。{word:number} の形式だ。ここでも number はパラメータのインデックス。パラメータの値によって word を自然な形に変化させ、波かっことその中身全体を、生成した word で置き換える。これには、以下のものが必要になる:
- パラメータを引数にとって、変化パターンを返す関数
- 各変化パターンに対応する word の変化形
これらの情報もまた、messages.json に格納する。まず 1. は、Language Plural Rules を参考に生成する。例えば英語の場合は
Language Name Code Category Examples Rules English en one 1 one → n is 1;
other → everything elseother 0, 2-999;
1.2, 2.07…ということである。変換関数は Rules を、変化パターンは Category を見ればいい。まず変換関数は、Rules に対応する javascript の式を書く。n が 1 の場合は ‘one’、それ以外は ‘other’(実際は、空文字で代用)を返すようにする。
{
"_plural_rule@function": {
"message": "n==1?'one':''"
}
}
そして、全メッセージ中で使用している複数形になりうる単語について、one パターンと other パターンのそれぞれを定義する。
{
"_plural_substitution": {
"message": "substitutions"
},
"_plural_substitution@one": {
"message": "substitution"
},
"_plural_line": {
"message": "lines"
},
"_plural_line@one": {
"message": "line"
},
"_plural_character": {
"message": "characters"
},
"_plural_character@one": {
"message": "character"
},
"_plural_operation": {
"message": "operations"
},
"_plural_operation@one": {
"message": "operation"
}
}
メッセージ ID は “_plural_” + word の基本形 + @ + 変化パターンとなる。この後ろに、通常のメッセージ群についてメッセージ ID と変換結果を全て記述する。
{
"invalid_boolean_value": {
"message": "Invalid boolean value",
"description": "Invalid boolean value"
},
:
:
:
"top_of_history": {
"message": "Top of history.",
"description": "Top of history."
}
}
messages.json 側でやることは以上。
で、Chrome ではメッセージ ID を変換するには chrome.i18n.getMessage() を呼ぶだけでよいのだが、他のブラウザではそうは行かない。
- Opera
フォルダベースの l10n 機能を利用する。background の起動時に XHR でエクステンションアーカイブ内の /messages.json を読み込む。実際は、メッセージカタログは locales/[localeCode]/messages.json に配置してあり、自動的にロケールに応じたファイルが参照される。wasavi 起動時にメッセージカタログの内容を wasavi.js へ送信する。wasavi.js 側でメッセージが必要になった際は、自分でカタログの中から探し出す。 - Firefox
メッセージカタログは data/xlocale/[localeCode]/messages.json へ配置する。現在のロケールを得るために api-utils/l10n/locale モジュールの getPreferedLocales() を使う。また、有効なロケール群から現在のロケールに最もふさわしいロケールを抜き出すためにも、上記のモジュールが提供する findClosestLocale() メソッドを使う。これ以外に、標準的な l10n の機能は使わない。
その他の仕組みは、Opera と共通。
というわけで、とりあえず日本語ロケールのメッセージを作ってみた。