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