package org.korsakow.ide.lang; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import org.apache.log4j.Logger; import org.dsrg.soenea.service.Registry; import org.korsakow.ide.util.PreferencesManager; import org.korsakow.ide.util.ResourceManager; public class LanguageBundle { private static class MyLoader extends ClassLoader { @Override protected URL findResource(String name) { try { return ResourceManager.getResourceSource().getResourceFile( name ).toURL(); } catch (MalformedURLException e) { throw new RuntimeException(e); } } } private static ClassLoader source = new MyLoader(); private static ResourceBundle defaultBundle; private static ResourceBundle bundle; private static synchronized ResourceBundle getBundle() { if (defaultBundle == null) { defaultBundle = ResourceBundle.getBundle("resources/lang/strings", new Locale("EN"), source); } if (bundle == null) { try { bundle = ResourceBundle.getBundle("resources/lang/strings", getCurrentLocale(), source); } catch (MissingResourceException e) { Logger.getLogger(LanguageBundle.class).error("", e); bundle = defaultBundle; } } return bundle; } private static String get(String key, ResourceBundle aBundle) { String bundleString = null; try { bundleString = aBundle.getString(key); } catch (MissingResourceException firstException) { try { // 2009-11-03: disabling this logging due to spam. anyway we mostly care about missing from the default EN bundle which will still be logged // stuff missing from other langs is managed via the strings.properties files // Logger.getLogger(LanguageBundle.class).warn("Locale=" + getCurrentLocale() + ", key= " + key, firstException); bundleString = '['+defaultBundle.getString(key)+']'; } catch (MissingResourceException secondException) { // usually the default bundle will have all strings throw firstException; } } return bundleString; } public static String getStringFromDefaultBundle(String key, Object... args) { getBundle(); String bundleString = get(key, defaultBundle); try { // hack to get the bundle in UTF-8 with JDK prior to 1.6 bundleString = new String(bundleString.getBytes("ISO-8859-1"), "UTF-8"); } catch (UnsupportedEncodingException e) { Logger.getLogger(LanguageBundle.class).error("", e); } bundleString = bundleString.replace("'", "''"); // messageformat hack... we don't currently use any of the fancy stuff in there at the moment return MessageFormat.format(bundleString, args); } public static String getString(String key, Object... args) { String bundleString = get(key, getBundle()); try { // hack to get the bundle in UTF-8 with JDK prior to 1.6 bundleString = new String(bundleString.getBytes("ISO-8859-1"), "UTF-8"); } catch (UnsupportedEncodingException e) { Logger.getLogger(LanguageBundle.class).error("", e); } bundleString = escapeMessageFormat(bundleString); return MessageFormat.format(bundleString, args); } /** * Returns whether the given key exists. This method checks against the default bundle, not the current * language bundle. */ public static boolean hasString(String key) { try { // we check against the default bundle defaultBundle.getString(key); return true; } catch (MissingResourceException e) { return false; } } public static int getInt(String key) { return Integer.parseInt(getString(key)); } /** * Gets the list of locales for which we actually have a bundle. * @return */ public static Collection<Locale> getAvailableLocales() { Collection<Locale> locales = new ArrayList<Locale>(); try { String localesstr = Registry.getProperty("locales"); String[] localesarray = localesstr.split(","); for (String localename : localesarray) locales.add(new Locale(localename)); } catch (Exception e1) { locales = Arrays.asList(new Locale("EN")); } return locales; } public static void setCurrentLocale(Locale locale) { Logger.getLogger(LanguageBundle.class).info("set locale = " + locale.getDisplayName()); PreferencesManager.getPreferences(LanguageBundle.class).put("locale_language", locale.getLanguage()); PreferencesManager.getPreferences(LanguageBundle.class).put("locale_country", locale.getCountry()); PreferencesManager.getPreferences(LanguageBundle.class).put("locale_variant", locale.getVariant()); } public static Locale getCurrentLocale() { Locale systemDefaultLocale = Locale.getDefault(); String language = PreferencesManager.getPreferences(LanguageBundle.class).get("locale_language", systemDefaultLocale.getLanguage()); String country = PreferencesManager.getPreferences(LanguageBundle.class).get("locale_country", systemDefaultLocale.getCountry()); String variant = PreferencesManager.getPreferences(LanguageBundle.class).get("locale_variant", systemDefaultLocale.getVariant()); Logger.getLogger(LanguageBundle.class).info("get locale = " + new Locale(language, country, variant).getDisplayName()); return new Locale(language, country, variant); } /** * Takes a string that was not properly escaped for MessageFormat and escapes special chars. * E.g. apostrophes are doubled. */ public static String escapeMessageFormat(String naive) { return naive.replace("'", "''"); // messageformat hack... we don't currently use any of the fancy stuff in there at the moment } } }