Monday, 20 June 2011

Using Spring, ResourceBundles and Locales

Yesterday’s blog covered the Locale class and talked about determining what locales your JVM supports. Today’s bog moves on to how you make use of this information by loading locale specific property files into your Spring application.

When internationalizing your application, it’s common practice to create a property file containing all your presentation strings for each locale you support together with an additional file for those locales that you don’t support.

Spring and the JDK uses the name of your property files to determine their locale. The file name format is:

<app-prefix>_<locale-suffix>.properties

For example if you wanted to write your application so that it supports UK English and French, then you’d need two separate files. In this example, ‘app-prefix’ is ‘messages’, so you’d have:
  • messages_en_GB.properties
  • messages_fr_FR.properties

The first file would be picked up by locale setting of: Locale.UK and the second by a locale setting of: Locale.FRANCE. If you’re not sure what the ‘locale-suffix’ is for your locale, run the code listed in yesterday’s blog and it’ll give you a complete print out with the ‘locale-suffix’ located in the last column, or check out my results.

The property files you need are pretty straight forward, here’s an extract from the English UK file:

postcode.required=Post code is missing
web.address=My web address is {0}

and this is an extract from the French file:

postcode.required=Code postal est nécessaire
web.address=Mon adresse du site est {0}

I can’t comment on the correctness of the French translation as that was courtesy of Google.

Having created the files above, you now need to store them in a directory accessible to your application that will be copied into the classpath at build time.

The next step is to configure Spring so that it loads the property files using a ResourceBundleMessageSource class. It has one property to set and that’s ‘basename’. This is the path to all the property files in your application and also includes the ‘app-prefix’ value mentioned above. For example, if the property files were located in the root directory of your classpath then in this example, the value would be: ‘messages’. If the property files were in a international/resources directory then the value would be: ‘international/resources/messages’.

Below is an example Spring XML configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
  <!-- This is the path to where the property file is located plus the first part of the file name -->
  <property name="basename">
   <value>messages</value>
  </property>
  </bean>
</beans>

Setting the basename property to ‘messages’ will mean that Spring will load all the property files in one go, differentiating between locales based on the property file name as described above.

Having written the property files and created a Spring XML config file, the next step is to write some test code to demonstrate that everything is working, and this is surprisingly simple as the ApplicationContext will take care of everything...

public class ResourceBundleMain {

 
public static void main(String[] args) {

   
ApplicationContext ctx = new ClassPathXmlApplicationContext(
       
"resource-bundle-example.xml");

    displayMessage
(ctx, Locale.UK);
    displayMessage
(ctx, Locale.FRANCE);

    String url =
"www.captaindebug.com";
    displayMessageWithParams
(ctx, Locale.UK, url);
    displayMessageWithParams
(ctx, Locale.FRANCE, url);

   
// This will throw an exception on a MAC as it can't find locale 'en_US', but works on
    // a Windows PC - this can be fix by using a default property file.
   
displayMessage(ctx, Locale.US);
 
}

 
private static void displayMessage(ApplicationContext ctx, Locale locale) {

   
String message = ctx.getMessage("postcode.required", null, locale);
    System.out.println
("Message is: " + message);
 
}

 
private static void displayMessageWithParams(ApplicationContext ctx, Locale locale,
      String url
) {

   
String message = ctx.getMessage("web.address", new Object[] { url }, locale);
    System.out.println
("Message is: " + message);
 
}
}

Notice that our property files are setup for the UK and France, so when a US locale is specified, an exception is thrown (at least one is on my Mac). The solution to this is to create a default property file simply called ‘messages.properties’ storing it in the same directory as the other property files.

Having configured our property file(s), the next step is to use them. You don’t often use strings created for your presentation layer in your Java code (an exception being during validation with the ValidationUtils class) so the code above is somewhat redundant. To remedy the situation, my next blog demonstrates how to use your property file strings with a JSP...

No comments: