资源包技巧和最佳实践

今天是资源捆绑日。 通常,这是Java中最著名的国际化机制(i18n)。 使用它应该很容易。 但是,在弄脏手时会出现许多小问题。 如果您有相同的想法,则此文章适合您。

基本

java.util.ResourceBundle定义了用于访问Java中翻译的标准化方法。 它们包含特定于语言环境的资源。 资源束属于其成员具有相同基本名称的族,但是其名称还具有标识
他们的语言环境。 族中的每个资源束都包含相同的项目,但是这些项目已针对该资源束所代表的语言环境进行了翻译。 这些是键/值对。 这些键唯一地标识捆绑软件中特定于语言环境的对象。

最基本的示例使用以下知识:
Messages.properties
Messages_de.properties Messages_en.properties

如果您需要在应用程序中查询包,则只需调用

ResourceBundle bundle = ResourceBundle.getBundle("Messages");

方法并查询返回的包:

bundle.getString("welcome.message");

如果您想在此处使用哪种语言环境,那是对的。 String构造函数隐式使用Locale.getDefault()解析语言。 那可能不是您想要的。 所以你应该ResourceBundle bundle =

ResourceBundle.getBundle("Messages", locale);

检索捆绑软件后,您将无法设置语言环境。 每个ResourceBundle都有一个定义的语言环境。

命名的东西
 
关于命名的一些想法。 用其内容命名捆绑属性。 您可以通过简单地将它们命名为“消息”和“错误”等来采用更通用的方式。但是,每个子系统或组件也可以具有捆绑软件。 无论您需要什么。 要维护内容,要输入大量条目并不容易。 因此,任何类型的上下文拆分都会使开发人员感到高兴。 捆绑软件属性文件等效于类。 相应地命名。 进一步,您应该找到一个用于命名密钥的通用系统。 根据为属性文件选择的拆分,还可能在密钥中引入某种子系统或组件名称空间。 页面前缀也是可能的。 明智地考虑一下,并加以解决。 您的目标是尽量减少密钥重复。

封装
 
如您所见,您经常使用包的字符串表示形式。 这些实际上是文件名(或更好的类名),您可以通过一个简单的枚举来更好地封装所有内容:

public enum ResourceBundles {MESSAGES("Messages"),ERRORS("Errors");private String bundleName;  ResourceBundles(String bundleName) {this.bundleName = bundleName;}public String getBundleName() {return bundleName;}@Overridepublic String toString() {return bundleName;}
}

有了这个你就可以写

ResourceBundle bundle = ResourceBundle.getBundle(MESSAGES.getBundleName());

Java Server Faces和ResourceBundle
 
要在基于jsf的应用程序中使用资源包,您只需在faces-config.xml中定义它们,并使用xhtml文件中的快捷方式。

<resource-bundle>
<base-name>Messages</base-name>
<var>msgs</var>
<h:outputLabel value="#{msgs['welcome.general']}" />

JSF负责其余的工作。 那么参数替换呢? 考虑如下的键值对:

welcome.name=Hi {0}! How are you?

您可以通过f:param标签传递参数:

<h:outputFormat value="#{msgs['welcome.name']}"><f:param value="Markus" /></h:outputFormat>

要更改语言,您必须为当前的FacesContext实例设置特定的语言环境。 最好通过值更改侦听器执行此操作:

