Seam拥有强大的i18n功能 - 它提供了一个内置的区域选择器,用于提供本地化消息包。您可以为不同的页面加载不同的消息包。
Seam内置的消息包使用属性文件来定义资源 - 但如果您想在数据库中存储消息怎么办?例如,您可能想允许管理员通过Web管理面板编辑属性。在这里,我们将介绍基本实体和连接所需的内容 - 您可能还需要为资源添加一些CRUD视图。
实体
我们创建了两个实体,首先是资源包实体,它定义了包名称和它所属的区域
@Entity public class ResourceBundle { @Id @GeneratedValue private Integer id; private String name; private ResourceLocale resourceLocale; @OneToMany(mappedBy="resourceBundle") ¨¨private List<Resource> resources; }
以及嵌入的区域
@Embeddable public class ResourceLocale { @Column(length=2) @Length(max=2) private String language; @Column(length=2) @Length(max=2) private String country; @Column(length=2) @Length(max=2) private String variant; }
以及资源本身,包括键和值
@Entity @NamedQueries({ @NamedQuery( name="keys", query="select r.key from Resource r where r.resourceBundle.name = :bundleName and r.resourceBundle.resourceLocale.language = :language and r.resourceBundle.resourceLocale.country = :country and r.resourceBundle.resourceLocale.variant = :variant"), @NamedQuery( name="value", query="select r.value from Resource r where r.resourceBundle.name = :bundleName and r.resourceBundle.resourceLocale.language = :language and r.resourceBundle.resourceLocale.country = :country and r.resourceBundle.resourceLocale.variant = :variant and r.key = :key") }) public class Resource { @Id @GeneratedValue private Integer id; @Column(name="_key") private String key; @Column(name="_value") private String value; @ManyToOne private ResourceBundle resourceBundle; }
连接
我们需要让Seam使用我们新的资源加载方案
@Name("org.jboss.seam.core.resourceLoader") @BypassInterceptors public class DatabaseResourceLoader extends ResourceLoader { // Redefine how we load a resource bundle public ResourceBundle loadBundle(final String bundleName) { return new ResourceBundle() { public Enumeration<String> getKeys() { Locale locale = org.jboss.seam.core.Locale.instance(); EntityManager entityManager = (EntityManager) Component.getInstance("entityManager"); List resources = entityManager.createNamedQuery("keys") .setParameter("bundleName", bundleName) .setParameter("language", locale.getLanguage()) .setParameter("country", locale.getCountry()) .setParameter("variant", locale.getVariant()) .getResultList(); return Collections.enumeration(resources); } protected Object handleGetObject(String key) { Locale locale = org.jboss.seam.core.Locale.instance(); EntityManager entityManager = (EntityManager) Component.getInstance("entityManager"); try { return entityManager.createNamedQuery("value") .setParameter("bundleName", bundleName) .setParameter("language", locale.getLanguage()) .setParameter("country", locale.getCountry()) .setParameter("variant", locale.getVariant()) .setParameter("key", key) .getSingleResult(); } catch (NoResultException e) { return null; } } }; } }
Java 6
此方法在Java 5上也可以工作 - 但我相信Java 6提供了增强的ResourceBundle支持(但由于没有为Mac提供Java 6,所以我没试过;-))。您可能想调查一下这一点。
缓存
我们在这里没有使用任何缓存 - 每个键的请求都将导致数据库查找。您可以使用JavaMap来缓存资源,当它们被加载时(注意在区域更改时刷新现金 - 使用Seam的事件总线来观察org.jboss.seam.localeSelected),或者您可能可以依赖Hibernate的第二级缓存... 看您了!