JSF 2 本地化(托管 bean)
我有一个用于本地化的属性文件:
foo=Bar
title=Widget Application
这在 faces-config 中作为 resource-bundle
绑定:
<resource-bundle>
<base-name>com.example.messages.messages</base-name>
<var>msgs</var>
</resource-bundle>
我可以使用 EL 在 Facelets 视图中很好地访问它:
<title>#{msgs.title}</title>
但是,如果有类似的情况SQLExceptions,我需要能够从托管 bean 写入消息。这一切也都有效:
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "There was an error saving this widget.", null);
FacesContext.getCurrentInstance().addMessage(null, message);
问题是:我希望这些消息来自属性文件,以便它们也可以根据区域设置进行更改。有没有一种简单的方法可以使用注入来访问属性文件?
I have a properties file for localization:
foo=Bar
title=Widget Application
This is tied in as a resource-bundle
in the faces-config:
<resource-bundle>
<base-name>com.example.messages.messages</base-name>
<var>msgs</var>
</resource-bundle>
I can access this just fine in the facelets view using EL:
<title>#{msgs.title}</title>
However, if there are things like SQLExceptions, I need to be able to write messages from the managed bean. This is all working also:
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "There was an error saving this widget.", null);
FacesContext.getCurrentInstance().addMessage(null, message);
Here is the issue: I want to have those messages come from the properties file so that they, too, can be changed based on the locale. Is there an easy way to access the properties file using injection?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我问了一个非常相关的问题:
如何注入非带有 Weld 的可序列化类(如 java.util.ResourceBundle)
以及 Seam 论坛内部:
http://seamframework.org/Community/HowToCreateAnInjectableResourcebundleWithWeld
总结一下:
我实现了一个带有 3 个 Producer 的可注入 ResourceBundle。
首先您需要一个 FacesContextProducer。我从 Seam 3 Alpha 源中获取了一个。
然后您需要一个 LocaleProducer,它使用 FacesContextProducer。我也从 Seam 3 Alpha 那里得到了它。
现在您已经拥有了创建 ResourceBundleProducer 的一切,它看起来像这样:
现在您可以将 ResourceBundle @Inject 到您的 bean 中。请注意,它必须被注入到瞬态属性中,否则您将收到一个异常,抱怨 ResourceBundle 不可序列化。
I asked a quite related question on SO:
How to inject a non-serializable class (like java.util.ResourceBundle) with Weld
And inside the Seam Forum:
http://seamframework.org/Community/HowToCreateAnInjectableResourcebundleWithWeld
To summarize:
I realized an injectable ResourceBundle with 3 Producers.
First you need a FacesContextProducer. I took the one from the Seam 3 Alpha sources.
Then you need a LocaleProducer, which uses the FacesContextProducer. I also took it from Seam 3 Alpha.
Now you have everything to create a ResourceBundleProducer, which can look like this:
Now you can @Inject the ResourceBundle into your beans. Pay attention that it has to be injected into a transient attribute, otherwise you'll get an exception complaining that ResourceBundle is not serializable.
使用MyFaces CODI的消息模块更容易!
It's easier to use e.g. the message module of MyFaces CODI!
您可以单独使用 JSF 来完成此操作。
首先在支持 bean 上定义托管属性。在 JSF 配置中,您可以将托管属性的值设置为引用资源包的 EL 表达式。
我使用 Tomcat 6 完成了如下操作。唯一需要注意的是,您无法从支持 bean 的构造函数访问该值,因为 JSF 尚未初始化它。如果在 bean 生命周期的早期需要该值,请在初始化方法上使用 @PostConstruct 。
这样做的优点是可以减少您的支持 bean 方法对表示技术的依赖,因此应该更容易测试。它还将您的代码与诸如捆绑包名称之类的细节分离。
当用户在会话中更改区域设置时,使用 Mojarra 2.0.4-b09 进行的一些测试确实显示出轻微的不一致。页内 EL 表达式使用新的语言环境,但没有为支持 bean 提供新的 ResourceBundle 引用。为了保持一致,您可以在 EL 表达式中使用 bean 属性值,例如使用
#{backingBean.messages.greeting}
代替#{msgs.greeting}
。然后页面 EL 和支持 bean 将始终使用会话开始时处于活动状态的语言环境。如果用户必须在会话中切换语言环境并获取新消息,您可以尝试创建一个请求范围的 bean 并为其提供对会话 bean 和资源包的引用。You can do this with JSF alone.
Start by defining a managed property on your backing bean. In the JSF configuration, you can set the managed property's value to an EL expression that references your resource bundle.
I've done something like the following using Tomcat 6. The only caveat is that you can't access this value from your backing bean's constructor, since JSF will not yet have initialized it. Use
@PostConstruct
on an initialization method if the value is needed early in the bean's lifecycle.This has the advantage of making your backing bean methods less dependent on the presentation technology, so it should be easier to test. It also decouples your code from details like the name given to the bundle.
Some testing using Mojarra 2.0.4-b09 does show a small inconsistency when a user changes locale mid-session. In-page EL expressions use the new locale but the backing bean isn't given the new ResourceBundle reference. To make it consistent you could use the bean property value in EL expressions, such as using
#{backingBean.messages.greeting}
in place of#{msgs.greeting}
. Then page EL and the backing bean would always use the locale that was active when the session began. If users had to switch locales mid-session and get the new messages, you could try making a request-scoped bean and give it references to both the session bean and resource bundle.以下是有关如何执行此操作的示例:
http://www.laliluna.de/articles/ javaserver-faces-message-resource-bundle-tutorial.html
您想查看
ResourceBundle.getBundle()
部分。问候,
拉尔斯
Here's an example on how to do this:
http://www.laliluna.de/articles/javaserver-faces-message-resource-bundle-tutorial.html
You want to have a look at the
ResourceBundle.getBundle()
part.Greetings,
Lars
这是一个老问题,但我添加了另一种方法来做到这一点。我正在寻找其他东西并遇到了这个。这里的方法似乎都很复杂,但对我来说并不那么困难。玩闪光,因为如果你问我的话,它很漂亮。
给定一个文件:
在文件内部:
我创建一个“getBundle()”方法,因为我喜欢捕获运行时并添加有意义的消息,这样我就会了解它来自哪里。这并不难,如果您出于某种原因突发奇想使用属性文件并且没有正确更新所有内容,那么这会有所帮助。我有时将其设为私有,因为它有时是类中的辅助方法(对我来说)。这可以防止 try catch 杂乱地影响有意义的代码。
如果您对组织有其他想法,则使用文件的完整路径可以将其放置在默认位置/目录之外的其他位置。
This is an old question but I'm adding another way to do this. I was looking for something else and ran across this. The methods here all seemed convoluted for something that doesn't strike me as all the that difficult. Playing with glitter because it's pretty if you ask me.
Given a file:
Inside the file:
I create a "getBundle()" method since I like to catch the runtime and add a meaningful message so I will understand where it is coming from. Not hard and can help if you get the whim to play with the properties files for some reason and don't update everything correctly. I sometimes make this private as it is sometimes a helper method within a class (for me). This keeps the try catch clutter out of the meaningful code.
Using the full path to the file allows you to put it somewhere other than the default location/directory if you have other ideas on organization.