このページはコミュニティーの尽力で英語から翻訳されました。MDN Web Docs コミュニティーについてもっと知り、仲間になるにはこちらから。

View in English Always switch to English

国際化

WebExtensions API には、拡張機能を国際化するとても簡単なモジュール — i18n があります。この記事ではその機能を見てみて、どのように動作するのかの例を提供します。

メモ: この記事の見本の拡張機能— notify-link-clicks-i18n — は GitHub で入手できます。以下の節を進んでいくのに合わせてコードを追ってください。

国際化拡張機能の中身

国際化された拡張機能は、他の拡張機能と同じ機能 — バックグラウンド文字体系コンテンツ文字体系など — を含む他、さまざまなロケールに切り替えられるような追加の部分もあります。これは下記のディレクトリーツリーのように要約されます:

  • extension-root-directory/
    • _locales

      • en

        • messages.json
          • 英語メッセージ (文字列)
      • de

        • messages.json
          • ドイツ語メッセージ (文字列)
      • etc.

    • manifest.json

      • ロケール依存のメタデータ
    • myJavascript.js

      • ブラウザーロケールや、ロケール固有メッセージなどを取得する JavaScript
    • myStyles.css

      • ロケール依存の CSS

それぞれの新機能を順に見ていきましょう— 以下の節は拡張機能を国際化するときのそれぞれのステップを表しています。

_locales 内にローカライズ済み文字列を提供する

メモ: 言語のサブタグを探すには、Language subtag lookup page の検索ツールを使います。注意点としては言語の名前の英語で探す必要があります。

すべての i18n システムはサポートする全ロケールに翻訳済みの文字列が要ります。拡張機能では、これは拡張機能のルート内に置かれる _locales と呼ばれるディレクトリーに入っています。各ロケールはそれぞれの文字列 (メッセージとも呼ばれる) を messages.json というファイル内に入れていて、これは _locales のサブディレクトリー内に置かれており、そこはロケール言語の言語サブタグを使った名前になっています。

サブタグには基本的な言語に加えて、地域の変化形があるのに注意してください。ここで言語と変化形は伝統的に "en-US" のようにハイフンで区切られます。しかし、_locales 内のディレクトリーでは、区切り文字はアンダースコアでなければならず、 "en_US" となります。

例えば、見本のアプリでは "en" (英語), "de" (ドイツ語), "nl" (オランダ語), "ja" (日本語) のフォルダーがあります。それぞれの中に messages.json ファイルがあります。

このファイル (_locales/en/messages.json) の構造を見てみます。

json
{
  "extensionName": {
    "message": "Notify link clicks i18n",
    "description": "Name of the extension."
  },

  "extensionDescription": {
    "message": "Shows a notification when the user clicks on links.",
    "description": "Description of the extension."
  },

  "notificationTitle": {
    "message": "Click notification",
    "description": "Title of the click notification."
  },

  "notificationContent": {
    "message": "You clicked $URL$.",
    "description": "Tells the user which link they clicked.",
    "placeholders": {
      "url": {
        "content": "$1",
        "example": "https://developer.mozilla.org"
      }
    }
  }
}

このファイルは標準の JSON — メンバーがそれぞれに messagedescription. を含む名前付きオブジェクトです。すべての項目が文字列です; $URL$ はプレースホルダーで、拡張機能から呼ばれる notificationContent メンバーに置き換えられます。マニフェスト内のローカライズ済み文字列を取得するの節でその方法を学びます。

メモ: messages.json ファイルの中身についての詳しい情報はロケール固有のメッセージリファレンスにあります。

manifest.json を国際化する

manifest.json の国際化を実行するにはいくつかの異なるタスクがあります。

マニフェスト内のローカライズ済み文字列を取得する

manifest.json にはユーザーに表示される文字列が入っています、例えば拡張機能の名前や説明です。この文字列を国際化して messages.json に適切な訳を置くと、現在のロケールなどに基づき、正しく翻訳された文字列がユーザーに表示されます。

文字列を国際化するには、このように指定します。

json
"name": "__MSG_extensionName__",
"description": "__MSG_extensionDescription__",

ここで、単なる固定文字列ではなく、ブラウザーのロケールに依存しないメッセージ文字列を取得します。

このようなメッセージ文字列を呼び出すには、次のように指定します。

  1. 2 つのアンダースコアに続いて
  2. "MSG" という文字列に続いて
  3. 1 つのアンダースコアに続いて
  4. messages.json で定義した呼び出しのメッセージ名に続いて
  5. 2 つのアンダースコア
__MSG_ + messageName + __

デフォルトロケールを指定する

manifest.json にて指定すべきフィールドは default_locale です。

json
"default_locale": "en"

これは拡張機能がブラウザーの現在のロケールに対するロケール文字列を含んでいない場合のデフォルトロケールを指定します。ブラウザーロケールで利用できないあらゆるメッセージ文字列が代わりのデフォルトロケールとして引受られます。ブラウザーが文字列を選ぶ方法に関して意識すべき詳細な点があります — ローカライズ済みの文字列の選択 を見てください。

ロケールに依存しない CSS

拡張機能の CSS ファイルからもローカライズされた文字列を取得できます。例えば、ロケールに依存しない CSS を組み立てるなら、このようにします:

css
header {
  background-image: url("../images/__MSG_extensionName__/header.png");
}

事前定義されたメッセージを使ってこんな状況を扱う方がより良いものの、これは便利です。

JavaScript からメッセージ文字列を取得する

それで、メッセージ文字列とマニフェストがセットアップできました。今は単に JavaScript からメッセージ文字列を呼び出して、拡張機能ができるだけ多くの正しい言語を話すようにします。実際の i18n API はとてもシンプルで、そこには 4 つのメソッドがあります。

  • たぶん一番多く i18n.getMessage() を使うでしょう。これは上記に触れられたとおり、特定の文字列を取得するのに使うメソッドです。これの使用例は下記で見ます。
  • i18n.getAcceptLanguages()i18n.getUILanguage() メソッドはロケールに応じて UI をカスタマイズする場合に使います。たぶんユーザーの好みの言語に応じて設定リストの上の方に表示したり、特定言語だけに関連する文化的情報を表示したり、ブラウザーロケールに従って日付表示を整形したりすると良いでしょう。
  • i18n.detectLanguage() メソッドはユーザーが投稿したコンテンツの言語を特定したり、それを適切に整形したりするのに使います。

notify-link-clicks-i18n の見本の中で、バックグラウンド文字体系に下記の行があります。

js
let title = browser.i18n.getMessage("notificationTitle");
let content = browser.i18n.getMessage("notificationContent", message.url);

最初は単に messages.json ファイルからブラウザーの現ロケールのための notificationTitle message 項目を取得します。2 つ目は同様ですが、2 つ目の引数に URL を渡されます。これは何でしょう?これは notificationContent message 項目の中の $URL$ プレースホルダーを置き換えるためにコンテンツを指定する方法です:

json
"notificationContent": {
  "message": "You clicked $URL$.",
  "description": "Tells the user which link they clicked.",
  "placeholders": {
    "url" : {
      "content" : "$1",
      "example" : "https://developer.mozilla.org"
    }
  }
}

"placeholders" メンバーはプレースホルダーを定義し、ここから取得します。"url" プレースホルダーは $1、つまり 2 つ目の引数の getMessage().の最初の値から取ってきたコンテンツを指定します。プレースホルダーは"url" と呼ばれるため、実際のメッセージ文字列の中で呼び出すのに $URL$ を使います (なので "name" には $NAME$などを使う)。複数のプレースホルダーがある場合、i18n.getMessage() の 2 つ目の引数として渡す配列の中で提供できます — messages.json内部で[a, b, c]$1, $2, $3, として使われる、など。

