Search code examples
javaresourcespropertieslocale

Java loads wrong resource


I have this 2 properties files in my resources folder: messages_hr_HR.properties and messages.properties

I don't use javas's Locale class I use mine custom Locale class:

public class Locale {

    private String bundleName;
    private String localeName;
    private String iconPath;

    public Locale(String bundleName, String localeName, String iconPath) {
        super();

        this.bundleName = bundleName;
        this.localeName = localeName;
        this.iconPath = iconPath;
    }

    public String getBundleName() {
        return bundleName;
    }
    public void setBundleName(String bundleName) {
        this.bundleName = bundleName;
    }
    public String getLocaleName() {
        return localeName;
    }
    public void setLocaleName(String localeName) {
        this.localeName = localeName;
    }

    public String getIconPath() {
        return iconPath;
    }

    public void setIconPath(String iconPath) {
        this.iconPath = iconPath;
    }
}

I have Messages class with static method to return the value of the key:

public class Messages {

    private Messages() {
        // do not instantiate
    }


    private static List<Locale> availableLocales;
    private static Locale defaultLocale = new Locale("messages.messages", "EN", "/images/icons/locale/en.png");
    static {
        availableLocales = new ArrayList<Locale>();

        availableLocales.add(defaultLocale);
        availableLocales.add(new Locale("messages.messages_hr_HR", "HR", "/images/icons/locale/hr.png"));   
    }

    private static Locale LOCALE = defaultLocale;
    private static ResourceBundle RESOURCE_BUNDLE = loadBundle();
    private static ResourceBundle loadBundle() {
        return ResourceBundle.getBundle(LOCALE.getBundleName());
    }

    public static String getString(String key) {
        try {
            ResourceBundle bundle = RESOURCE_BUNDLE == null ? loadBundle() : RESOURCE_BUNDLE;
            return bundle.getString(key);
        } catch (MissingResourceException e) {
            return "!" + key + "!";
        }
    }

    public static void setLocale(Locale locale) {
        LOCALE = locale;
        RESOURCE_BUNDLE = loadBundle();
    }

    public static Locale getLocale() {
        return LOCALE;
    }
    public static List<Locale> getAvailableLocales() {

        return availableLocales;
    }
}

Then in my GUI I have radiobutton menu with available languages and when user clicks on some I just call Messages.setLocale(clickedLanguageLocale);

So you can see that I am responsible of loading specific file, not java.

Problem is that on some computers it acts strange. Some text is on english (messages.properties) and some on croatian (messages_hr_HR). First thing that got on my mind was some OS default locale but it does not make any sense since I use mine classes.

Any ideas for this behavior?


Solution

  • It is hard to guess the order in which the messages are loaded without seeing the entire code. My guess is there is a data race on RESOURCE_BUNDLE if multiple threads are involved in your GUI application. The GUI starts reading the new text-keys before the new RESOURCE_BUNDLE has been loaded. That is why part of them appear in English while the rest in Croatian.

    Edit: This turned out to be the actual solution as noted in the comment below:

    Also, you can use this version of getBundle() docs.oracle.com/javase/6/docs/api/java/util/… to explicitly pass the Locale you want to use.