UIX開発者ガイド | ![]() 目次 |
![]() 前へ |
![]() 次へ |
このトピックでは、UIXで国際化アプリケーションを開発する方法を説明します。実行時に自動的にローカライズされるUIX ComponentsおよびuiXMLのページの記述方法や、ページを正しいロケールおよびキャラクタ・セットで配信する方法、および両方向言語をサポートする方法などについて説明します。
ここでは、次の項目について説明します。
多くの異なる言語を使用する多数のユーザーにアプリケーションをデプロイすることはごく一般的です。Javaに習熟している場合、サーブレットをNLS(National Language Support)準拠にする方法を知っている場合もあるでしょう。Javaでは内部的にUnicode文字列が使用されるため、文字列の処理は、通常、NLSに準拠しています。また、JavaのResourceBundle
は翻訳テキストにアクセスするための堅固な標準的メカニズムです。ただし、サーブレットには、従来のJavaアプリケーションでは考慮する必要がなかった多くの問題があります。
第1に、従来のJavaアプリケーションでは複数のロケールがサポートされていましたが、通常、実行できるのは1回に1つのみでした。Webアプリケーションでは、1つのWebサーバーで、それぞれ独自のロケールを使用する多くのユーザーをサポートする必要があります。ここでは、1つのページを複数言語で実行できる、UIX ComponentsまたはuiXMLのページの記述方法を学びます。また、ユーザーの指定ロケールをUIXで自動的に検出する方法、およびその選択をオーバーライドする方法を学びます。
第2に、JavaサーバーではUnicode文字列のみが使用されますが、ユーザーのブラウザでは、任意の数の文字コードが実行されます。「文字コード」とは、数字、アルファベットまたは漢字などのテキストと、バイト・ストリームとのマッピングです。JavaのUnicodeサポートは便利ですが、(正確には、使用されるUTF-16文字コードでは)各文字について2バイトから4バイトが必要とされ、帯域幅が消費されます。デフォルトのHTMLエンコーディング(西ヨーロッパ言語ISO-8859-1)では各文字に1バイトしか使用しませんが、ごく一部のUnicode文字しかサポートされません。ここでは、UIXでキャラクタ・セット・エンコーディングが処理される方法、および必要に応じてその動作をオーバーライドする方法を説明します。
第3に、アラビア語やヘブライ語などの両方向言語をサポートするページの記述方法を説明します。UIX ComponentsおよびuiXMLを使用すると、簡単に記述できます。
また、適切に実装するためにはWebアプリケーションの開発者が長時間作業する必要があったいくつかのタスクを、自動的および透過的に処理する方法を学びます。
oracle.cabo.share.nls.LocaleContext
APIは、UIXでのローカライズにおいて重要です。APIには、ロケール、レンダリングの方向(左から右、または右から左)およびTimeZone
といった、ページを正しく翻訳するために必要な情報が含まれています。また、負荷の高いResourceBundle.getBundle()
Java APIを繰り返しコールしないための、ResourceBundle
オブジェクトのキャッシュも含まれています。
その他ほとんどすべてのコンテキスト・オブジェクトからLocaleContext
を取得できます。UIX ComponentsのRenderingContext
、およびUIX ControllerのBajaContext
インタフェースのどちらにもgetLocaleContext
メソッドがあります。可能な場合は、これらのRenderingContext
およびBajaContext
のデフォルトの実装によりユーザーのリクエストが自動的に確認され、accept-languages
HTTPヘッダーを使用して適切なロケールが推測されます。そのため、ほとんどのアプリケーションでロケールを取得するための操作をせずに、正しいロケールが得られます。必要に応じて選択をオーバーライドする方法は後で学びますが、ここではLocaleContext
の利用方法を説明します。
UIX Componentsを翻訳する1つの方法はごく明白です。リクエストごとにUIX ComponentsのBeanを新規に作成し、正しく翻訳されたテキストを設定する方法です。
Locale locale = localeContext.getLocale();
ResourceBundle bundle =
ResourceBundle.getBundle(_BUNDLE_CLASS_NAME, locale);
ButtonBean button = new ButtonBean();
button.setText(bundle.getString("buttonText"));
ただし、この場合、リクエストごとにボタン(およびページのその他すべての部品)を作成するか、ロケールごとに1つのコピーを保存する必要があります。これでは負荷がかかります。Beanを一度作成し、ローカライズされたテキストをそのBeanで独自に取得する方が効率的です。UIX Componentsでは、動的出力(データ・バインド)をサポートする場合と同じ方法で、これをサポートします。(「データ・バインド」のトピックをまだ読んでいない場合は、必要に応じて参照してください。)
簡単で便利なクラスoracle.cabo.ui.data.bind.BundleBoundValue
を使用して、この作業すべてを実行できます。このクラスでは、ResourceBundle
の名前およびキーを取得して、翻訳されたテキストを自動的に取得するBoundValue
を返します。
ButtonBean button = new ButtonBean();
button.setTextBinding(new BundleBoundValue(_BUNDLE_CLASS_NAME,
"buttonText"));
これで終了です。このボタンにより、翻訳済テキストが実行時に自動的に取得されます。
UIX Componentsの場合と同様に、uiXMLを翻訳する1つの方法は明白です。uiXMLページを英語で作成し、ファイルをそのまま翻訳チームに渡す方法です。uiXMLは、翻訳者が不得意とするJSPなどの様々なファイル形式に比べて処理が容易です。しかし、翻訳作業ができたとしてもこのようなアプリケーションの形態はシステムにも相当の負担がかかります。すべてのファイルを実行時にロードする必要があるため、メモリーが無駄に使用されるだけでなく、ページに修正を加えるたびに、そのページのすべてのコピーも修正する必要があります。ユーザーがページをカスタマイズした場合、そのページのすべてのコピーもカスタマイズすることになります。しかし、もっと効率的な方法があります。
uiXMLのユーザーは、UIX Componentsの開発者と同じ方法を使用できますが、推奨される方法は、<dataScope>
要素、およびこのセクションで紹介する新規要素の<bundle>
を使用する方法です。
<dataScope>
要素の基本を参照します。この要素では、そこに含まれるすべての要素にデータのソースを公開します。その中の<provider>
要素内に、それぞれname
属性を1つずつ持つ一連の<data>
要素を追加します。
<dataScope>
<provider>
<data name="...">
... a data provider ...
</data>
<data name="...">
... a second data provider ...
</data>
</provider>
<contents>
... Everything in here can use this data ...
</contents>
</dataScope>
<bundle>
要素は、<inline>
および<method>
などの他のデータ・プロバイダ要素に似ています。ただし、<bundle>
はResourceBundle
を使用します。ResourceBundle
の完全なJavaクラス名である属性のclass
を使用します。一度定義されると、すべてのコンテンツをキーと値のペアとして公開します。
<dataScope>
<provider>
<data name="nls">
<bundle class="your.Bundle"/>
</data>
</provider>
<contents>
<button data:text="buttonText@nls"/>
</contents>
</dataScope>
これですべてです。翻訳済テキストをこの新規のnlsデータ・プロバイダにバインドすると、実行時にすべてが自動的に表示されます。もちろん、(個々の<data>
要素内にある)複数の<bundle>
要素を使用して、複数のResourceBundle
にバインドできます。また、一般的に、<dataScope>
要素はページの最上部に置かれるため、<bundle>
要素はページ全体で一度宣言するだけです。
DataObject
の場合について考えます。uiXMLおよびUIX Componentsコードから完全に分離されたデータソースはすべて、実行時にRenderingContext
を取得するため、残りのページでも同じLocaleContext
にアクセスします。翻訳済テキストを表示することも可能です。
public class YourDataObject implements DataObject
{
public Object getValue(RenderingContext context, Object select)
{
if (select.equals(_TRANSLATED_KEY))
{
ResourceBundle bundle =
context.getLocaleContext().getBundle(_BUNDLE_NAME);
return bundle.getObject(_SOME_KEY);
}
...
}
}
多くのクライアントではUIXのLocale
デフォルト設定のみで十分ですが、この選択をオーバーライドする場合があります。特に、一部のWebアプリケーションでは、ユーザーが設定できる作業環境の言語を選択します。
UIX Controllerを使用して開発中の場合、PageBroker
の実装にコードを数行追加するだけです。
public class YourPageBroker extends UIXPageBroker
{
public void requestStarted(BajaContext context)
{
Locale locale = ...;
context.setLocaleContext(new LocaleContext(locale));
}
}
非常に簡単です。UIX Controllerにより、ロケールがUIX ComponentsのRenderingContext
に自動的に渡されます。UIX Componentsを直接使用している場合は、UIX ComponentsのServletRenderingContext.setLocaleContext()
メソッドをコールするだけです。
UIX Componentsの各ページは、1つのLocale
のみで実行されます。デフォルト以外の言語で文字列を表示できないわけではありません。UIX Componentsでは文字を自動的にエスケープし、ブラウザで正しく読み込まれるようにします。
1つ注意する点があります。多言語ページを正しく表示できるブラウザを使用する必要があることです。たとえば、Netscape 4は、多言語対応に優れているとは言えません。
UIX ComponentsおよびuiXMLの両方で、java.text.MessageFormat
クラス、および高速な置換を行うoracle.cabo.share.util.FastMessageFormat
に対する統合サポートを提供しています。
これらのクラスでも、データ・バインド・アーキテクチャおよびBoundValue
インタフェースを基にすべてが作成されています。UIX Componentsでは、oracle.cabo.ui.data.bind.MessageFormatBoundValue
クラスを提供しています。このクラスでは1つのBoundValue
からメッセージの書式マスクを動的に取得し、そのマスクに挿入する各オブジェクトをBoundValue
配列に入れます。たとえば、ResourceBundle
に次のようなエントリがあるとします。
...
{"textFormat", "From {0} to {1}"}
...
次のコードでは、2つの文字列を自動的に取得し、その書式マスクに挿入し、現行ロケールの正しい書式を取得します。
StyledTextBean styledText = new StyledTextBean();
// Get the format mask from a ResourceBundle
BoundValue formatMask = new BundleBoundValue(_BUNDLE_CLASS_NAME,
"textFormat");
// And get each of the two pieces that go into the mask
// from DataObjects:
BoundValue firstEntry = new DataBoundValue("firstSelectKey");
BoundValue secondEntry = new DataBoundValue("secondSelectKey");
// And wrap it all up in a MessageFormatBoundValue
styledText.setTextBinding(new MessageFormatBoundValue(
formatMask,
new BoundValue[]{firstEntry,
secondEntry});
この例は、少し複雑です。ただし、強力です。
<messageFormat>
要素を使用して、uiXML内で同じ機能が得られます。
<dataScope>
<provider>
<data name="nls">
<bundle class="your.Bundle"/>
</data>
</provider>
<contents>
<styledText>
<boundAttribute name="text">
<messageFormat data:format="textFormat@nls">
<dataObject select="firstSelectKey"/>
<dataObject select="secondSelectKey"/>
<messageFormat>
</boundAttribute>
</styledText>
</contents>
</dataScope>
小さな機能に対して長いテキストが記述されていますが、ここで注目するのは、<boundAttribute>
要素とその内部です。
DataObject
以外にバインドする場合、<boundAttribute>
を使用する必要があります。
<messageFormat>
要素では、バインド先となる値を定義します。上の例ではリソース・バンドルから書式を動的に取得するよう選択していますが、format
属性を直接設定することも可能です。
BoundValue
を定義する2つの子は、それぞれ1つのデータを取得してメッセージの書式にマージします。
このセクションの最初に記載したFastMessageFormat
クラスが、デフォルトで使用される書式設定クラスです。特に次のような索引ベースの単純な置換のみが可能です。
some{1}text{0}here{2}andthere
また、この索引文字に対して、先頭に一重引用符を付けることでエスケープすることが可能です。Javaのビルトイン書式設定クラスは負荷が高いため、可能であれば使用しないことをお薦めします。ただし、MessageFormatBoundValue
クラス、およびUIXの<messageFormat>
オブジェクトには、fast属性が用意されています。fast
属性をfalse
に設定した場合、機能は増えますが、実装は遅くなります。
前に説明したように、文字コードは、テキストとバイト・ストリームとのマッピングを定義したものです。
UIX Controllerを使用せずにUIX ComponentsまたはuiXMLを単独で使用する場合、追加で行う作業がいくつかあります。ServletResponse
にWriter
を要求し、使用するエンコーディングをサーブレットAPIに指示する必要があります。ServletRequest
のパラメータが正しいキャラクタ・セットに適切にデコードされていることも確認します。
UIX Controllerを使用している場合は、UIXでこれらが自動的に処理されます。UIXで推奨されるデフォルトの文字コードは、UTF-8です。これは、特別なUnicodeエンコーディングです。UTF-16(Java文字列に使用されるエンコーディング)のように、Unicodeキャラクタ・セットのすべての文字がサポートされます。UTF-16とは異なり、文字ごとに2バイトから4バイトは使用されません。1バイトから3バイトが使用されます。ASCII文字(0(ゼロ)から127)の場合、1バイトのみが使用されます。HTMLのタグはすべてASCIIのため、HTMLページのほとんどのコンテンツではASCIIが使用されています。このエンコーディングの場合、実質的に使用される領域が少なくなります。
UIX Controllerでこのデフォルトをオーバーライドするには、PageBroker
の実装にコードを数行追加するだけです。
public class YourPageBroker extends UIXPageBroker
{
public void requestStarted(BajaContext context)
{
String desiredEncoding = ...;
context.getPageDecoder().setRequestCharacterEncoding(desiredEncoding);
}
}
ここでもこれですべてです。requestStarted()
内でコールしていることが重要です。
一部のサーブレット・エンジンでは、サーブレット・リクエストの自動的なデコードがサポートされているので、注意してください。たとえば、サーブレット2.3仕様では、ServletRequest.setCharacterEncoding()
メソッドを定義しています。サーブレット2.3エンジン(Tomcat 4.0など)を使用している場合は、上のコードを次のように変更する必要があります。
public class YourPageBroker extends UIXPageBroker
{
// Servlet 2.3 code only!
public void requestStarted(BajaContext context)
{
String desiredEncoding = ...;
context.getServletRequest().setCharacterEncoding(desiredEncoding);
}
}
また、一部のサーブレット・エンジンで、サーブレット仕様の独自の拡張を使用して、エンコーディングを明示的に設定できるものもあります。これらのエンジンのいずれかを使用している場合でも、requestStarted()
をオーバーライドしてsetRequestCharacterEncoding()
をコールする必要があります。ただし、null
を渡して、UIX Controllerで二重にデコードしないように指示します。
手間がかかりますが、サーブレット2.3仕様でブラウザ間で一貫した動作が提供されるまでは、サーブレット・エンジンの標準以外の動作を自動的にするためにいくつかの操作が必要です。
ただし、文字コードが設定されている場合は、次の処理が自動的に行われます。
PageEvent
で、要求パラメータが自動的にデコードされます(UIX Controllerについて)。
OutputMethod
が、正しいエンコーディングで作成されます。
デコードされた文字を正しく表示するには、ServletRequest
ではなく、PageEvent
を使用する必要があります。サーブレット2.3エンジンではServletRequest
が適切に機能しますが、それでもPageEvent
を使用してください。PageEventではファイルのアップロード時に発行されるパラメータも含まれ、UIXの携帯情報端末サポートに必要な追加のデコードも実行されます。また、最も重要なことは、追加修正や拡張が可能な抽象層であることです。
UIX Componentsのスタックを使用すると、アラビア語やヘブライ語などの両方向言語の処理が単純化されます。それには、ユーザーのブラウザで両方向言語がサポートされている必要があります。Internet Explorer 5、Netscape 6およびMozillaなどです。
UIX ComponentsではgetReadingDirection()
メソッドを使用して、LocaleUtils
からデフォルトのレンダリング方向を取得します。LocaleUtils
は、ロケールからのレンダリング方向(アラビア語およびヘブライ語は右から左、その他すべての言語は左から右)にデフォルト設定します。ページを右から左にレンダリングすることをブラウザに指示するのは、<HTML>
タグのdir="rtl"
属性です。UIX Controllerを介してuiXMLを使用している場合、これらの処理が行われます。UIX ComponentsまたはuiXMLを直接使用している場合、この処理にはDocumentBean
または<document>
要素を使用できます。
ページに方向が指定されている場合、正しい水平位置揃え定数を一貫して使用するだけです。HTMLで通常サポートされているleft
、right
およびcenter
の他に、UIX Componentsではstart
とend
がサポートされます。これらは、デフォルトのleft
およびright
と同じように動作しますが、自動的に右から左方向モードに切り替わります。UIX StylesのXSSテクノロジにより、UIX ComponentsのビルトインのCSSスタイルはすべて、自動的に切り替えられます。
ビルトインXSSを拡張している場合(「カスタマイズ」を参照)、明示的にtext-align
を指定するのではなく、StartTextAlign
およびEndTextAlign
プロパティを注意して使用します。
<styleSheetDocument xmlns="http://xmlns.oracle.com/uix/style">
<import href="blaf.xss"/>
<styleSheet>
<!-- Bad -->
<style name="YourBadStyle">
<property name="text-align">right</property>
....
</style>
<!-- Good -->
<style name="YourGoodStyle">
<includeStyle name="EndTextAlign"/>
<property name="text-align">right</property>
....
</style>
</styleSheet>
</styleSheetDocument>
独自のResourceBundle
を記述して、翻訳する必要はもちろんあります。