使用从数据库加载的ResourceBundle条目在JSF中进行国际化

前端之家收集整理的这篇文章主要介绍了使用从数据库加载的ResourceBundle条目在JSF中进行国际化前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在使用JPA / EJB / JSF开发 Java EE6项目,我在为实体设计多语言支持方面遇到了一些麻烦.有三个相关实体:

语言(有id)
能力(有id)
CompetenceName(具有能力参考,语言参考和字符串)

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 API可以完全控制加载和填充包.

了解这些事实后,应该可以使用自定义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}" />
原文链接:https://www.f2er.com/mssql/77226.html

猜你在找的MsSQL相关文章