Локализация в 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
значение.
Как я могу применить локаль для сессии?
5 ответов
Вам нужно сохранить выбранный языковой стандарт в области видимости сеанса и установить его в корне просмотра в двух местах: один раз UIViewRoot#setLocale()
сразу после изменения языкового стандарта (который изменяет языковой стандарт текущего viewroot и, таким образом, отражается в обратной передаче; эта часть не требуется при последующем перенаправлении) и один раз в locale
атрибут <f:view>
(который устанавливает / сохраняет локаль в последующих запросах / просмотрах).
Вот пример того, как такой 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.
Связанные с:
Я вижу, что проблема также с именем файла.properties. Java Locale использует коды (в нижнем регистре), например: en_gb Но автоматически созданный языковой стандарт (для Netbeans) - это casecase_uppercase, то есть: messages_en_GB.properties Измените имя на: messages_en_gb.properties, и оно должно работать - если вы все перепробовали
Этот компонент f:view не находится на вашей JSF-странице, он не будет работать, и он будет отображать только английский язык по умолчанию. Укажите значение localae для этого компонента f:view, тогда он будет работать нормально. Я столкнулся с той же проблемой, теперь она работает нормально.
Одно небольшое замечание к @BalusC отличное решение. Если у нас есть <f:viewAction>
который выполняет некоторый метод в компоненте поддержки. Язык доступен от звонка до FacesContext.getCurrentInstance().getViewRoot().getLocale()
внутри этого метода будет локаль, которая задается браузером пользователя или локали приложения по умолчанию, а не та локаль, которая задается в сессионном компоненте по выбору пользователя (конечно, они могут совпадать, если локаль браузера равна локали, выбранной пользователем).
Я могу быть исправлен, потому что, возможно, я сделал что-то не так при реализации решения, предоставленного @BalusC.
РЕДАКТИРОВАТЬ. После игры с жизненным циклом JSF это поведение с локалью не связано с <f:viewAction>
потому что есть подобное поведение также с @PostContruct
, <f:view locale="#{localeBean.locale}">
в запросе (после выбора пользователем локали) выполняется в фазе ответа рендеринга. <f:viewAction>
а также @PostContruct
методы выполняются на этапе вызова приложения. Вот почему логика, которая выполняется в этом методе, не имеет доступа к выбранной пользователем локали.
Решение, которое мы используем, когда нам нужна правильная локаль, заключается в том, чтобы ввести (CDI) localeBean
в другом бобе, который содержит <f:viewAction>
а также @PostContruct
методы, а затем установить локаль с UIViewRoot#setLocale()
от localeBean
в начале этих методов.
Если вы можете использовать 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);
}
}