2

I have a faces-config.xml file with some resource bundles declared, like this:

<faces-config xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
              version="2.0">
    <application>
        <locale-config>
            <default-locale>en</default-locale>
            <supported-locale>de</supported-locale>
            <supported-locale>es</supported-locale>
            <supported-locale>pt</supported-locale>
            <supported-locale>zh</supported-locale>
        </locale-config>
        <resource-bundle>
            <base-name>messages.Messages</base-name>
            <var>bundle</var>
        </resource-bundle>
        <resource-bundle>
            <base-name>countries.Countries</base-name>
            <var>countryBundle</var>
        </resource-bundle>
    </application>
</faces-config>

These resource bundles are registered and can be used in any .xhtml file, but is there any way to register these resource bundles programmatically? I mean by the use of dynamic code instead of a xml declaration.

Joe Almore
  • 4,036
  • 9
  • 52
  • 77

2 Answers2

2

Here's a simplified version of what I'm doing using CDI:

@ApplicationScoped
public class BundleProducer {
    @Produce @RequestScoped @Named
    public ResourceBundle getMsgBundle() {
        Locale userLocale = Faces.getLocale();
        return ResourceBundle.getBundle("messages", userLocale);
    }
}

Note the use of omnifaces' getLocale() to avoid a ton of boilerplace code (for a less sane version, you can substitute FacesContext.getCurrentInstance().getViewRoot().getLocale() like in the tutorial you linked to).

This will cause the CDI framework to call getMsgBundle once each request if it needs to access to msgBundle thanks to the @Named annotation. In this simple case, I'm relying on the ResourceBundle internal caching and lookup mechanisms to produce my bundle efficiently. You can execute any logic you like here (eg, load stuff from the enclosing BundleProducer) as long as you return a ResourceBundle from the method (you're not allowed to return null).

Repeat as you like with more methods producing different bundles.

Not sure if I got what you were after, so just comment if you need more clarification.


For easier handling of FacesMessage stuff, I'd recommend having a look at omnifaces' Messages utility class. I use something like this to be able to optionally give bundle keys as message strings:

@Singleton
@Startup
public class MessageResolverInit {
    @PostConstruct
    public void initMessageResolver() {
        Messages.setResolver(new Messages.Resolver() {
            @Override
            public String getMessage(String message, Object... params) {
                Locale userLocale = Faces.getLocale();
                ResourceBundle b = ResourceBundle.getBundle("msgs", userLocale);
                if (b.containsKey(message)) {
                    return MessageFormat.format(b.getString(message), params);
                }
                return message;
            }
        });
    }

Note that I use b as a variable name only for demo purposes. Usage goes like this:

Messages.addGlobalError("my_msg_key", param1);
Messages.addGlobalInfo("I'm a standalone message");
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
mabi
  • 5,279
  • 2
  • 43
  • 78
  • I see. Interesting. So, if I use this code then I won't have to include the bundles in `faces-config.xml`, right? – Joe Almore Apr 03 '14 at 14:01
  • @JoeAlmore Depends. AFAIK those entries are also used when translating messages, so you need to see that in addition to the code way you posted. As it is, this production is only for use in facelets. – mabi Apr 03 '14 at 14:28
0

Here is the answer from Oracle documentation: Using FacesMessage to Create a Message

Joe Almore
  • 4,036
  • 9
  • 52
  • 77