拡張機能のローカライズ

はじめに

ローカライズしたい拡張機能を見つけたら、作業を始める前に、その拡張機能の機能を一通り確認しておきましょう。

この記事では、アプリケーションのパスワード管理機能を拡張する Saved Pasward Editor を取り上げます。他の拡張機能で、まだ日本語のロケールが無い場合は、日本語のリソースを追加する方法 を参照してローカライズするファイルを準備しておいてください。

この拡張機能の locale/* フォルダには、以下のファイルが含まれています:

  • browserOverlay.dtd
  • prefwindow.dtd
  • pwdedit.dtd
  • pwdedit.properties
  • pwdmgrOverlay.dtd
  • pwdmgrOverlay.properties
  • spe.properties
  • welcome.dtd

いろいろなファイルがありますが、これらは .dtd ファイルと .properties ファイルの 2 種類に分けられます。

翻訳作業後は、どちらのファイルも文字エンコードを UTF-8 (BOM 無し) にして保存してください。

dtd ファイルと properties ファイルのローカライズ

dtd ファイル

dtd ファイルは、拡張機能の content フォルダに含まれる xul ファイルや html ファイルで使用されます。

はじめに、pwdmgrOverlay.dtd ファイルを見てみましょう。このファイルは、保存されたパスワードウィンドウに追加されるボタンとコンテキストメニューの文字列が書かれています。

<!ENTITY newentry.label "New">
<!ENTITY newentry.accesskey "N">
<!ENTITY editentry.label "Edit">
<!ENTITY editentry.accesskey "E">
<!ENTITY cloneentry.label "Clone">
<!ENTITY cloneentry.accesskey "l">

dtd ファイルは、「<!ENTITY 実体名 "文字列">」という書式で書かれており、ダブルクォートで囲まれた文字列の部分を翻訳します。これは、content フォルダの pwdmgrOverlay.xul ファイルで次のように呼び出されています。

<!DOCTYPE overlay SYSTEM
          "chrome://savedpasswordeditor/locale/pwdmgrOverlay.dtd">

例えば、pwdmgrOverlay.xul ファイル内で newentry.label の実体名を検索すると、コマンドやボタンメニューの label 属性 で使われていることが分かります。(xul コード内では、&実体名; のように書かれます。)

<command id="new_signon"
         label="&newentry.label;" accesskey="&newentry.accesskey;"
         oncommand="spEditor.newSignon();"/>
 ...
<menuitem id="speMenuBtn_newSignon" label="&newentry.label;"
          accesskey="&newentry.accesskey;"
          oncommand="spEditor.menuBtnSel(event, this);"/>

この部分は「新規作成」にします。newentry.accesskey は、この機能の ショートカットキー に指定されているので英語版と同じにします。

<!ENTITY newentry.label "新規作成">
<!ENTITY newentry.accesskey "N">

同様に、editentry.label と cloneentry.label も翻訳しましょう。

<!ENTITY newentry.label "新規作成">
<!ENTITY newentry.accesskey "N">
<!ENTITY editentry.label "編集">
<!ENTITY editentry.accesskey "E">
<!ENTITY cloneentry.label "複製">
<!ENTITY cloneentry.accesskey "l">

properties ファイル

次に、同じ名前を持つ pwdmgrOverlay.properties ファイルを見てみます。properties ファイルは、JavaScript ファイル (*.js) で使用されます。

# POPUP MESSAGE WHEN ADDING/MODIFYING AN ENTRY FAILS
badnewentry=Got an error:\n  %S\nDid you try to create a duplicate login entry?

# で始まる行はコメントです (ちなみに、dtd ファイルのコメントは html と同じ <!-- --> で囲みます)。

properties ファイルは、「実体名 = 文字列」という書式で書かれ、特殊な文字が含まれることがあります。上記の例の \n は改行、%S は文字列中に表示される JavaScript 変数を表します (複数の %S が使われる場合、%1$S, %2$S のように書きます)。

この拡張機能の場合、properties ファイルは、xul ファイルの stringbudle 要素 で呼び出され、すぐ下の script 要素 で指定された pwdmgrOverlay.js ファイルで使用されています。

pwdmgrOverlay.xul:

<stringbundleset>
...
   <stringbundle id="savedpwdedit-overlay-stringbundle"
     src="chrome://savedpasswordeditor/locale/pwdmgrOverlay.properties"/>
</stringbundleset>

<script type="text/javascript"
        src="chrome://savedpasswordeditor/content/pwdmgrOverlay.js"/>

pwdmgrOverlay.js では、上記の要素を getElementById で取得しています。

spEditor.pmoStrBundle =
  document.getElementById("savedpwdedit-overlay-stringbundle");

pwdmgrOverlay.js ファイル内の badnewentry を検索すると、次のところで使われています:

alert(window, this.genStrBundle.getString("error"),
      this.pmoStrBundle.getFormattedString("badnewentry",
                                           [e.message]));

alert() 関数内の getFormattedString() の引数として、実体名の "badnewentry" とエラーメッセージらしきものが渡されています。というわけで、%S はエラーメッセージに置き換えられるのが分かります。

それでは、上記を踏まえて badnewentry を翻訳しましょう。

badnewentry=エラーが発生しました:\n %S\n既存のログインエントリと同じものを作成しようとしていませんか?

ローカライズする文字列

文字列中の JavaScript 変数

properties ファイルでは、JavaScript 変数に置き換えられる %S が使用されることがあります。一つの実体で複数の変数が使用される場合、.js コード内に記述された順に、「%1$S, %2$S, ...」と書くことができます。

元のロケールによっては、「%S, %S, ...」のように数字が省かれていることがありますが、このままでは変数の位置を入れ替えることができません。これは、元のロケールでの記述順に「%1$S, %2$S, ...」と書くことができます。数字を付けて書けば変数の位置を入れ替えることができます。複数の変数が現れる場合は、数字を付けて書きましょう。

また、元のロケールに書かれた変数の表示を省くこともできます。例えば、最初に現れる %S を省きたいときは「%1$0.S」と書きます。同様に、2 番目に現れるものを省きたいときは「%2$0.S」と書きます。

Plural forms

文脈によっては、文字列の単数形と複数形がセミコロン (;) で分けて書かれているものがあります。複数形の規則 は言語によって異なるため、アプリケーションの言語パックで設定されています。拡張機能もそれを継承します (日本語言語パックの intl.properties を参照)。

日本語の場合は、セミコロンから左側を削除して、複数形を前提に翻訳します。

dueInDays=#1 day;#1 days
dueInHours=#1 hour;#1 hours
dueInDays=#1 日
dueInHours=#1 時間