使用从数据库加载的ResourceBundle条目在JSF中进行国际化
|
我正在使用JPA / EJB / JSF开发 Java EE6项目,我在为实体设计多语言支持方面遇到了一些麻烦.有三个相关实体: 语言(有id) Competence对使用Map实现的CompetenceName有一对多的引用,包含一个对象,每个语言都有一个Competence的名称.请注意,权限是动态创建的,因此它们的名称不能存在于资源包中. 在网页上列出Competences时,我希望它们以当前登录用户的语言显示,它存储在Session Scoped Managed Bean中. 如果没有破坏良好的MVC设计,有没有什么好方法可以做到这一点?我的第一个想法是通过FacesContext直接从Competence实体中的“getName”方法获取会话范围bean,并在CompetenceNames的地图中查找如下: public class Competence
{
...
@MapKey(name="language")
@OneToMany(mappedBy="competence",cascade=CascadeType.ALL,orphanRemoval=true)
private Map<Language,CompetenceName> competenceNames;
public String getName(String controller){
FacesContext context = FacesContext.getCurrentInstance();
ELResolver resolver = context.getApplication().getELResolver();
SessionController sc = (SessionController)resolver.getValue(context.getELContext(),null,"sessionController");
Language language = sc.getLoggedInUser().getLanguage();
if(competenceNames.get(language) != null)
return competenceNames.get(language).getName();
else
return "resource missing";
}
这个解决方案感觉非常粗糙,因为实体依赖于Controller层,并且每次我想要它的名字时都必须获取会话控制器.一个更符合MVC的解决方案是采用一个Language参数,但这意味着来自JSF的每一次调用都必须包含从会话作用域托管bean中获取的语言,这也不是一个好的解决方案. 有没有人对这个问题有任何想法或设计模式? 解决方法国际化/本地化最好完全在视图方面完成.该模型不应该意识到这一点.在JSF中,< resource-bundle> faces-config.xml中的条目和< f:loadBundle>在XHTML中也可以指向一个完整的ResourceBundle类而不是.properties文件的basename.在Java SE 6中,有一个新的 了解这些事实后,应该可以使用自定义ResourceBundle和Control从DB加载捆绑消息.这是一个启动示例: public class CompetenceBundle extends ResourceBundle {
protected static final String BASE_NAME = "Competence.messages"; // Can be name of @NamedQuery
protected static final Control DB_CONTROL = new DBControl();
private Map<String,String> messages;
public CompetenceBundle() {
setParent(ResourceBundle.getBundle(BASE_NAME,FacesContext.getCurrentInstance().getViewRoot().getLocale(),DB_CONTROL));
}
protected CompetenceBundle(Map<String,String> messages) {
this.messages = messages;
}
@Override
protected Object handleGetObject(String key) {
return messages != null ? messages.get(key) : parent.getObject(key);
}
@Override
public Enumeration<String> getKeys() {
return messages != null ? Collections.enumeration(messages.keySet()) : parent.getKeys();
}
protected static class DBControl extends Control {
@Override
public ResourceBundle newBundle
(String baseName,Locale locale,String format,ClassLoader loader,boolean reload)
throws IllegalAccessException,InstantiationException,IOException
{
String language = locale.getLanguage();
Map<String,String> messages = getItSomehow(baseName,language); // Do your JPA thing. The baseName can be used as @NamedQuery name.
return new CompetenceBundle(messages);
}
}
}
这样你就可以在faces-config.xml中声明如下: <resource-bundle>
<base-name>com.example.i18n.CompetenceBundle</base-name>
<var>competenceBundle</var>
</resource-bundle>
或者在Facelet中如下: <f:loadBundle basename="com.example.i18n.CompetenceBundle" var="competenceBundle" /> 无论哪种方式,您都可以通常的方式使用它: <h:outputText value="#{competenceBundle.name}" /> (编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
