ShowTable of Contents
はじめに
XPages アプリケーションでは、アプリケーションで使用されるテキストなどを自動的に抽出し、翻訳用のプロパティファイルを生成する仕組みが用意されています。これを使うことで XPages で使用しているコントロールなどで表示される文字列を簡単に抽出し翻訳作業を行うことができます。しかし、JavaScript や「値の計算」で生成される文字列や、XPages で使用されるほかの設計要素のから生成される文字列は、自動的に翻訳テキストを抽出することができません。これらのについては、開発者がローカライズのための仕組みを用意する必要があります。この記事は JavaScript を中心に、XPages 内で使用されるさまざまな文字列の国際化の手法について解説します。
本記事は以下の Wiki 記事を元に翻訳し加筆したもので、Lotus Notes/Domino 8.5.3 をもとに動作確認をしています。
XPages: JavaScript Internationalization
JavaScript と「値の計算」でローカライズしたテキストを使用する
XPages ではローカライズする必要のあるテキストを自動的に翻訳してプロパティファイルを生成する仕組みがあります。しかし、JavaScript や「値の計算」で使用されるテキストは自動的に翻抽出されないため、ローカライズする仕組みを開発者が実装する必要があります。
XPages アプリケーションで「ローカライゼーションのオプション」の使用方法
の記事でアプリケーションの翻訳を有効にする方法を説明しました。この設定により翻訳すべきテキストがプロパティファイルへ自動的に抽出されます。XPages アプリケーションのローカライズを行う際には、まずこの文書に記述された操作を行ってください。そしてそれでもまだローカライズしきれないテキストがあれば、本記事をご参照ください。本記事では JavaScript、値の計算、そして他の XPages に関連する設計要素から得られる文字列をローカライズする方法を説明します。
バンドルリソースの使い方
JavaScript にインラインに記述されたテキストを自動的にプロパティファイルに抽出してくれる便利なツールはありません。開発者は一つひとつの文字列をプロパティファイルへ抽出しなくてはなりません。翻訳すべきテキストが抽出されたプロパティファイルは XPages にロードされて抽出されたテキストが参照されます。翻訳されたプロパティファイルがアプリケーションに提供されていれば、アプリケーションを使用するユーザーのロケールに応じて適切なプロパティファイルがロードされます。翻訳されたプロパティファイルの束はバンドルと呼ばれ、バンドルリソースからアクセスされます。
表示されるテキストはキーをともにプロパティファイルに保持され、バンドルリソースからはそのキーをもとに翻訳されたテキストを取り出すことができます。簡単なバンドルは以下の手順で構成します。
1. 最初にローカライズする文字列を用意します。
新規に XPage を作成し、計算結果フィールドコントロールを XPage にドラッグ&ドロップします。「値」タブで「JavaScript」ラジオボタンを選択し、「スクリプトダイアログを開く」ボタンをクリックします。スクリプトダイアログで以下の値を貼り付けます。
2. ローカライズする文字列を含むプロパティファイルを作成します。
- アプリケーションを右クリックし、「新規」→「ファイル」を選択し、「strings.properties」と入力して「OK」をクリックします。
- 「greeting」というキーでエントリを作成し、その値として XPage の計算結果フィールドの値に使用したテキストを以下のよう設定します。ここで「#」で始まる行はコメントです。
##G11N This file contains translated messages
greeting=Welcome.
3. 与えられた変数名をもつプロパティファイルを公開するために、ページのルートにバンドルリソースを追加します。
- XPage のプロパティビューで「すべてのプロパティ」タブを選択し「基本」→「resources」プロパティを選択します。
- 「+」ボタンが表示されるのでクリックし、メニューから「xp:bundle」を選択します。
- 「var」プロパティで、JavaScript からプロパティファイルを参照する変数名を入力します。ここでの例は「scripts」です。
- 「src」プロパティにファイル名を入力します。ここでの例は「/scripts.properties」です。
4. 計算結果フィールドコントロールで「値」を編集し、バンドルからの文字列使用するように変更します。
// 'Welcome.'
return strings['greeting'];
5. strings.properties ファイルの翻訳用のコピーを作成します。ここでは日本語に翻訳すると仮定して言語コード「ja」を使用します。
1. strings.properties を strings_ja.properties にコピーします。
2. 翻訳者にファイルを送る前のテストとして、ダミーの翻訳文字列を適当に入れます。
strings_ja.properties をクリックして Domino Designer のエディタで開き、メニューから「編集」→「検索/置換」を選択して「検索/置換」ダイアログを開きます。このダイアログで以下の設定を行い、プロパティファイル内の文字を置換します。
- 検索フィールド以下の文字列を入力します。
これは key=value という形式で、@nowiki@2が [ (左大括弧)ではじまっていない行にマッチします。
- 置換フィールドに以下の文字列を入力します。ここで「fr」はフランスを示す文字列です。
これは検索でヒットした行を value=[ja| value] という文字列に変換します。文字列自体の翻訳はしていないですが、ロケールコードを付加することで、言語に対応した正しいロケールがロードされていることを確認できます。
「すべてを置換」をクリックします。
3. ひとつの翻訳ファイルがテストできるようになったら、同様にして他のサポートすべき言語についても同じ操作を繰り返します。サポートする言語は「アプリケーションのプロパティ」の「XPages」タブで「ローカリゼーションのオプション」セクションにリストされています。
Javascript の文法についての補足:Lotus Notes/Domino 8.5.1 より、バンドルの値への参照で配列シンタックスが使えるようになりました。ここではそれを使用してスクリプトを記述しています。「strings」バンドルの「greeting」キーを取得する方法は以下のようになります。
もし Lotus Notes/Domino 8.5 をお使いのときは getString() メソッドを使用してください。
strings.getString('greeting')
配列シンタックスを Lotus Notes/Domino 8.5 で使用すると、以下のようなエラーが発生します。
Unknown member 'greeting' in Java class 'java.util.PropertyResourceBundle'
Lotus Notes/Domino 8.5.1 以降ではバンドルにキーが存在していないときにのみエラーが発生します。
これ以降の例では Lotus Notes/Domino 8.5.1 以降を使用しているとして配列シンタックスを使用して説明をします。
I18n (Internationalization) ライブラリの使用
サーバーサイド Javascript の i18n ライブラリにはローカライゼーション、ローケル依存の日付表示、そしてさまざまな国際化のための文字列のフォーマットのメソッドが含まれています。I18n は国際化(Internationalization)の略語で。詳細は本記事最後の用語集をご覧ください。ここでは i18n ライブラリの使用方法を示し、計算結果によって変わる文字列を含む一つのフレーズ全体を、ひとつの文字列として翻訳でき、翻訳者がフレーズに含まれる語の順番も変更できることとを示します。
1. ここでの例となる文字列では、「Hello」と「, Welcome.」という2つの文字列と、「@UserName()」によって得られる値で1つのフレーズを作っています。
'Hello ' + @Name("[CN]",@UserName()) + ', Welcome.'
ここで「@UserName()」の部分をプレースフォルダで置き換えた1つの文字列に変更します。こうすることで別々の2つの文字列を翻訳するのではなく、関連のある語をすべて含んだ1つの文字列として翻訳できます。
2. スクリプトエディタダイアログの右側にある「参照タブ」で、「ライブラリ」ドロップダウンにある「Runtime」を選択します。「I18n」のトグルを開くと「format()」メソッドがあります。
このメソッドの最初の引数がローカライズ対象の文字列で、2番目以降の引数はプレースフォルダーの {0}、{1} などに入れるオブジェクトです。プレースフォルダの上限は4つまでで、それ以上のプレースフォルダを指定したいときには、文字列を複数に分割することになります。
「format()」 メソッドをうレースフォルダー付きで使用する例は以下のようになります。
var message = 'Hello {0}, Welcome.';
message = I18n.format(message, @Name("[CN]",@UserName()));
return message;
プロパティファイルから翻訳された文字列を使用して計算結果フィールドの値を返すスクリプトは以下のようになります。
// 'Hello {0}, Welcome.'
var message = strings['greeting'];
message = I18n.format(message, @Name("[CN]",@UserName()));
return message;
プロパティファイルに含まれる内容は以下のようになります。
##G11N This file contains translated messages
# {0} is the UserName
greeting=Hello {0}, Welcome.
その他の新しい設計要素のローカライゼーション
以下のような設計要素のローカライゼーションのやり方は、インラインスクリプトのローカライズのやり方に依存しています。
- サーバーサイド Javascript ライブラリ
サーバーサイド Javascript ライブラリからのローカライズした文字列を取得するには、独自のプロパティファイルを作成し、インラインの Javascript と同じやり方で文字列を抽出します。しかし、ライブラリを使用しているすべての XPage にバンドルリソースを追加するのではなく、プロパティファイルの値をロードするバンドルリソースをプログラムで作成することができます。
以下の例では BundleResource クラスのインスタンスをプログラムで作成しています。BundleResource クラスのインスタンスでは src と component プロパティをプログラムで設定する必要があり、 src プロパティにはプロパティファイルを、 component プロパティには XPage のトップレベルのコントロール、つまり XPage 自身を示す view を設定しています。ResourceBundle から取得できたテキストは、同じリソースが同じロケールで詳細参照されたときに再利用できるよう applicationScope 変数に格納されています。
このスクリプトライブラリを使用する計算結果フィールドからは、 ibraryMessage() 関数を呼び出すことで、ストリングバンドルから「libraryMessage」キーの値を取得します。
function libraryMessage(){
// 'Library message'
return getStrings()['libraryMessage'];
}
function getStrings(){
// see http://www-10.lotus.com/ldd/ddwiki.nsf/dx/JavaScriptInternationalization.htm
var locale = view.getLocale();
if( applicationScope.stringsPerLocale ){
var existingStrings = applicationScope.stringsPerLocale[locale];
if( existingStrings ){
return existingStrings;
}
}
var resource = new com.ibm.xsp.resource.BundleResource();
resource.src = "/strings.properties";
resource.component = view;
var strings = resource.contents;
synchronized(applicationScope){
if( ! applicationScope.stringsPerLocale ) {
applicationScope.stringsPerLocale = new java.util.HashMap();
}
applicationScope.stringsPerLocale[locale] = strings;
}
return strings;
}
- クライアントサイド Javascript ライブラリ
クライアントサイド Javascript ライブラリのローカライズについては明確な指針はありません。もし Dojo ウィジェットを使用しているのであれば、Djo の機能が働き、ロケールが djConfig 属性に書き込まれます。これを使用してローカライズすることもできます。
もうひとつの方法としては、ローカライズされた文字列をサーバーからクライアントへクライアントスクリプトのメソッドの引数として渡すことができます、例えば以下のようになります。ここではクライアントサイド Javascript で alert() 関数が呼ばれていますが、この関数の引数に指定されている #{javascript: strings['alertMessage']} はページの生成時にサーバーサイドでプリプロセスされ、プロパティファイルから取得した翻訳済みのテキストが設定されます。
<xp:button value="Click me" id="button2">
<xp:eventHandler event="onclick" submit="false">
<xp:this.handlers>
<xp:handler type="text/javascript">
<xp:this.script><![CDATA[
alert("#{javascript: strings['alertMessage'] }");
]]></xp:this.script>
</xp:handler>
</xp:this.handlers>
</xp:eventHandler>
</xp:button>
- テーマ
テーマにはローカライズされるような文字列を定義すべきではありませんテーマのメカニズムはスタイルの変更などのために突然変更されることがあります。どうしても必要であるのなら、XPagesのバンドルリソースを使用する「値の計算」への参照を使用すべきです。先のサーバーサイド Javascript の例のように、テーマのプロパティに「値の計算」を設定すべきです。例えば以下のようになります。
<control>
<name>mySubmitButton</name>
<property>
<name>value</name>
<value>${javascript:
function getThemeStrings(){
// see http://www-10.lotus.com/ldd/ddwiki.nsf/dx/JavaScriptInternationalization.htm
var locale = view.getLocale();
if( applicationScope.stringsPerLocale ){
var existingStrings = applicationScope.stringsPerLocale[locale];
if( existingStrings ){
return existingStrings;
}
}
var resource = new com.ibm.xsp.resource.BundleResource();
resource.src = "/strings.properties";
resource.component = view;
var strings = resource.contents;
synchronized(applicationScope){
if( ! applicationScope.stringsPerLocale ) {
applicationScope.stringsPerLocale = new java.util.HashMap();
}
applicationScope.stringsPerLocale[locale] = strings;
}
return strings;
}
return getThemeStrings()['submitButtonLabel'];
}</value>
</property>
</control>
- スタイルシート
スタイルシートファイルの中でローカライズされた文字列を定義したりアクセスする機能はありません。そのような機能は必要ないといっていいでしょう。もしスタイルシートの中にローカライズする文字列を置くときには、ロケールごとにスタイルシートファイルのコピーを作成し、ロケールに応じて選択的にスタイルシートファイルを出力するようにします。この手法は Supporting Bidi in XPages でも説明している、異なる css ファイルの選択的出力と同じです。
より複雑なローカライゼーションのメカニズム
もうひとつのやり方として、普通にローカライズした文字列をスクリプトを使用して処理するという方法があります。例えばそれぞれ異なるテキストを持つ2つの表示用のラベルを持たせ、どちらのラベルを表示するかはその時々に計算されるようにすることもできます。ただし、ページごとにそれぞれのコントロールやテキストの値を処理するオーバーヘッドがあるため、このやり方は推奨されません。これはバンドルを使用すれば避けられます。もうひとつ、バンドルによる手法が推奨される理由は、それを使用することで XPages の構造が理解しやすくなるという点もあります。
この処理の例を以下に示します。ラベルの値は afterPageLoad イベントのスクリプト処理でで変更されて、初期の {0} と {1} というプレースフォルダーを含む文字列で、{0} と {1} の場所に数字を入れた文字列に変換されています。
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
<xp:this.afterPageLoad><![CDATA[#{javascript:
var created = java.lang.Integer.valueOf(2007);
var lastModified = java.lang.Integer.valueOf(@Year(@Today()));
// Copyright Example.com {0}, {1}
var copyright = getComponent('copyright');
copyright.value = I18n.format(copyright.value, created, lastModified );
}]]></xp:this.afterPageLoad>
The main contents of the page<xp:br></xp:br>
<xp:br></xp:br>
<xp:label id="copyright" value="Copyright Example.com {0}, {1}"/>
</xp:view>
用語集
- I18N 国際化(Internationalization)
国際化とローカライズを組み合わせたプロセスです。
- G11n グローバライゼーション(Globalization)
アプリケーションを異なるロケールや使用できるようにしたり、多言語に翻訳できるようにするための準備に必要なステップです。例えば以下のような作業です。
1. 日付、数字、通貨などが、アプリケーションを使用するユーザーの指定したロケールに応じて、そのロケールで求められる書式で表示できることを確認します。「en_US」では日付の短い書式を「12/31/2000」と記述しますが、「en_UK」では「311/12/2000」と記述します。
2. Bidi 言語(アラビア語などの逆方向言語)を処理できるようにスタイルシートとレイアウトを構成います。例えばアラビア語のテキストは左から右ではなく右から左へ記述されます。詳細については HTML の「dir」 属性について検索してください。
3. すべてのローカライズ可能な文字列をプロパティファイルに抽出し、それらの文字列をバンドルを通して使うようにします。そうすることでプロパティファイルの翻訳したバージョンが利用できるようになります。バンドルはロケールに応じてロードするファイルを選択します。
4. 画像ファイルに翻訳すべきテキストが含まれていないことを確認します。必要に応じて、ビルドの機能でロケールに応じてことなる画像がロードされるようにします。
- L10n ローカライゼーション (Localization)
アプリケーションで用意された既存のリソースに、翻訳したバージョンを追加することです。以下のような例が含まれます。
1. ローカライズすべき文字列が含まれるプロパティファイルの翻訳したバージョンを追加します。
2. テキストを含むイメージの翻訳したバージョンを追加します。
I18n、G11n、L10n はいずれも文字数の多い英語単語です。このような長い単語を省略するために、最初と最後の文字の間に含まれる文字列を、その文字数で置き換えて省略しています。