第13章 国際化とテーマ (Internationalization and themes)

多言語 UI メッセージを扱う組み込みコンポーネントの提供により、 Seam では容易に国際化されたアプリケーションを作成できます。

13.1. ロケール

各ユーザログインのセッションは、 java.util.Locale インスタンスと関連しています。 (アプリケーションでは、 locale という名前の セッションスコープのコンポーネントとして扱えます ) 通常の環境では、 ロケールのための特別な設定は不要です。 Seam ではアクティブはロケールの決定は単純に JSF に委譲しています。

  • HTTP リクエストで指定されるロケール (ブラウザのロケール) があり、 そして、faces-config.xml により対応可能なロケールの組み合わせの中にそのロケールがある場合、 その後のセッションの期間、そのロケールを使用します。
  • それ以外で、デフォルトロケールが faces-config.xml 中に指定されていれば、 その後のセッションの期間、そのロケールを使用します。
  • それ以外では、サーバのデフォルトロケールを使用します。

Seam 設定プロパティによるマニュアルでロケールの設定が 可能 です。 ( org.jboss.seam.core.localeSelector.languageorg.jboss.seam.core.localeSelector.country、 そして、org.jboss.seam.core.localeSelector.variant ) でも、これを行う妥当な理由は考え付きません。

しかし、アプリケーションユーザインタフェースを介して、 ユーザにマニュアルでロケール設定を可能とさせることは有用です。 Seam は上記のアルゴリズムによって決定されるロケールをオーバライドする組み込み機能も提供しています。 すべきことは、JSP または、Facelet ページのフォームに以下の断片を追加するだけです。

<h:selectOneMenu value="#{localeSelector.language}">
    <f:selectItem itemLabel="English" itemValue="en"/>
    <f:selectItem itemLabel="Deutsch" itemValue="de"/>
    <f:selectItem itemLabel="Francais" itemValue="fr"/>
</h:selectOneMenu>
<h:commandButton action="#{localeSelector.select}" value="#{messages['ChangeLanguage']}"/>

あるいは、faces-config.xml に対応されたすべてのロケールの組み合わせが欲しければ、 以下を使ってください。

<h:selectOneMenu value="#{localeSelector.localeString}">
    <f:selectItems value="#{localeSelector.supportedLocales}"/>
</h:selectOneMenu>
<h:commandButton action="#{localeSelector.select}" value="#{messages['ChangeLanguage']}"/>

これを使用してドロップダウンからアイテムを選択し、ボタンをクリックすれば、 その後のセッションの期間、Seam と JSF のロケールはオーバライドされます。

13.2. ラベル

JSF は、ユーザインタフェースのラベルや説明用テキストの国際化を、 <f:loadBundle /> を使用によって対応しています。 Seam アプリケーションでもこのアプローチが使用可能です。 別途、組み込みの EL 式を利用したテンプレート化されたラベルを表示するために、 Seam メッセージ コンポーネントを利用することも可能です。

13.2.1. ラベルを定義する

各ログインセッションは、 関連付けられた java.util.ResourceBundle のインスタンスを持ちます。 (アプリケーションでは、 org.jboss.seam.core.resourceBundle という名前の セッションスコープのコンポーネントとして扱えます ) この特別なリソースバンドルを通して、 国際化されたラベルを有効化する必要があります。 デフォルトで、 Seam によって使用されるリソースバンドルは、 メッセージと呼ばれ、 messages.propertiesmessages_en.propertiesmessages_en_AU.properties などの名前のファイルでラベルを定義する必要があります。 これらのファイルは通常、 WEB-INF/classes ディレクトリに配置します。

従って、messages_en.properties では、

Hello=Hello

そして、messages_en_AU.properties では、

Hello=G'day

org.jboss.seam.core.resourceBundle.bundleNames と呼ばれる Seam 設定プロパティによって、 リソースバンドルとして異なる名前を選択することが可能です。 リソースバンドル名のリストを指定してメッセージの検索をさせる (深さ優先) こともできます。

<core:resource-bundle>
    <core:bundle-names>
        <value>mycompany_messages</value>
        <value>standard_messages</value>       
    </core:bundle-names>
</core:resource-bundle>

特定のページだけにメッセージを定義したいのであれば、 そのJSFビューIDと同じ名前でリソースバンドルに指定します。 このときIDの最初の / と最後の拡張子を除去します。 つまり /welcome/hello.jsp にメッセージを表示したいだけであれば、 そのメッセージを welcome/hello_en.properties に書きます。