public void countryLocaleCodeChanged(ValueChangeEvent e) {String newLocaleValue = e.getNewValue().toString();//loop country map to compare the locale codefor (Map.Entry<String, Object> entry : countries.entrySet()) {if (entry.getValue().toString().equals(newLocaleValue)) {FacesContext.getCurrentInstance().getViewRoot().setLocale((Locale) entry.getValue());}}}

EJB中的资源包
 
JSF显然很容易集成。 在EJB中使用这些捆绑包怎么办? 基本上是一样的。 您可以使用相同的机制来使用和使用捆绑包。 您应该记住一件事。 您可能不想始终使用默认语言环境。 因此,您必须找到一种从UI向下传递语言环境的方法。 如果您想通过@Produces批注@Injecting MessageBundle,则必须考虑多次。 尤其是在使用@Stateless EJB时。 这些实例将合并,您必须将语言环境传递给需要了解当前语言环境的任何业务方法。 通常,您可以使用参数对象或某种用户会话配置文件来执行此操作。 不要将语言环境全部添加为方法签名。

来自数据库的资源包
 
在大多数情况下,我看到您需要从数据库中提取密钥。 鉴于ResourceBundle的内部工作原理(每个语言环境一个“类”),您最终不得不在自己的ResourceBundle实现中实现逻辑。 您在网络上找到的大多数示例都是通过重写handleGetObject(String key)方法来实现的。 我不喜欢这种方法,尤其是因为我们有一个更好的方法来使用ResourceBundle.Control机制。 现在,您可以覆盖newBundle()方法并返回自己的ResourceBundle实现。 您所要做的就是将自己的Control设置为DatabaseResourceBundle的父级:

public DatabaseResourceBundle() {setParent(ResourceBundle.getBundle(BUNDLE_NAME,FacesContext.getCurrentInstance().getViewRoot().getLocale(), new DBControl()));}

DBControl返回MyResourceBundle,它是一个ListResourceBundle:

protected class DBControl extends Control {@Overridepublic ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload)throws IllegalAccessException, InstantiationException, IOException {return new MyResources(locale);}/*** A simple ListResourceBundle*/protected class MyResources extends ListResourceBundle {private Locale locale;/*** ResourceBundle constructor with locale** @param locale*/public MyResources(Locale locale) {this.locale = locale;}@Overrideprotected Object[][] getContents() {TypedQuery<ResourceEntity> query = _entityManager.createNamedQuery("ResourceEntity.findForLocale", ResourceEntity.class);query.setParameter("locale", locale);List<ResourceEntity> resources = query.getResultList();Object[][] all = new Object[resources.size()][2];int i = 0;for (Iterator<ResourceEntity> it = resources.iterator(); it.hasNext();) {ResourceEntity resource = it.next();all[i] = new Object[]{resource.getKey(), resource.getValue()};values.put(resource.getKey(), resource.getValue());i++;}return all;}}}

如您所见,这由一个entitymanager和一个简单的ResourceEntity作为后盾,该ResourceEntity具有构建不同捆绑软件所需的所有字段和NamedQueries。

@Id@GeneratedValue(strategy = GenerationType.AUTO)private Long id;@Column(name = "i18n_key")private String key;@Column(name = "i18n_value")private String value;@Column(name = "i18n_locale")private Locale locale;

通过将捆绑包放入私有Map <String,String>值= new HashMap <String,String>(); 在首次构建捆绑包之后,您还可以使用一种很好的方法来缓存结果。

这仍然不是最好的解决方案,因为ResourceBundles具有缓存的方式。 但我稍后可能会更详细地探讨这一点。 到现在为止,此捆绑包将被永久缓存(或至少直到下一次重新部署为止)。

改写为语言切换
 
最后要提到的是,您还可以在此处添加一些精美的插件。 如果您已经有了JSF语言切换魔术,则可以轻松地将ocpsoft的重写添加到您的应用程序中。 这是一种将网址中的语言编码的简单方法,例如http://yourhost.com/Bundle-Provider-Tricks/en/index.html 您要做的就是通过添加两个简单的依赖关系来向游戏添加重写:

<dependency><groupId>org.ocpsoft.rewrite</groupId><artifactId>rewrite-servlet</artifactId><version>1.1.0.Final</version></dependency><dependency><groupId>org.ocpsoft.rewrite</groupId><artifactId>rewrite-integration-faces</artifactId><version>1.1.0.Final</version></dependency>

重写需要您添加自己的ConfigurationProvider,这是保存重写规则的中心位置。 执行以下操作:

public class BundleTricksProvider extends HttpConfigurationProvider {@Overridepublic Configuration getConfiguration(ServletContext context) {return ConfigurationBuilder.begin()// Locale Switch.addRule(Join.path("/{locale}/{page}.html").to("/{page}.xhtml").where("page").matches(".*").where("locale").bindsTo(PhaseBinding.to(El.property("#{languageSwitch.localeCode}")).after(PhaseId.RESTORE_VIEW)));}@Overridepublic int priority() {return 10;}
}

接下来是将一个名为“ org.ocpsoft.rewrite.config.ConfigurationProvider”的文件添加到您的META-INF / services文件夹,并在其中放置您的ConfigurationProvider实现的标准名称。 最后要调整的是LanguageSwitch bean中的逻辑。 重写不能触发ValueChangeEvent(据我所知:)),因此您必须在调用setter时添加一些魔术来更改Locale。 就是这样..非常简单!

