Локализация в JSF, как запомнить выбранную локаль для сеанса, а не для запроса / представления - PullRequest
42 голосов
/ 28 января 2011

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.

Как применить языковой стандарт для сеанса?

Ответы [ 5 ]

80 голосов
/ 28 января 2011

Необходимо сохранить выбранный языковой стандарт в области видимости сеанса и установить его в корне просмотра в двух местах: один раз на UIViewRoot#setLocale() сразу после изменения языкового стандарта (который изменяет языковой стандарт текущего видового корня итаким образом, это отражается в обратной передаче; эта часть не нужна при последующем перенаправлении) и один раз в атрибуте locale <f:view> (который устанавливает / сохраняет языковой стандарт в последующих запросах /views).

Вот пример того, как должен выглядеть такой 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.

Связанный:

4 голосов
/ 14 ноября 2011

Я вижу, что проблема также с именем файла .properties.Java Locale использует коды (в нижнем регистре), например: en_gb Но автоматически созданный языковой стандарт (для Netbeans) - это casecase_uppercase, т.е.

3 голосов
/ 30 апреля 2016

Этот компонент f: view не находится на вашей JSF-странице, он не будет работать и будет отображать только английский язык по умолчанию. Укажите значение localae для этого компонента f: view, тогда он будет работать нормально. Я столкнулся с той же проблемой, теперь она работает нормально.

1 голос
/ 24 декабря 2016

Одно небольшое замечание к @BalusC отличное решение.Если у нас есть <f:viewAction>, который выполняет некоторый метод в компоненте поддержки.Языковой стандарт, доступный из вызова к FacesContext.getCurrentInstance().getViewRoot().getLocale() внутри этого метода, будет языковым стандартом, установленным браузером пользователя или языковым стандартом приложения по умолчанию, а не тем языковым стандартом, который установлен для сессионного компонента по выбору пользователя (конечно, они могут совпадать, если языковой стандарт браузера равен той языковой стандартпользователь выбран).

Я могу быть исправлен, потому что, возможно, я что-то не так сделал при реализации решения, предоставляемого @ BalusC.

EDIT. После игры с JSF lifecycle это поведение с локалью не связано с <f:viewAction>, потому что такое же поведение также с @PostContruct.<f:view locale="#{localeBean.locale}"> в запросе (после выбора пользователем локали) выполняется в фазе ответа рендеринга.Методы <f:viewAction> и @PostContruct выполняются на этапе вызова приложения.Вот почему логика, которая выполняется в этом методе, не имеет доступа к выбранной пользователем локали.

Решение, которое мы используем, когда нам нужна правильная локаль, заключается в том, чтобы внедрить (CDI) localeBean в другой компонент поддержки, содержащий <f:viewAction> и @PostContruct методов, а затем установите языковой стандарт с UIViewRoot#setLocale() из localeBean в начале этих методов.

0 голосов
/ 08 марта 2016

Если вы можете использовать CDI и deltaspike ( JSF module ) в вашей среде, вы можете добавить следующее к вашему 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);
    }
}
...