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的第二级缓存... 看您了!