例をざっと見ましょう。 en/messages.json ファイル内のオリジナルの notificationContent メッセージ文字列はこうです

You clicked $URL$.

https://developer.mozilla.org を指すリンクがクリックされたとします。i18n.getMessage() を呼び出した後、2 つ目の引数のコンテンツは messages.json 内で $1 として利用できて、これは "url" プレースホルダー内で定義された $URL$ プレースホルダーを置換します。よって最終のメッセージ文字列はこうなります

You clicked https://developer.mozilla.org.

直接プレースホルダーを使う

メッセージ文字列の中に直接に変数 ($1, $2, $3 など) を挿入できます。例えば上記の "notificationContent" メンバーをこう書き換えてみます。

json
"notificationContent": {
  "message": "You clicked $1.",
  "description": "Tells the user which link they clicked."
}

これはややこしくなくて速いように見えますが、他の方法 ("プレースホルダー"を使う)が最も良いやり方です。これはプレースホルダー名 (例えば"url") や例によって、プレースホルダーの目的を思い出せます — コードを書いた 1 週間後には、$1$8 が何を指すか忘れているでしょうが、プレースホルダー名が何を指すかならもっと思い出しやすいでしょう。

ハードコーディングされた置き換え

プレースホルダーにハードコードされた文字列を入れることもできます、これでコード内の変数の代わりに、いつでも同じ値が使われます。例えば、

json
"mdn_banner": {
  "message": "For more information on web technologies, go to $MDN$.",
  "description": "Tell the user about MDN",
  "placeholders": {
    "mdn": {
      "content": "https://developer.mozilla.org/"
    }
  }
}

ここでは、$1 といった変数から取るのではなく、プレースホルダーの content をハードコードしています。これはメッセージが複雑で、ファイル内で読みやすくするために色々な値に分割したい時に役立ちますし、さらにこの値はプログラム的にアクセスすることもできます。

それに加えて、個人やビジネス名といった翻訳したくない文字列を、このような置き換えから指定するのに使うことができます。

ローカライズ済みの文字列の選択

ロケールは、fren といった言語コードを使用して指定します。これには、en-USzh-Hans-CN のような文字体系や地域コードを付加することもできます。拡張機能がローカライズされた文字列を要求すると、i18n システムは messages.json ファイルから、以下の優先順位に従って文字列を返します。

  1. ブラウザーのロケールに対応するファイル(例:zh-Hans-CN)。
  2. ブラウザーのロケールに文字体系または地域が指定されている場合、地域指定なしのバージョンのファイル(例:zh-Hans)。
  3. ブラウザーのロケールに文字体系または地域が指定されている場合、文字体系指定なしのバージョンのファイル(例:zh)。
  4. manifest.json ファイルで定義された default_locale に対応するファイル。

リクエストされた文字列がこれらのファイルのいずれにも存在しない場合、空文字列が返されます。

この例を見てみましょう。

  • extension-root-directory/
    • _locales
      • en_GB

        • messages.json
          • { "colorLocalized": { "message": "colour", "description": "Color." }, /* … */ }

        en

        • messages.json
          • { "colorLocalized": { "message": "color", "description": "Color." }, /* … */ }
          • { "colorBlue": { "message": "Blue", "description": "Blue." }, /* … */ }
      • fr

        • messages.json
          • { "colorLocalized": { "message": "couleur", "description": "Color." }, /* … */}
          • { "colorBlue": { "message": "Bleu", "description": "Blue." }, /* … */ }

