0
votes

Currently i am learning i18n and found that the Locale returned by

Locale.getDefault()

influence the look up process for the resource. The example is taken from The Java™ Tutorials - A Quick Example slightly modified:

org.i18n.I18NSample

package org.i18n;

import java.util.*;

public class I18NSample {

    static public void main(String[] args) {

        String language;
        String country;

        if (args.length != 2) {
            language = new String("en");
            country = new String("US");
        } else {
            language = new String(args[0]);
            country = new String(args[1]);
        }

        Locale defaultLocale = Locale.getDefault();
        System.out.println("default language = " + defaultLocale.getLanguage()
                  + "; default country = " + defaultLocale.getCountry());

        Locale inputLocale = new Locale(language, country);
        System.out.println("input language = " + inputLocale.getLanguage()
                  + "; input country = " + inputLocale.getCountry());

        ResourceBundle messages = ResourceBundle.getBundle("MessagesBundle", inputLocale);
        Locale bundleLocale = messages.getLocale();
        System.out.println("bundle language = " + bundleLocale.getLanguage()
                  + "; bundle country = " + bundleLocale.getCountry());

        System.out.println(messages.getString("greetings"));
        System.out.println(messages.getString("inquiry"));
        System.out.println(messages.getString("farewell"));
    }
}

defined default resource MessagesBundle.properties

greetings = Hello.
farewell = Goodbye.
inquiry = How are you?

and 3 additional resource files

MessagesBundle_de_DE.properties

greetings = Hallo.
farewell = Tschüß.
inquiry = Wie geht's?

MessagesBundle_en_US.properties

greetings = Hi.
farewell = Bye-bye.

MessagesBundle_fr_FR.properties

greetings = Bonjour.
farewell = Au revoir.
inquiry = Comment allez-vous?

until now everything is O.K. java -jar I18nFirstTest.jar fr FR gives:

default language = pl; default country = PL
input language = fr; input country = FR
bundle language = fr; bundle country = FR
Bonjour.
Comment allez-vous?
Au revoir.

java -jar I18nFirstTest.jar nl NL gives:

default language = pl; default country = PL
input language = nl; input country = NL
bundle language = ; bundle country =
Hello.
How are you?
Goodbye.

now, I add the following resource file MessagesBundle_pl_PL.properties

farewell = Do widzenia.
greetings = Dzie\u0144 dobry.
inquiry = \u0104\u0105\u0106\u0107\u0118\u0119\u0141\u0142\u0143\u0144Óó\u015A\u015B\u0179\u017A\u017B\u017C

and there the problem arises java -jar I18nFirstTest.jar nl NL gives:

default language = pl; default country = PL
input language = nl; input country = NL
bundle language = pl; bundle country = PL
Dzień dobry.
ĄąĆćĘꣳŃńÓ󌜏źŻż
Do widzenia.

the reason pl_PL is set in the bundle is described here public static ResourceBundle getBundle(String baseName, Locale locale, ClassLoader loader) - extract:

If no matching resource bundle is found, the default control's
getFallbackLocale method is called, which returns the current
default locale. A new sequence of candidate locale names is
generated using this locale and and searched again, as above. 

and the default locale is indeed pl_PL, but that is NOT what I want to get by the design --> there is default resource, right?

QUESTION:
How do I remove that functionality of the getBundle method, that it processes the second look up using my default Locale?

I don't want to change my locale to Locale.setDefault(new Locale("en", "GB")) because it will influence the functionality of other modules

Switching between locales may also not be thread-safe operation (right?)

...
    Locale defaultLocale = Locale.getDefault();
    Locale.setDefault(new Locale("en", "GB"));
    ResourceBundle messages = ResourceBundle.getBundle("MessagesBundle", inputLocale);
    Locale.setDefault(defaultLocale);
...

So what is the solution?

1

1 Answers

0
votes

When loading a resource bundle Java basically first checks if there is a bundle for the requested locale, then if there is a bundle for the default locale and if neither of those is present it returns the base bundle (bundle for Locale("")).

As stated in the fragment of documentation you quoted the default locale is provided by the getFallbackLocale() method of control. ResourceBundle provides a static Control class that controls the process. It is used by default when loading a ResourceBundle but you can provide your own implementation of Controlas well.

What should suffice in your case is:

public class ModifiedControl extends ResourceBundle.Control {

    @Override
    public Locale getFallbackLocale( String aBaseName, Locale aLocale ) {
        if( aBaseName == null || aLocale == null ) {
            throw new NullPointerException();
        }
        return null;
    }
}

Because the method returns null ResourceBundle will return the default resource.

[...]
5. The control.getFallbackLocale method is called to get a fallback locale (alternative to the current target locale) to try further finding a resource bundle. If the method returns a non-null locale, it becomes the next target locale and the loading process starts over from Step 3. Otherwise, if a base bundle was found and put on hold in a previous Step 5, it is returned to the caller now. Otherwise, a MissingResourceException is thrown.
[...]
source: https://docs.oracle.com/javase/7/docs/api/java/util/ResourceBundle.html#getBundle(java.lang.String,%20java.util.Locale,%20java.lang.ClassLoader,%20java.util.ResourceBundle.Control)

Then you must simply provide an instance of your modified control when loading a resource bundle.

ResourceBundle messages = ResourceBundle.getBundle("MessagesBundle", inputLocale, new ModifiedControl() );