/* Copyright 2009-2016 David Hadka
*
* This file is part of the MOEA Framework.
*
* The MOEA Framework is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* The MOEA Framework is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the MOEA Framework. If not, see <http://www.gnu.org/licenses/>.
*/
package org.moeaframework.util;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
/**
* Facilitates internalization (i18n) and localization (l10n) of strings.
* Locale-specific strings are stored in a single file in each package
* named {@code LocalStrings.properties},
* {@code LocalStrings_{locale}.properties} or any other format supported by
* {@link ResourceBundle}. This class supports two modes of localization:
* <p>
* <h3>Package-specific</h3>
* This is useful when classes in a package share common resources. All
* classes have access to all stored resources. Use the
* {@link #getLocalization(String)} method to create instances of the
* {@code Localization} class for a specific package. Here, you use the
* {@link #getString(String)} and {@link #getString(String, Object...)}
* methods on the {@code Localization} instance you previously created.
* <p>
* <h3>Class-specific</h3>
* The {@link #getString(Class, String)} and
* {@link #getString(Class, String, Object...)} static methods do not require
* you to explicitly create a new {@code Localization} instance. In addition,
* the keys are automatically prefixed with the class name. For example, if
* your property file contains the following lines:
* <pre>
* WindowA.title = First Title
* WindowB.title = Second Title
* </pre>
* You can read each entry with
* {@code Localization.getString(WindowA.class, "title")} and
* {@code Localization.getString(WindowB.class, "title")}. This is convenient
* for providing localization in subclasses by using the {@code getClass()}
* method.
*/
public class Localization {
/**
* The underlying resource bundle storing the key-value resource mapping.
*/
private final ResourceBundle bundle;
/**
* Constructs a new localization instance based on the specified resource
* bundle. If this resource bundle is {@code null}, then the
* {@code getString} methods return the {@code key}.
*
* @param bundle the resource bundle storing the key-value resource mappings
* used by this localization object
*/
private Localization(ResourceBundle bundle) {
super();
this.bundle = bundle;
}
/**
* Returns the underlying resource bundle.
*
* @return the underlying resource bundle
*/
public ResourceBundle getBundle() {
return bundle;
}
/**
* Returns the locale of this localization.
*
* @return the locale of this localization
*/
public Locale getLocale() {
return bundle.getLocale();
}
/**
* Returns the localized string for the given key. If the key is not
* found, then this methods returns the key itself.
*
* @param key the key for the desired string
* @return the localized string for the given key
*/
public String getString(String key) {
try {
if (bundle == null) {
return key;
} else {
return bundle.getString(key);
}
} catch (MissingResourceException e) {
return key;
}
}
/**
* Returns {@code true} if a localized string exists for the given key;
* {@code false} otherwise.
*
* @param key the key for the desired string
* @return {@code true} if a localized string exists for the given key;
* {@code false} otherwise
*/
public boolean containsKey(String key) {
if (bundle == null) {
return false;
}
return bundle.containsKey(key);
}
/**
* Returns the localized string for the given key and formatting arguments.
* This method uses {@link MessageFormat} for formatting the arguments. If
* the key is not found, then this methods returns the key itself.
*
* @param key the key for the desired string
* @param arguments the formatting arguments
* @return the localized string for the given key and formatting arguments
*/
public String getString(String key, Object... arguments) {
MessageFormat format = new MessageFormat(getString(key),
getLocale());
return format.format(arguments, new StringBuffer(), null).toString();
}
/**
* Returns the localization object for the given package.
*
* @param packageName the name of the package
* @return the localization object for the given package
*/
public static Localization getLocalization(String packageName) {
return getLocalization(packageName, Locale.getDefault());
}
/**
* Returns the localization object for the given package and locale.
*
* @param packageName the name of the package
* @param locale the target locale
* @return the localization object for the given package
*/
public static Localization getLocalization(String packageName,
Locale locale) {
ResourceBundle bundle = null;
try {
bundle = ResourceBundle.getBundle(packageName + ".LocalStrings",
locale);
} catch (MissingResourceException e) {
//bundle remains null, so the localization returns the key to
//provide a visual clue for debugging
}
return new Localization(bundle);
}
/**
* Returns the localization object for the given class.
*
* @param type the class requesting the localization object
* @return the localization object for the given class
*/
public static Localization getLocalization(Class<?> type) {
return getLocalization(type.getPackage().getName());
}
/**
* Returns the localization object for the given class and locale.
*
* @param type the class requesting the localization object
* @param locale the target locale
* @return the localization object for the given class
*/
public static Localization getLocalization(Class<?> type, Locale locale) {
return getLocalization(type.getPackage().getName(), locale);
}
/**
* Returns {@code true} if a localized string exists for the given key;
* {@code false} otherwise. This method automatically finds the correct
* resource bundle and key prefix appropriate for the class.
*
* @param type the class requesting the localized string
* @param key the key (minus the class prefix)
* @return {@code true} if a localized string exists for the given key;
* {@code false} otherwise
*/
public static boolean containsKey(Class<?> type, String key) {
return getLocalization(type).containsKey(type.getSimpleName() + "." +
key);
}
/**
* Returns the localized string for the given key. This method
* automatically finds the correct resource bundle and key prefix
* appropriate for the class. For example, calling
* {@code Localization.getString(MainGUI.class, "title")} returns the
* localized string for the key {@code "MainGUI.title"}.
*
* @param type the class requesting the localized string
* @param key the key (minus the class prefix)
* @return the localized string for the given key
*/
public static String getString(Class<?> type, String key) {
return getLocalization(type).getString(type.getSimpleName() + "." +
key);
}
/**
* Returns the localized string for the given key and formatting arguments.
* This method automatically finds the correct resource bundle and key
* prefix appropriate for the class. For example, calling
* {@code Localization.getString(MainGUI.class, "title")} returns the
* localized string for the key {@code "MainGUI.title"}.
*
* @param type the class requesting the localized string
* @param key the key (minus the class prefix)
* @param arguments the formatting arguments
* @return the localized string for the given key
*/
public static String getString(Class<?> type, String key,
Object... arguments) {
return getLocalization(type).getString(type.getSimpleName() + "." + key,
arguments);
}
}