
clime.messadmin.i18n.I18NSupport Maven / Gradle / Ivy
/**
*
*/
package clime.messadmin.i18n;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import clime.messadmin.taglib.fmt.MessageTag;
import clime.messadmin.utils.StackIntrospector;
/**
* ThreadLocal containing administration locale + i18n utilities.
* @author Cédrik LIME
* @since 4.1
*/
public class I18NSupport {
private static final ThreadLocal/**/ adminLocale = new ThreadLocal/**/();
/**
* Default Locale to use for the administration application, if none is requested: {@value}
*/
public static final Locale DEFAULT_ADMIN_LOCALE = Locale.ENGLISH;
private static final Locale EMPTY_LOCALE = new Locale("", "");//$NON-NLS-1$//$NON-NLS-2$
/**
*
*/
private I18NSupport() {
super();
}
public static Locale getAdminLocale() {
Locale locale = (Locale) adminLocale.get();
return locale != null ? locale : DEFAULT_ADMIN_LOCALE;
}
public static void setAdminLocale(Locale locale) {
adminLocale.set(locale);
}
/**
* Gets the resource bundle with the given base name and preferred locale.
*
* This method calls java.util.ResourceBundle.getBundle(), but ignores
* its return value unless its locale represents an exact or language match
* with the given preferred locale.
*
* @param baseName the resource bundle base name
* @param locale the preferred locale
*
* @return the requested resource bundle, or null if no resource
* bundle with the given base name exists or if there is no exact- or
* language-match between the preferred locale and the locale of
* the bundle returned by java.util.ResourceBundle.getBundle().
*
* @see clime.messadmin.taglib.fmt.BundleTag#findMatch(String, Locale)
*/
public static ResourceBundle getResourceBundle(String baseName, Locale locale, ClassLoader cl) {
ResourceBundle match = null;
try {
if (cl == null) {
cl = Thread.currentThread().getContextClassLoader();
}
ResourceBundle bundle = ResourceBundle.getBundle(baseName, locale, cl);
Locale avail = bundle.getLocale();
if (locale.equals(avail)) {
// Exact match
match = bundle;
} else {
/*
* We have to make sure that the match we got is for
* the specified locale. The way ResourceBundle.getBundle()
* works, if a match is not found with (1) the specified locale,
* it tries to match with (2) the current default locale as
* returned by Locale.getDefault() or (3) the root resource
* bundle (basename).
* We must ignore any match that could have worked with (2).
* So if an exact match is not found, we make the following extra
* tests:
* - avail locale must be equal to preferred locale
* - avail country must be empty or equal to preferred country
* (the equality match might have failed on the variant)
*/
if ("".equals(avail.getLanguage())//$NON-NLS-1$
|| (locale.getLanguage().equals(avail.getLanguage())
&& ("".equals(avail.getCountry())//$NON-NLS-1$
|| locale.getCountry().equals(avail.getCountry())))) {
/*
* Language match.
* By making sure the available locale does not have a
* country and matches the preferred locale's language, we
* rule out "matches" based on the container's default
* locale. For example, if the preferred locale is
* "en-US", the container's default locale is "en-UK", and
* there is a resource bundle (with the requested base
* name) available for "en-UK", ResourceBundle.getBundle()
* will return it, but even though its language matches
* that of the preferred locale, we must ignore it,
* because matches based on the container's default locale
* are not portable across different containers with
* different default locales.
*/
match = bundle;
}
if (match == null) {
/* Try to fetch (3) the root resource bundle (basename). This case is
* when (2) the current default locale as returned by Locale.getDefault()
* was used (ResourceBundle.getBundle() algorithm stopped at step 2).
*/
bundle = ResourceBundle.getBundle(baseName, EMPTY_LOCALE, cl);
avail = bundle.getLocale();
if ("".equals(avail.getLanguage())//$NON-NLS-1$
&& "".equals(avail.getCountry())//$NON-NLS-1$
&& "".equals(avail.getVariant())) {//$NON-NLS-1$
// we got a match
match = bundle;
}
}
}
} catch (MissingResourceException mre) {
}
return match;
}
public static ResourceBundle getResourceBundle(String baseName, ClassLoader cl) {
return getResourceBundle(baseName, getAdminLocale(), cl);
}
/**
* Retrieves the localized message corresponding to the given key, and
* performs parametric replacement using the arguments specified via
* args.
*
*
* See the specification of {@link java.text.MessageFormat} for a
* description of how parametric replacement is implemented.
*
*
* If no resource bundle with the given base name exists, or the given key
* is undefined in the resource bundle, the string "???<key>???" is
* returned, where "<key>" is replaced with the given key.
*
* @param baseName the resource bundle base name
* @param key the message key
* @param args the arguments for parametric replacement
*
* @return the localized message corresponding to the given key
*/
public static String getLocalizedMessage(String baseName, ClassLoader cl, String key, Object[] args) {
String message = MessageTag.UNDEFINED_KEY + key + MessageTag.UNDEFINED_KEY;
ResourceBundle bundle = getResourceBundle(baseName, cl);
if (bundle != null) {
try {
message = bundle.getString(key);
if (args != null) {
MessageFormat formatter = new MessageFormat("");//$NON-NLS-1$
Locale locale = getAdminLocale();
if (locale != null) {
formatter.setLocale(locale);
}
formatter.applyPattern(message);
message = formatter.format(args);
}
} catch (MissingResourceException mre) {
}
}
return message;
}
public static String getLocalizedMessage(String baseName, ClassLoader cl, String key) {
return getLocalizedMessage(baseName, cl, key, null);
}
public static String getLocalizedMessage(ClassLoader cl, String key, Object[] args) {
return getLocalizedMessage(StackIntrospector.getCallerClass().getName(), cl, key, args);
}
public static String getLocalizedMessage(ClassLoader cl, String key) {
return getLocalizedMessage(StackIntrospector.getCallerClass().getName(), cl, key, null);
}
public static String getLocalizedMessage(String key, Object[] args) {
return getLocalizedMessage(StackIntrospector.getCallerClass().getName(), null, key, args);
}
public static String getLocalizedMessage(String key) {
return getLocalizedMessage(StackIntrospector.getCallerClass().getName(), null, key, null);
}
}