Search code examples
javapropertiesinternationalizationresourcebundle

Advantages and Disadvantages of ways to Internationalize a Java App (Resource Bundle)


I've got two ways to internationalize my app, i know that there a more ways to do so via Resource Bundle(if you consider there's a better way to do so explain me please), am a bit new using Resource Bundle that's why this doubt merge.

These are the ways in which i do it:

1st - ListResourceBundle

    import java.util.*;
//http://docs.oracle.com/javase/tutorial/i18n/resbundle/list.html
public class ListDemo {

   static void displayValues(Locale currentLocale) {

      ResourceBundle stats = ResourceBundle.getBundle("StatsBundle",currentLocale);

      Integer gdp = (Integer)stats.getObject("GDP");
      System.out.println("GDP = " + gdp.toString());
      Integer pop = (Integer)stats.getObject("Population");
      System.out.println("Population = " + pop.toString());
      Double lit = (Double)stats.getObject("Literacy");
      System.out.println("Literacy = " + lit.toString());

   } // displayValues

   static public void main(String[] args) {

      Locale[] supportedLocales = {
         //new Locale("en","CA"),
         new Locale("ja","JP")
         //new Locale("fr","FR")
      };

      for (int i = 0; i < supportedLocales.length; i ++) {
         System.out.println("Locale = " + supportedLocales[i]);
         displayValues(supportedLocales[i]);
         System.out.println();
      }

   } // main

} // class

Here's the class that contains the data

    import java.util.*;
public class StatsBundle_ja_JP extends ListResourceBundle {

    public StatsBundle_ja_JP() {
        this.contents = new Object[][]{{ "GDP", 21300}, { "Population", 125449703}, { "Literacy", 0.99}};
    }
    @Override
    public Object[][] getContents() {
        return contents;
    }

    private final Object[][] contents;
}

NOTE: This is the example that oracle brings. I would like to know why it doesn't function when both classes are not in the default package (I've already with the fully qualified name for the resource).

2nd - PropertiesResourceBundle

 import java.util.Locale;
import java.util.ResourceBundle;
public class InternationalizationDemo {

    public static void main(String[] args) {
        ResourceBundle bundle = ResourceBundle.getBundle("oTHER/MessageBundle", Locale.US);
        System.out.println("Message in " + Locale.US + ": " + bundle.getString("greeting"));

        //changing the default locale to indonasian 
        Locale.setDefault(new Locale("in", "ID"));
        bundle = ResourceBundle.getBundle("oTHER/MessageBundle");
        System.out.println("Message in " + Locale.getDefault() + ": " + bundle.getString("greeting"));

    }
}

And here are the properties:

properties

Both of them works, but wich one is better, quicker, and has the the minimum weight?, or is there any better way?

Also want to know when to use each kind of them (PropertiesResourceBundle and ListResourceBundle)


Solution

  • Both of them works, but wich one is better, quicker, and has the the minimum weight?

    Wrong question asked. When you write software which will evolve (and if you want to externalize strings, this is rather obvious), you should put premium on maintainability. ListResourceBundle are basically code files - these files could not be easily maintained. Just imagine that you'll be tasked with updating just one entry... For all languages. How do you set up Translation Memory? Or how to use Machine Translation on source files?
    But the real problem is, what if you want to add a language in the future? Do you really want to recompile everything?

    PropertiesResourceBundle has some drawbacks (ISO8859-1 anyone?), but there are ways to resolve them. Performance-wise once you load them they are (almost) as quick as ListResourceBundle - the simple reason being HashMap is used internally to keep the translations.
    And if you want to add a language in the future, it might be as easy as simply copying resource file into right place (in your jar file or on disk if you override ResourceBundle.Control).
    Java 8 further simplifies this process - now ResourceBundle.Control implements Service Provider Interface, so you can quite easily create language packs and make the discoverable at runtime. And of course these files could be encoded in UTF-8.
    OK, in theory you can auto-discover ListResourceBundles, but maintainability problems won't go away.

    or is there any better way?

    Don't go that route. I've seen many people trying to reinvent the wheel. And it always end up being worse than ResourceBundle. Unless you know all the ins and outs of I18n, you should not try.