Home » Java » Core Java » Resource Bundle Tricks and Best Practices

About Markus Eisele

Markus Eisele
Markus is a Developer Advocate at Red Hat and focuses on JBoss Middleware. He is working with Java EE servers from different vendors since more than 14 years and talks about his favorite topics around Java EE on conferences all over the world. He has been a principle consultant and worked with different customers on all kinds of Java EE related applications and solutions. Beside that he has always been a prolific blogger, writer and tech editor for different Java EE related books. He is an active member of the German DOAG e.V. and it's representative on the iJUG e.V. As a Java Champion and former ACE Director he is well known in the community. Follow him on Twitter @myfear.

Resource Bundle Tricks and Best Practices

Today is resource bundle day. This is the most well known mechanism for internationalization (i18n) in Java in general. Working with it should be a breeze. But there are many little questions that come up while getting your hands dirty with it. If you are feeling the same, this post is for you.


The java.util.ResourceBundle defines a standardized way for accessing translations in java. They contain locale-specific resources. Resource bundles belong to families whose members share a common base name, but whose names also have additional components that identify
their locales. Each resource bundle in a family contains the same items, but the items have been translated for the locale represented by that resource bundle. Those are key/value pairs. The keys uniquely identify a locale-specific object in the bundle.

The most basic example uses the following familiy:

If you need to query a bundle in your application you simple call the

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

method and query the returned bundle:


If you are wondering which Locale is going to be used here, you are right. The String constructor implicitly uses Locale.getDefault() to resolve the language. That might not be what you want. So you should ResourceBundle bundle =

ResourceBundle.getBundle("Messages", locale);

You cannot set the locale after you have retrieved the bundle. Every ResourceBundle has one defined locale.

Naming stuff
Some thoughts about naming. Name the bundle properties after their contents. You can go a more general way by simply naming them “Messages” and “Errors” etc. but it also is possible to have a bundle per subsystem or component. Whatever fit’s your needs. Maintaining the contents isn’t easy with lots of entries. So any kind of contextual split makes developers happy. The bundle properties files are equivalent to classes; Name them accordingly. And further on you should find a common system for naming your keys. Depending on the split you have chosen for the property files you might also introduce some kind of subsystem or component namespace with your keys. Page prefixes are also possible. Think about this wisely and play around with it. You are aiming to have least possible dublicates in your keys.

As you have seen, you use the string representation of the bundles a lot. The fact that those are actually file-names (or better class-names) you would be better of with a simple enum which encapsulates everything for you:

public enum ResourceBundles {
    private String bundleName;  

    ResourceBundles(String bundleName) {
        this.bundleName = bundleName;

    public String getBundleName() {
        return bundleName;

    public String toString() {
        return bundleName;

Having this you simply can write

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

Java Server Faces and ResourceBundles
To use resource bundles in your jsf based application you simple have to define them in your faces-config.xml and use the shortcuts in your xhtml files.

 <h:outputLabel value="#{msgs['welcome.general']}" />

JSF takes care of the rest. What about parameter substitution? Think about a key-value pair like the following:

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

You can pass the parameter via the f:param tag:

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

To change the language you have to set a specific locale for your current FacesContext instance. It’s best to do this via a value change listener:

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

Resource Bundles in EJBs
JSF obviously is very easily integrated. What about using those bundles in EJBs? It is basically the same. You have the same mechanisms in place to get hand on the bundle and use it. There is one thing that you should keep in mind. You probably don’t want to always use the default locale. So you have to find a way to pass the locale down from the UI. If you are thinking about @Injecting the MessageBundle via a @Produces annotation you have to think more than one time. Especially if you are working with @Stateless EJBs. Those instances get pooled and you have to pass the Locale to any business method that needs to know about the current Locale. You typically would do this with a parameter object or some kind of user session profile. Don’t add the Locale as method signature all over.

Resource Bundles from the DB
In most of the cases I see you need to pull the keys from a DB. Given the inner workings of the ResourceBundle (one “class” per locale) you end up having to implement the logic in your own ResourceBundle implementation. Most of the examples you find on the web do this by overriding the handleGetObject(String key) method. I don’t like this approach, especially since we have a far better way using the ResourceBundle.Control mechanism. Now you can override the newBundle() method and return your own ResourceBundle implementation. All you have to do is to set your own Control as a parent with your DatabaseResourceBundle:

public DatabaseResourceBundle() {
        FacesContext.getCurrentInstance().getViewRoot().getLocale(), new DBControl()));

The DBControl returns MyResourceBundle which is a ListResourceBundle:

protected class DBControl extends Control {

        public 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;

            protected 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());
                return all;

As you can see, this is backed by an entitymanager and a simple ResourceEntity which has all the fields and NamedQueries necessary for building up the different bundles.

    @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;

By putting the bundles in a private Map<String, String> values = new HashMap<String, String>(); you also have a good way of caching the results after the bundles have been build up for the first time.

This still isn’t the best solution as ResourceBundles have a way of caching. But I might dig into this in more detail later. Until now, this bundle is cached forever (or at least until the next redeployment).

Rewrite as Language Switch
On last thing to mention is that you also could have some fancy add-ons here. If you already have the JSF language switch magic in place it is simple to add ocpsoft’s rewrite to your application. This is a simple way to encode the language in the URLs like this http://yourhost.com/Bundle-Provider-Tricks/en/index.html
All you have to do is to add rewrite to the game by adding two simple dependencies:


Rewrite needs you to add your own ConfigurationProvider which is the central place to hold your rewriting rules. Implement the following:

public class BundleTricksProvider extends HttpConfigurationProvider {

    public Configuration getConfiguration(ServletContext context) {
        return ConfigurationBuilder.begin()
                // Locale Switch

    public int priority() {
        return 10;

Next is to add a file named “org.ocpsoft.rewrite.config.ConfigurationProvider” to your META-INF/services folder and put the fully qualified name of your ConfigurationProvider implementation there. One last thing to tweak is the logic in the LanguageSwitch bean. Rewrite isn’t able to trigger a ValueChangeEvent (as far as I know :)) so you have to add some magic to change the Locale while the setter is called. That’s it .. very easy!

Reference: Resource Bundle Tricks and Best Practices from our JCG partner Markus Eisele at the Enterprise Software Development with Java blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!


1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design


and many more ....



Leave a Reply

Your email address will not be published. Required fields are marked *


Want to take your Java skills to the next level?

Grab our programming books for FREE!

Here are some of the eBooks you will get:

  • Advanced Java Guide
  • Java Design Patterns
  • JMeter Tutorial
  • Java 8 Features Tutorial
  • JUnit Tutorial
  • JSF Programming Cookbook
  • Java Concurrency Essentials