web-dev-qa-db-ja.com

JSFのローカリゼーション、リクエスト/ビューごとではなくセッションごとに選択したロケールを記憶する方法

faces-config.xml

<application>
    <locale-config>
        <default-locale>ru</default-locale>
        <supported-locale>ua</supported-locale>
    </locale-config>
</application> 

Beanアクションメソッドでは、現在のビューのロケールを次のように変更しています。

FacesContext.getCurrentInstance().getViewRoot().setLocale(new Locale("ua"));

問題は、uaロケールが適用されますが、セッションごとではなくリクエスト/ビューごとにのみ適用されることです。同じセッション内の別の要求/ビューは、ロケールをデフォルトのru値にリセットします。

セッションにロケールを適用するにはどうすればよいですか?

43
sergionni

選択したロケールをセッションスコープに保存し、ビュールートの2つの場所に設定する必要があります。1回 UIViewRoot#setLocale() を変更した直後(現在のロケールを変更しますviewroot、したがってポストバックに反映されます;この部分は、後でリダイレクトを実行する場合は不要です) <f:view> (設定/保持する)のlocale属性に一度後続のリクエスト/ビューのロケール)。

以下に、そのようなLocaleBeanがどのように見えるかを示す例を示します。

package com.example.faces;

import Java.util.Locale;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

@ManagedBean
@SessionScoped
public class LocaleBean {

    private Locale locale;

    @PostConstruct
    public void init() {
        locale = FacesContext.getCurrentInstance().getExternalContext().getRequestLocale();
    }

    public Locale getLocale() {
        return locale;
    }

    public String getLanguage() {
        return locale.getLanguage();
    }

    public void setLanguage(String language) {
        locale = new Locale(language);
        FacesContext.getCurrentInstance().getViewRoot().setLocale(locale);
    }

}

そして、次のようなビューの例があります:

<!DOCTYPE html>
<html lang="#{localeBean.language}"
    xmlns:f="http://Java.Sun.com/jsf/core"
    xmlns:h="http://Java.Sun.com/jsf/html">
<f:view locale="#{localeBean.locale}">
    <h:head>
        <title>JSF/Facelets i18n example</title>
    </h:head>
    <h:body>
        <h:form>
            <h:selectOneMenu value="#{localeBean.language}" onchange="submit()">
                <f:selectItem itemValue="en" itemLabel="English" />
                <f:selectItem itemValue="nl" itemLabel="Nederlands" />
                <f:selectItem itemValue="es" itemLabel="Español" />
            </h:selectOneMenu>
        </h:form>
        <p><h:outputText value="#{text['some.text']}" /></p>
    </h:body>
</f:view>
</html>

<html lang>はJSFの機能には必要ありませんが、検索ボットがページを解釈する方法は必須です。そうしないと、重複コンテンツとしてマークされる可能性があり、SEOに悪影響を及ぼす可能性があります。

関連:

80
BalusC

問題は.propertiesファイル名にもあることがわかります。 Java en_gbのようなロケールusコード(小文字))ただし、(Netbeansによって)自動的に作成されたロケールは小文字です。つまり、messages_en_GB.propertiesに変更します。

4
Sebastian

このコンポーネントf:viewはJSFページに存在せず、動作しません。デフォルトの英語のみが表示されます。このf:viewコンポーネントのlocalae値を指定すると、正常に動作します。私は今、同じ問題に直面しました。

3

@BalusCの優れたソリューションへの小さなコメント。バッキングBeanで何らかのメソッドを実行する<f:viewAction>がある場合。そのメソッド内のFacesContext.getCurrentInstance().getViewRoot().getLocale()の呼び出しから使用可能なロケールは、ユーザーの選択によってセッションBeanに設定されるロケールではなく、ユーザーのブラウザーまたはデフォルトのアプリケーションロケールによって設定されるロケールになります(もちろん、ブラウザーのロケールがユーザーが選択したロケール)。

おそらく、@ BalusCが提供するソリューションを実装するときに何か間違ったことをしたからです。

EDIT。JSFライフサイクル で遊んだ後、ロケールでのこの動作は<f:viewAction>とは関係ありません。同様の動作は@PostContructでも同様です。リクエスト内の<f:view locale="#{localeBean.locale}">(ユーザーが選択したロケールの後)は、応答のレンダリングフェーズで実行されます。 <f:viewAction>および@PostContructメソッドは、アプリケーション呼び出しフェーズで実行されます。そのため、このメソッドで実行されるロジックは、ユーザーが選択したロケールにアクセスできません。

正しいロケールが必要なときに使用するソリューションは、<f:viewAction>および@PostContructメソッドを含む他のバッキングBeanにlocaleBeanを挿入し、UIViewRoot#setLocale()でロケールを設定することです。これらのメソッドの最初のlocaleBeanから。

1
Znas Me

環境でCDIとdeltaspike( JSFモジュール )を使用できる場合は、LocaleBeanに次を追加して、現在のビューのロケールを自動的にリセットできます。

@javax.enterprise.context.SessionScoped
public class LocaleBean implements Serializable {

    ...

    public void resetLocale(@Observes @BeforePhase(JsfPhaseId.RENDER_RESPONSE) PhaseEvent event) {
        event.getFacesContext().getViewRoot().setLocale(this.locale);
    }
}
0
Xavier Dury