pages.xml に明確なバンドル名を指定することもできます:

<page view-id="/welcome/hello.jsp" bundle="HelloMessages"/>

これで HelloMessages.properties に定義されたメッセージを /welcome/hello.jsp で使うことができます。

13.2.2. ラベルを表示する

もし、Seamのリソースバンドルにラベルを定義したならば、 すべてのページに <f:loadBundle ... /> をタイプすることなく、 これらが使用可能です。 その代わりに、以下のように単純にタイプします:

<h:outputText value="#{messages['Hello']}"/>

あるいは、

<h:outputText value="#{messages.Hello}"/>

さらに良いことに、メッセージそのものには EL 式を含むことも可能です。

Hello=Hello, #{user.firstName} #{user.lastName}
Hello=G'day, #{user.firstName}

コードの中にメッセージを使用することも可能です。

@In private Map<String, String> messages;
@In("#{messages['Hello']}") private String helloMessage;

13.2.3. Faces メッセージ

facesMessages コンポーネントはユーザに成功か失敗かを表示するとても便利な方法です。 上述した機能は、faces messages にも有効です。

@Name("hello")
@Stateless
public class HelloBean implements Hello {
    @In FacesMessages facesMessages;
    
    public String sayIt() {
        facesMessages.addFromResourceBundle("Hello");
    }
}

これは、ユーザのロケールに応じて、Hello, Gavin King あるいは、 G'day, Gavin と表示されます。

13.3. タイムゾーン

org.jboss.seam.core.timezone という名の セッションスコープの java.util.Timezone インスタンスと、 org.jboss.seam.core.timezoneSelector という名の タイムゾーン変更のためのSeamコンポーネントもあります。 デフォルトではタイムゾーンはサーバのデフォルトタイムゾーンです。 あいにくJSF仕様では、 <f:convertDateTime>を使って明示的にタイムゾーンを指定しない限り、 全ての日付と時刻はUTCであると想定され、UTCとして表示されます。 これは非常に不便なデフォルト動作です。

Seamはこの動作をオーバーライドし、全ての日付と時刻をデフォルトでSeamタイムゾーンにします。 さらにSeamは、Seamタイムゾーンにおける変換をいつでも行えるよう、 <s:convertDateTime> タグを提供します。

13.4. テーマ

Seamアプリケーションはまた、とても簡単にスキン変更ができます。 テーマAPIはローカライゼーションAPIにとても似ていますが、 もちろんこれら2つの関心事は直交しており、 ローカライゼーションとテーマの両方をサポートするアプリケーションもあります。

まず、サポートされるテーマのセットを設定します:

<theme:theme-selector cookie-enabled="true">
    <theme:available-themes>
        <value>default</value>
        <value>accessible</value>
        <value>printable</value>
    </theme:available-themes>
</theme:theme-selector>

最初にリストされたテーマがデフォルトテーマであることに注意してください。

テーマは、テーマと同じ名前でプロパティファイルに定義されます。 例えば、 default テーマは default.properties に一連のエントリとして定義されます。 例えば、default.properties は以下のように定義します:

css ../screen.css
template template.xhtml

通常、 テーマリソースバンドルのエントリは CSS スタイルや画像へのパスや facelet テンプレートの名前になるでしょう (通常はテキストであるローカライゼーションリソースバンドルとは違って)。

これでJSPやfaceletページにおいてこれらのエントリを使えます。 例えば、faceletページでスタイルシートを適用するには:

<link href="#{theme.css}" rel="stylesheet" type="text/css" />

最も強力な使い方として、 faceletでは <ui:composition> によってテンプレートを適用できます。

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    template="#{theme.template}">

ちょうどロケールセレクタのように、 ユーザが自由にテーマを変更できるよう、組み込みのテーマセレクタがあります。

<h:selectOneMenu value="#{themeSelector.theme}">
    <f:selectItems value="#{themeSelector.themes}"/>
</h:selectOneMenu>
<h:commandButton action="#{themeSelector.select}" value="Select Theme"/>

13.5. ロケールとテーマ設定のクッキーによる永続化

ロケールセレクタ、テーマセレクタ、タイムゾーンセレクタは全て、 ロケールとテーマ設定をクッキーに永続化することをサポートしています。 単に cookie-enabled プロパティを設定してください。

<theme:theme-selector cookie-enabled="true">
    <theme:available-themes>
        <value>default</value>
        <value>accessible</value>
        <value>printable</value>
    </theme:available-themes>
</theme:theme-selector>

<core:locale-selector cookie-enabled="true"/>