WebExtensionsによるFirefox用の拡張機能で組み込みのページのローカライズを容易にするライブラリ:l10n.js


(この記事は、Firefoxの従来型アドオン(XULアドオン)の開発経験がある人向けに、WebExtensionsでの拡張機能開発でのノウハウを紹介する物で、所属会社のブログの2018年7月10日の記事の再掲です。)

XULアドオンでは、表示文字列のローカライズには「DTDファイルで<!ENTITY menu.open.label "開く">といった形式でロケールを定義し、XULファイルの中に<label value="&menu.open.label;">のように書いておくと自動的に適切なロケールの内容に置き換わる」「propertiesファイルでmenuLabelOpen=開くといった形式でロケールを定義し、JavaScriptからstringbundle.getString('menuLabelOpen')といった形で参照する(String Bundle)」という2つの方法がありました。

WebExtensionsの国際化対応の仕組みはそれよりももっと単純です。ロケールはJSON形式のみで定義し、browser.i18n.getMessage()でキーを指定すると適切な言語のロケールの内容が文字列として取得できるという物で、XULアドオンでのString Bundleに近い形式です。

この方法はテンプレートエンジンやVirtual DOMなどでUIを構築する場合は特に支障にならないのですが、静的なHTMLファイルで設定画面のページなどを作成する場合には、「参照されるべきロケールのキーを書いておくだけで表示時に適切なロケールの内容が反映される」というXULファイルで使っていた方法のような仕組みが欲しくなる所です。実際、manifest.jsonの中では__MSG_menuLabelOpen__のように書くだけでFirefoxが表示時に自動的に適切なロケールの内容を反映してくれるので、これと同じ事がHTMLファイルではできないというのはもどかしいです。

そこで、静的なHTMLファイルの中にロケールを埋め込む使い方を可能する軽量ライブラリとして、l10n.jsという物を開発しました1

基本的な使い方

読み込みと初期化

このライブラリを使う事自体には、特別な権限は必要ありません。最も単純な使い方では、国際化するページからファイルを読み込むだけで機能します。

<script type="application/javascript" src="path/to/l10n.js"></script>

このライブラリを使う時は、HTMLのページ中のテキストや属性値に__MSG_(ロケールのキー)__と書いておきます。例えば以下の要領です。

<p title="__MSG_config_enabled_tooltip__">
  <label><input type="checkbox">
         __MSG_config_enabled_label__</label></p>
<p title="__MSG_config_advanced_tooltip__">
  <label><input type="checkbox">
         __MSG_config_advanced__</label></p>
<p title="__MSG_config_attributes_tooltip__">
  <label>__MSG_config_attributes_label_before__
         <input type="text">
         __MSG_config_attributes_label_after__</label></p>

これだけで、ページの読み込み時に自動的に各部分が対応するロケールの内容で置き換わります。


任意のタイミングでの反映

このライブラリは、動的に挿入されたDOM要素の内容テキストや属性値に対しては作用しません。ページの読み込み完了後に追加された内容に対してもロケールの反映を行いたい場合は、それらがDOMツリー内に組み込まれた後のタイミングでl10n.updateDocument()を実行して下さい。例えば以下の要領です。

var fragment = range.createContextualFragment(`
  <p>__MSG_errorDescription__
     <label><input type="checkbox">__MSG_errorCheckLabel__</label></p>
`);
document.body.appendChild(fragment);
l10n.updateDocument();

明示的に空文字列を使う場合の注意点

「See(リンク)」と「(リンク)を参照して下さい」のように、言語によって要素の前や後に何もテキストを設けない方が自然になる場合があります。このようなケースでは、あらかじめ要素の前後にテキストを埋め込めるようにしておき、言語によってその内容を変えるというやり方が使われる事があります。

<p>__MSG_before_link__
   <a href="...">__MSG_link_text__</a>
   __MSG_after_link__</p>
{ // 英語
  { "before_link": { "message": "For more details, see " } },
  { "link_text":   { "message": "the API document." } },
  { "after_link":  { "message": "" } },
}

{ // 日本語
  { "before_link": { "message": "" } },
  { "link_text":   { "message": "APIドキュメント" } },
  { "after_link":  { "message": "に詳しい情報があります。" } }
}

XULではこのような場合空文字列は空文字列として埋め込まれていましたが、l10n.jsでは対応するロケールが空だった場合は__MSG_after_link__という参照のための文字列がそのままUI上に残ります。これは、browser.i18nにおいて「参照したロケールが未定義だった場合」と「参照したロケールの値が明示的に空文字に設定されていた場合」を区別できないことから、ミスの検出を容易にするために敢えてそのような仕様としているためです。

このようなケースでは、明示的に空にしたい部分には\u200b(ゼロ幅スペース)と書いて下さい。上記の例であれば、訂正後は以下のようになります。

{ // 英語
  { "before_link": { "message": "For more details, see " } },
  { "link_text":   { "message": "the API document." } },
  { "after_link":  { "message": "\u200b" } },
}

{ // 日本語
  { "before_link": { "message": "\u200b" } },
  { "link_text":   { "message": "APIドキュメント" } },
  { "after_link":  { "message": "に詳しい情報があります。" } }
}

まとめ

以上、Firefox用のWebExtensionsベースのアドオンにおける静的なHTMLファイルのローカライズを容易にするライブラリであるl10n.jsの使い方を解説しました。

XULアドオンでの感覚に近い開発を支援する軽量ライブラリは他にもいくつかあります。以下の解説も併せてご覧下さい。


  1. 「l10n」は「localization(ローカライズ、地域化)」の略としてよく使われる、先頭と末尾の文字、およびその間の文字数を組み合わせた表現です。ちなみに、同様に「i18n」は「internationalization(国際化)」の略です。