JSF1.2 中实现国际化
程序员文章站
2022-05-24 09:48:29
...
JSF的<f:view>标签中可以通过locale属性来指定语言和区域信息来实现国际化,如:<f:view locale="#{indexBean.locale}">。
在实践中发现这个属性不起作用,后台IndexBean的locale已经改变,但是前台界面显示的语言没有跟这变化。
简单的跟踪一下代码发现大致的原因如下:
以index.jsp为例来说明:
1、第一次打开index.jsp页面,系统创建一个UIViewRoot对象,根据#{indexBean.locale}(默认为zh_CN)设置UIViewRoot对象locale值,这种情况下页面显示是正确。
2、在页面通过按钮或者选择列表改变#{indexBean.locale}的值为"en_US",按照设想页面显示的语言应该为英文,但实际情况还是中文。
跟踪代码发现问题在UIComponentClassicTagBase.java的findComponent()方法中
//获取UIViewRoot对象
parentComponent = context.getViewRoot();
if (null == parentComponent.getAttributes().get("javax.faces.webapp.CURRENT_VIEW_ROOT"))
{
try
{
//这个方法里面会用#{indexBean.locale}的值来设置UIViewRoot对象locale值
//第一次打开index.jsp时,UIViewRoot对象是新建的所以parentComponent.getAttributes().get("javax.faces.webapp.CURRENT_VIEW_ROOT")==null
//执行此方法。当通过通过触发页面上的按钮或者下拉列表重新绘制index.jsp时,由于JSF会保存的组件的状态而且可以恢复,此时的 UIViewRoot对象还是上次
//创建的对象,所以 parentComponent.getAttributes().get("javax.faces.webapp.CURRENT_VIEW_ROOT")==null 这个条件不满足,因此也不会执行此方法。
setProperties(parentComponent);
}
catch (FacesException e) {
if (e.getCause() instanceof JspException) {
throw ((JspException)e.getCause());
}
throw e;
}
if (null != this.id) {
parentComponent.setId(this.id);
}
else {
assert (null != getFacesJspId());
parentComponent.setId(getFacesJspId());
}
parentComponent.getAttributes().put("javax.faces.webapp.CURRENT_VIEW_ROOT", "javax.faces.webapp.CURRENT_VIEW_ROOT");
this.created = true;
}
else if (hasBinding()) {
try {
setProperties(parentComponent);
}
catch (FacesException e) {
if (e.getCause() instanceof JspException) {
throw ((JspException)e.getCause());
}
throw e;
}
}
3、这个问题在MyFaces中没有发现,不知道是参考实现中的BUG还是使用方法的错误。
4、一个替代的解决方法是加入一个PhaseListener,然后在PhaseId.RENDER_RESPONSE之前直接调用UIViewRoot对象的setLocale方法来改变语言和区域信息。
FacesContext.getCurrentInstance().getViewRoot().setLocale(new Locale("zh","CN"));
下一篇: Spring之AOP面向切面编程