参考:来自JCG合作伙伴 Markus Eisele的Resource Bundle技巧和最佳实践 ,位于Enterprise Software Development with Java博客上。


翻译自: https://www.javacodegeeks.com/2012/09/resource-bundle-tricks-and-best.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/371351.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

springMvc-文件上传

赶时间&#xff0c;又在写垃圾博客&#xff0c;在心里给自己一耳巴 1.单文件上传 2.多文件上传 代码&#xff1a; 页面&#xff1a; <!DOCTYPE html><html><head><meta charset"UTF-8"><title>Insert title here</title></he…

c cuda 指定gpu_GPU并行编程:熟练使用CUDA C语言

【IT168 专稿】一个大任务通常可能被分解成许多可以一起处理的小任务&#xff0c;以便创建一个解决方案&#xff0c;这和粉刷房子的道理是一样的&#xff0c;在粉刷之前&#xff0c;假设你需要买5公升油漆和5把刷子&#xff0c;你可以自己一个人干完采购和粉刷的活&#xff0c;…

js中使用0 “” null undefined {}需要注意

注意&#xff1a;在js中0为空&#xff08;false&#xff09; &#xff0c;代表空的还有“”&#xff0c;null &#xff0c;undefined&#xff1b; 如果做判断if(&#xff01;上面的四种值)&#xff1b;返回均为false console.log(!null);// true console.log(!0);//true consol…

PhpStorm 10.0.3破解版下载

汉化破解版软件下载&#xff1a; http://pan.baidu.com/s/1geNO24r 密码: d5ci 这个汉化破解软件解决了大纲视图里空白的问题。 先安装腾讯电脑管家&#xff0c;然后安装这个软件&#xff0c;安装到最后提示有个文件有病毒已删除&#xff0c;点确定后正常使用。转载于:https://…

Jenkins:部署JEE工件

随着持续集成和持续交付的出现 &#xff0c;我们的构建被分为不同的步骤&#xff0c;以创建部署管道。 这些步骤中的一些步骤可以是例如编译和运行快速测试&#xff0c;运行慢速测试&#xff0c;运行自动验收测试或发布应用程序等。 部署流程的最后一步意味着将我们的产品&…

seafile 部署_Seafile开启webdav及读写性能测试

为什么要在seafile搞webdavSeafile 一直是一款可靠的文件同步web应用&#xff0c;经过个人测试&#xff0c;同一台机器上&#xff0c;seafile在传输文件时的速度比nextcloud要快&#xff08;可能也与php的设置有关系&#xff09;&#xff0c;这是seafile的优势。但是&#xff0…

Python--校园网爬虫记

查成绩&#xff0c;算分数&#xff0c;每年的综合测评都是个固定的过程&#xff0c;作为软件开发者&#xff0c;这些过程当然可以交给代码去做&#xff0c;通过脚本进行网络请求获取数据&#xff0c;然后直接进行计算得到基础分直接填表就好了&#xff0c;查成绩再手动计算既容…

Spring–添加SpringMVC –第1部分

欢迎来到本教程的第四部分。 在这一部分中&#xff0c;我们将使用Spring MVC编写控制器和视图&#xff0c;并考虑我们的REST模型。 我们必须做的第一件事&#xff0c;就是根据目前的情况制作一个Web应用程序。 我们将web / WEB-INF文件夹添加到我们的项目根目录。 在WEB-INF内创…

[Linux] 权限与指令间的关系

我们知道权限对于使用者帐号来说是非常重要的&#xff0c;因为他可以限制使用者能不能读取/创建/删除/修改文件或目录&#xff01; 在这一章我们介绍了很多文件系统的管理指令&#xff0c;第五章则介绍了很多文件权限的意义。在这个小节当中&#xff0c; 我们就将这两者结合起来…

access month函数用法_学会了这7个EXCEL日期函数技巧,老板再让你加班,你找我!...

