http://www.developer.com/

Back to article

Java Internationalization Made Easy


June 24, 2009

Gone are the days when your application would be geared only for local users. Today, every application must support internationalization: being accessible to users across the world and customized to the respective local users. As one of the most widely used programming languages, Java must support this requirement.

This article explains how to support internationalization in Java. Java internationalization is a simple concept, and when it is implemented correctly, long-term management requires only minimal or no code changes—even when requirements such as additional lingual support keep accumulating.

Author Note: The industry abbreviation for internationalization is i18n, which is the letters i and n with a count of the letters between the two (both inclusive).

Building internationalization support isn't very difficult. In fact, once you get acquainted with the implementation methodology, you will find it is one of the easiest Java development tasks that you will perform. You can use it as a best practice to ensure internationalization support in all your future applications.

How i18n Works

The classes ResourceBundle and Locale in the java.util package are the building blocks for internationalization. As an example, consider the following code fragment for an application that displays a thank you message to the user along with a localized message:
import javax.swing.*;
 
public class GenericClass
{
   public static void main(String args[])
   {
      GenericClass genericClass = new GenericClass();
      genericClass.askQ();
 
   }
 
   private void askQ()
   {
      JOptionPane.showMessageDialog(null, 
"The text displayed is specific to locale",
"Thanks to visit", JOptionPane.INFORMATION_MESSAGE); } }

Figure 1 shows the output from the above code.


Figure 1: Thank You Message to the User

Imagine customizing this application to your locale without needing to rewrite it. With Java, you just add a few lines of code and the rest is simple customization.

Take a look at how you would transform the above code using internationalization:

import javax.swing.*;
import java.util.*;
 
public class InternationalizedClass
{
   //This are the stuff that will help you internationalize
   private static String language = "en"; //Initialize with en
    private static String country = "US"; //Initialize with US
   private static Locale currentLocale;
   private static ResourceBundle localMessagesBundle;
 
   public static void main(String args[])
   {
 
      if(args.length == 2)
      {
         language = new String(args[0]);
         country = new String(args[1]);
      }
      currentLocale = new Locale(language, country);
 
      localMessagesBundle = ResourceBundle.getBundle("LocalMessagesBundle",currentLocale);
 
      InternationalizedClass internationalizedClass = new InternationalizedClass();
      internationalizedClass.askQ();
   }
 
   private static void askQ()
   {
      JOptionPane.showMessageDialog(null,
         localMessagesBundle.getString("localeInfo"),
         localMessagesBundle.getString("thanks"),
         JOptionPane.INFORMATION_MESSAGE);
   }
}

When you run the transformed code with the arguments fr and FR, you will see the output shown in Figure 2.


Figure 2: Message Localized to France

If you have used the .properties file in Java, you already know how the preceding example worked. It is no different from the key-value pair mapping of information. There are different .properties files created for every locale; the file contents have the same key but different values. In i18n code, you always refer to the key, and based on the values specified for the locale and the country, you retrieve the correct resources and use them in your application.

The internationalization in the above code is supported by the files LocalMessagesBundle_en_US.properties and LocalMessagesBundle_fr_FR.properties (which you can download). The .properties file name is derived from a combination of the filename, language, and country code. For example, the file name LocalMessagesBundle_en_US.properties is for United States of America, with the language (English) denoted by en and the country code by US. Similarly, LocalMessagesBundle_fr_FR.properties is built for France with fr for French and the country code FR.

Transforming Your App for Different Locales

When you have your i18n infrastructure in place, it's just a matter of minutes to transform your application for any locale you wish. Java supports a set of locales by default. The following snippet helps list the supported locales. The result will vary depending on the platform you use.
import java.util.*;
import java.text.*;
 
public class SupportedLocales{
   public static void main(String args[])
   {
      Locale list[] = DateFormat.getAvailableLocales();
      //Displays language and the country code
      for (int i=0; i< list.length; i++) {
         System.out.println(list[i].toString());
      }
      System.out.println("----------------------------------------------");
      //Displays the Language; more user readable
      for (int i=0; i< list.length; i++) {
         System.out.println(list[i].getDisplayName());
      }
   }
}

When Things Get a Bit More Complicated

So far, you have seen messages that are simple and mostly just a few words. In real-world scenarios, you may know only part of the message that needs to be localized and the remaining values will be computed at runtime or come from some other source.

For example, consider the following message:

I was born at 5:45 on January 25, 1971

The message contains distinct information (in boldface) that are part of a single statement. The code for this would still be:

ResourceBundle messages = ResourceBundle.getBundle("Messages",locale);

The resource bundle Messages.properties would contain the following:

msgRules = I was born at (2,time,short) on (2,date,long)

The following class uses the above resource bundle to display the desired message:

import java.util.*;
import java.text.*;
 
public class MessageFormatter
{
   public static void main(String args[])
   {
      showMessage();
   }
 
   static void showMessage()
   {
      //Defaulting to US
      showMessage("en","US");
   }
 
   static void showMessage(String language, String country)
   {
      Locale locale = new Locale(language,country);
      ResourceBundle messages = ResourceBundle.getBundle("Messages",locale);
 
      Object[] messageArguments =
      {
         new Date(74,6,8,12,5,0)
      };
 
      MessageFormat formatter = new MessageFormat("");
      formatter.setLocale(locale);
 
      formatter.applyPattern(messages.getString("msgRules"));
      String formattedMessage = formatter.format(messageArguments);
 
      System.out.println(formattedMessage);
   }
}

Figure 3 shows the output from the above code.


Figure 3: Birth Date and Time Message

Not only are the i18n techniques described here simple, but they also have the long-term benefit of enabling you to add internationalization support to applications that are already deployed. In effect, you can utilize the concept in almost every aspect of information display that you can imagine.

Code Download

  • Java i18n _src

    For Further Reading

  • "Java Internationalization" (from Sun Developer Network)

    About the Author

    Sridhar M S is a Java developer from Bangalore, India. He holds a master's degree in Computer Science.
  • Sitemap | Contact Us

    Thanks for your registration, follow us on our social networks to keep up-to-date