JSF 中的本地化,如何记住每个会话而不是每个请求/视图的选定语言环境

Localization in JSF, how to remember selected locale per session instead of per request/view

提问人:sergionni 提问时间:1/29/2011 最后编辑:BalusCsergionni 更新时间:1/11/2022 访问量:52791

问:

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"));

问题是应用了 Locale,但仅针对每个请求/视图,而不是针对会话。同一会话中的另一个请求/视图将区域设置重置回默认值。uaru

如何为会话应用区域设置?

JSF 专场 JSF-2 本地化 国际化

评论

0赞 treaz 4/11/2013
我很好奇,这种设置语言的技术多久使用一次?我所有的浏览器都是英文的,作为 i18n 技术,这可靠吗?

答:

89赞 BalusC 1/29/2011 #1

您需要将选定的区域设置存储在会话作用域中,并在 viewroot 中的两个位置设置它:一次是在更改区域设置后立即通过 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>

它假设已经配置如下:#{text}faces-config.xml

<application>
    <resource-bundle>
        <base-name>com.example.i18n.text</base-name>
        <var>text</var>
    </resource-bundle>
</application>

请注意,JSF 的运行不需要,但搜索机器人如何解释您的页面是强制性的。否则,它可能会被标记为重复内容,这对SEO不利。<html lang>

另请参阅:

评论

0赞 Kemoda 8/26/2013
f:view 不应该进入 body 标签吗?
0赞 BalusC 8/26/2013
@Kemoda:您的选择。在幕后,go 的属性是根组件。<f:view>UIViewRoot
0赞 Anatoly 5/21/2014
@BalusC,你能修复你的主要文章中的代码吗?人们一次又一次地“踩耙子”,尤其是没有经验的程序员。谢谢。
0赞 Peter Penzov 10/24/2015
@BalusC 还有一个问题。是否必须编辑 faces-config.xml这样 pastebin.com/uEm9eYVg
1赞 BalusC 7/7/2020
@MestreLion:见答案第1段。这取决于您是重用视图还是重新创建视图。如果重复使用视图,则需要在视图上手动设置它。如果重新创建视图,它将自动从 Bean 中获取它。
4赞 Sebastian 11/14/2011 #2

我看到问题也出在.properties文件名上。 Java 语言环境 us 代码(小写),例如:en_gb 但是自动创建的语言环境(由 Netbeans 创建)是lowercase_uppercase的,即:messages_en_GB.properties 将名称更改为:messages_en_gb.properties 它应该有效 - 如果你尝试了一切

0赞 Xavier Dury 3/8/2016 #3

如果可以在环境中使用 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);
    }
}
3赞 GIRI KUMAR PANEM 4/30/2016 #4

这个组件 f:view 不在您的 JSF 页面中,它将不起作用,它只会显示默认的英语语言。为此 f:view 组件提供 localae 值,然后它就可以正常工作了。我现在遇到了同样的问题,它工作正常。

3赞 Znas Me 12/24/2016 #5

一句小话@BalusC很好的解决方案。如果我们有,在后备 bean 中执行一些方法。从调用到该方法内部可用的区域设置是由用户浏览器或默认应用程序区域设置的区域设置,而不是由用户选择在会话 Bean 上设置的区域设置(当然,如果浏览器区域设置等于用户选择的区域设置,它们可以匹配)。<f:viewAction>FacesContext.getCurrentInstance().getViewRoot().getLocale()

我可以纠正,因为也许我在实施@BalusC提供的解决方案时做错了什么。

编辑。在使用 JSF 生命周期之后,locale 的这种行为与 无关,因为 也有类似的行为。 在请求中(在用户选择语言环境之后)在渲染响应阶段执行。 方法在调用应用程序阶段执行。这就是在此方法中执行的逻辑无权访问用户选择的区域设置的原因。<f:viewAction>@PostContruct<f:view locale="#{localeBean.locale}"><f:viewAction>@PostContruct

当我们需要正确的语言环境时,我们使用的解决方案是将 (CDI) 注入包含 和 方法的其他后备 Bean 中,然后从这些方法的开头设置语言环境。localeBean<f:viewAction>@PostContructUIViewRoot#setLocale()localeBean

评论

0赞 Kukeltje 12/24/2016
这是评论,不是答案!请获得足够的声誉并评论答案。
0赞 Znas Me 12/26/2016
@Kukeltje可能是对的,但是当我获得足够的声誉时,我可能会忘记这个问题。从另一方面和你对 Jsf 的经验来看,你可以验证我在这里提到的是否存在任何问题。f:viewAction