default_localefr に設定している場合。

  • ブラウザーのロケールが en-GB の場合、
    • getMessage("colorLocalized") は、_locales/en_GB/messages.jsoncolorLocalized メッセージが含まれているため、「colour」を返します。
    • getMessage("colorBlue") は、_locales/en/messages.json 内の colorBlue メッセージで代替されるため、"blue" を返します。
  • ブラウザーのロケールが en-US の場合、
    • getMessage("colorLocalized") は "color" を返します。これは、_locales/en_US/messages.json ファイルがないため、_locales/en/messages.json に存在するメッセージで代替されるからです。
    • getMessage("colorBlue") は、_locales/en/messages.json 内の colorBlue メッセージで代替されるため、"blue" を返します。
  • ブラウザーのロケールが zh-Hans-CN の場合、
    • getMessage("colorLocalized") は "couleur" を返します。これは、zh-Hans-CN ロケールに一致する地域、文字体系、言語がないためです(つまり、zh-Hans-CNzh-Hanszh フォルダー内に messages.json ファイルがないためです)。
    • getMessage("colorBlue") は、zh-Hans-CN ロケールに一致する地域、文字体系、言語がないため、"bleu" を返します。

この拡張機能が getMessage("colorRed") を呼び出した場合、どの言語ファイルにも "colorRed" というプロパティがないため、空文字列が返されます。

事前定義されたメッセージ

i18n モジュールでは、事前定義されたメッセージを提供しており、これまで見てきたマニフェスト内のローカライズ済み文字列を取得するロケールに依存しない CSSと同じ方法で呼び出すことができます。例えばこのようにします。

__MSG_extensionName__

事前定義されたメッセージでも全く同じ文法を使っていますが、メッセージ名の前に @@ をつけるのが異なります。例えば、

__MSG_@@ui_locale__

下記の表は利用可能なさまざまな事前定義されたメッセージを示しています。

メッセージ名 説明
@@extension_id

拡張機能の内部生成された UUID。この文字列は拡張機能内のリソースの URL を作るのに使います。ローカライズされた拡張機能でもこのメッセージを使用できます。

このメッセージをマニフェストファイル内で使用することはできません。

もう一つの注意点として、この ID は runtime.id から返される、manifest.json 内の browser_specific_settings キーを用いてセットされるアドオン ID とは異なっています。これはアドオンの URL 内にある生成された UUID です。つまりこの値を runtime.sendMessage()extensionId 引数の値として使うことはできず、runtime.MessageSender オブジェクトの id プロパティの値のチェックに使うこともできません。

@@ui_locale 現在のロケールで、この文字列をロケール固有の URL 生成に使うことができます。
@@bidi_dir 現在のロケールにおけるテキストの向きで、英語のような左書きの言語では "ltr" で、アラビア語のような右書きの言語では "rtl" となり、このいずれかです。
@@bidi_reversed_dir @@bidi_dir が "ltr" なら "rtl" で、そうでなれば "ltr" です。
@@bidi_start_edge @@bidi_dir が "ltr" なら "left" で、そうでなれば "right" です。
@@bidi_end_edge @@bidi_dir が "ltr" なら "right" で、そうでなれば "left" です。

前の例に戻って、次のように書いてみるともっと意味がわかります。

css
header {
  background-image: url("../images/__MSG_@@ui_locale__/header.png");
}

サポートしているロケール (en, de など) に一致したディレクトリー内にロケール固有の画像を保管しているとすると、もっとわかり良いです。

CSS ファイル内で @@bidi_* メッセージを使った次の例を見てみましょう。

css
body {
  direction: __MSG_@@bidi_dir__;
}

div#header {
  margin-bottom: 1.05em;
  overflow: hidden;
  padding-bottom: 1.5em;
  padding-__MSG_@@bidi_start_edge__: 0;
  padding-__MSG_@@bidi_end_edge__: 1.5em;
  position: relative;
}

英語のような左から右への言語では、上の事前定義されたメッセージを含んだ CSS 定義は、下記の最終コード行に変換されます。

css
direction: ltr;
padding-left: 0;
padding-right: 1.5em;

アラビア語のような右から左への言語では、次のようになります。

css
direction: rtl;
padding-right: 0;
padding-left: 1.5em;

拡張機能をテストする

ローカライズの検査に使用するツールや手順に関する情報については、以下をご覧ください。