package com.revolsys.i18n; import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import com.revolsys.beans.AbstractPropertyChangeSupportProxy; public final class I18n extends AbstractPropertyChangeSupportProxy { /** The map from category names to I18n instances. */ private static Map<String, WeakReference<I18n>> instances = new HashMap<>(); private static Locale locale = Locale.getDefault(); private static final I18n NULL_INSTANCE = new I18n(); public static CharSequence getCharSequence(final Class<?> clazz, final String key) { final I18n i18n = I18n.getInstance(clazz); String fullKey; if (key != null && key.trim().length() > 0) { fullKey = clazz.getName() + "." + key; } else { fullKey = clazz.getName(); } return new I18nCharSequence(i18n, fullKey); } private static I18n getExactInstance(final ClassLoader classLoader, final String resourcePath) { synchronized (instances) { WeakReference<I18n> i18nRef = instances.get(resourcePath); I18n i18n = null; if (i18nRef != null) { i18n = i18nRef.get(); } if (i18n == null) { i18n = new I18n(classLoader, resourcePath); i18nRef = new WeakReference<>(i18n); instances.put(resourcePath, i18nRef); } return i18n; } } public static I18n getInstance(final Class clazz) { final ClassLoader classLoader = clazz.getClassLoader(); final String className = clazz.getName(); return getInstance(classLoader, className); } private static I18n getInstance(final ClassLoader classLoader, final String resourceName) { synchronized (instances) { final String resourcePath = resourceName.replace('.', '/'); try { final I18n i18n = getExactInstance(classLoader, resourcePath); return i18n; } catch (final MissingResourceException e) { try { final I18n i18n = getExactInstance(classLoader, resourcePath + "/i18n"); return i18n; } catch (final MissingResourceException e2) { final int dotIndex = resourceName.lastIndexOf('.'); if (dotIndex != -1) { final String parentName = resourceName.substring(0, dotIndex); final I18n i18n = getInstance(classLoader, parentName); return i18n; } } return NULL_INSTANCE; } } } public static String getString(final Class<?> clazz, final String key) { return getCharSequence(clazz, key).toString(); } public static void setLocale(final Locale locale) { synchronized (instances) { final Locale oldLocale = I18n.locale; I18n.locale = locale; for (final WeakReference<I18n> reference : instances.values()) { final I18n i18n = reference.get(); if (i18n != null) { i18n.loadResourceBundle(); i18n.firePropertyChange("locale", oldLocale, locale); } } } } private WeakReference<ClassLoader> classLoaderReference; private ResourceBundle resourceBundle; private String resourcePath; private I18n() { } /** * Construct an I18n instance for the category. * * @param resourcePath The path to the language files. */ private I18n(final ClassLoader classLoader, final String resourcePath) { this.classLoaderReference = new WeakReference<>(classLoader); this.resourcePath = resourcePath; loadResourceBundle(); } public CharSequence getCharSequence(final String key) { return new I18nCharSequence(this, key); } /** * Get the I18n text from the language file associated with this instance. If * no label is defined then a default string is created from the last part of * the key. * * @param key The key of the text in the language file. * @return The I18Nized text. */ public String getString(final String key) { if (this.resourceBundle != null) { try { return this.resourceBundle.getString(key); } catch (final java.util.MissingResourceException e) { } } final String[] labelpath = key.split("\\."); return labelpath[labelpath.length - 1]; } private void loadResourceBundle() { final ClassLoader classLoader = this.classLoaderReference.get(); this.resourceBundle = ResourceBundle.getBundle(this.resourcePath, Locale.getDefault(), classLoader); } @Override public String toString() { return this.resourcePath; } }