日期函数&#xff0c;常用年月日&#xff0c;时分秒&#xff0c;星期&#xff0c;季度&#xff0c;求差值等&#xff0c;学会以下几个函数&#xff0c;老板再让你加班&#xff0c;你找我&#xff01;1、记录当前时间(不随系统时间变化)NOW()函数与数据有效性结合&#xff0c;记…

css样式表的选择器与分类

css 样式表的作用&#xff1a; 主要用于结构,样式与行为,CSS主要的作用就是美化网页的一个语言,它的特点: 1.结构与样式分离的方式,便于后期维护与改版; 2.样式定义精确到像素的级别; css样式表的结构&#xff1a;CSS 称为层叠样式表 用于给网页设置各种样式 css样式的语法由3部…

Spring 3.1缓存和@Cacheable

缓存在软件领域已经存在很长时间了。 它们是那些真正有用的东西之一&#xff0c;一旦您开始使用它们&#xff0c;您会想知道如果没有它们&#xff0c;您是如何相处的&#xff0c;所以似乎让Spring的家伙们只是在版本中向Spring核心添加缓存实现有点奇怪。 3.1。 我猜想以前没有…

pytorchyolov4训练_使用pytorch-yolov5 訓練自己的數據集-2020.6.15

make yolov5 pytorch train datasets训练所需环境 python3.5, pytorch1.3, torchvision 0.4.1 , tensorboard 1.14.0 , tensorflow-gpu1.14.0本例制作yolov5数据集 并进行数据训练从VOC数据集转为训练所需的coco数据集代码有待改进包含文件夹voc2coco/(Annotations/ JPEGImages…

meta 的作用 搜集

Meta标签中的format-detection属性及含义 format-detection翻译成中文的意思是“格式检测”&#xff0c;顾名思义&#xff0c;它是用来检测html里的一些格式的&#xff0c;那关于meta的format-detection属性主要是有以下几个设置&#xff1a;<meta name"format-detecti…

Web服务安全性和SOA路线图的人为维度

在大多数非平凡的SOA环境中&#xff0c;很难跟踪系统之间不断发展的集成&#xff0c;除非有明确的发布和查找适当信息的方法。 概述IT环境&#xff0c;定义当前或将要连接的内容&#xff0c;是维护环境的先决条件。 缺少这种情况通常会导致“面向意大利面条的环境”的感觉&…

pccad自定义图框_(PCCAD自定义标题栏详细方法.doc

PCCAD2011自定义标题栏详细方法下面以图3-1为例说明标题栏的自定义过程。图3-11&#xff0e;新建文件(用New 命令)。2&#xff0e;用绘图和文字中的相关命令设计出图3-1所示的图形。其中在使用中不变的内容&#xff0c;如厂名等均用“文字”命令标出&#xff0c;而需临时填充的…

ThinkPHP 3.2.x 集成极光推送指北

3.2版本已经过了维护生命周期&#xff0c;官方已经不再维护&#xff0c;请及时更新至5.0版本 —— ThinkPHP 官方仓库 以上&#xff0c;如果有条件&#xff0c;请关闭这个页面&#xff0c;然后升级至 ThinkPHP 5&#xff0c;如果由于各种各样的原因无法升级至 TP 5 &#xff0c…

Java:选择正确的集合

这是在应用程序中选择Set &#xff0c; List或Map的正确实现的快速指南。 最好的通用或“主要”实现可能是ArrayList&#xff0c;LinkedHashMap和LinkedHashSet。 它们的整体性能更好&#xff0c;除非您需要其他实现提供的特殊功能&#xff0c;否则应使用它们。 该特殊功能通常…

Java多线程——不变性与安全发布

1、不变性 某个对象在被创建后其状态就不能被修改&#xff0c;那么这个对象就称为不可变对象&#xff0c;不可变对象一定是线程安全的。不可变对象很简单。他们只有一种状态&#xff0c;并且该状态由构造函数来控制。 当满足以下条件时&#xff0c;对象才是不可变的&#xff1a…

中tr不能显示字符_垃圾文本识别中基本操作指南和错误总结,第三部分

创建模型需要用到机器学习的库&#xff0c;所以我们先下载sklearn库sklearn库下载完成后再输入库文件&#xff0c;就可以完美运行。然后就是划分测试集和训练集&#xff0c;需要注意的是&#xff0c;在从数据处理函数中导入数据时&#xff0c;足足运行了有将近30多秒&#xff0…