diff --git a/src/java/com/threerings/util/MessageBundle.java b/src/java/com/threerings/util/MessageBundle.java new file mode 100644 index 000000000..c4e677abe --- /dev/null +++ b/src/java/com/threerings/util/MessageBundle.java @@ -0,0 +1,121 @@ +// +// $Id: MessageBundle.java,v 1.1 2002/01/29 20:44:35 mdb Exp $ + +package com.threerings.util; + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import com.samskivert.util.StringUtil; + +/** + * A message bundle provides an easy mechanism by which to obtain + * translated message strings from a resource bundle. It uses the {@link + * MessageFormat} class to substitute arguments into the translation + * strings. Message bundles would generally be obtained via the {@link + * MessageManager}, but could be constructed individually if so desired. + */ +public class MessageBundle +{ + /** + * Constructs a message bundle which will obtain localized messages + * from the supplied resource bundle. The path is provided purely for + * reporting purposes. + */ + public MessageBundle (String path, ResourceBundle bundle) + { + _path = path; + _bundle = bundle; + } + + /** + * Obtains the translation for the specified message key. No arguments + * are substituted into the translated string. If a translation + * message does not exist for the specified key, an error is logged + * and the key itself is returned so that the caller need not worry + * about handling a null response. + */ + public String get (String key) + { + try { + return _bundle.getString(key); + + } catch (MissingResourceException mre) { + Log.warning("Missing translation message " + + "[bundle=" + _path + ", key=" + key + "]."); + return key; + } + } + + /** + * Obtains the translation for the specified message key. The + * specified argument is substituted into the translated string. See + * {@link MessageFormat} for more information on how the substitution + * is performed. If a translation message does not exist for the + * specified key, an error is logged and the key itself (plus the + * argument) is returned so that the caller need not worry about + * handling a null response. + */ + public String get (String key, Object arg1) + { + return get(key, new Object[] { arg1 }); + } + + /** + * Obtains the translation for the specified message key. The + * specified arguments are substituted into the translated string. See + * {@link MessageFormat} for more information on how the substitution + * is performed. If a translation message does not exist for the + * specified key, an error is logged and the key itself (plus the + * arguments) is returned so that the caller need not worry about + * handling a null response. + */ + public String get (String key, Object arg1, Object arg2) + { + return get(key, new Object[] { arg1, arg2 }); + } + + /** + * Obtains the translation for the specified message key. The + * specified arguments are substituted into the translated string. See + * {@link MessageFormat} for more information on how the substitution + * is performed. If a translation message does not exist for the + * specified key, an error is logged and the key itself (plus the + * arguments) is returned so that the caller need not worry about + * handling a null response. + */ + public String get (String key, Object arg1, Object arg2, Object arg3) + { + return get(key, new Object[] { arg1, arg2, arg3 }); + } + + /** + * Obtains the translation for the specified message key. The + * specified arguments are substituted into the translated string. See + * {@link MessageFormat} for more information on how the substitution + * is performed. If a translation message does not exist for the + * specified key, an error is logged and the key itself (plus the + * arguments) is returned so that the caller need not worry about + * handling a null response. + */ + public String get (String key, Object[] args) + { + try { + String message = _bundle.getString(key); + return MessageFormat.format(message, args); + + } catch (MissingResourceException mre) { + Log.warning("Missing translation message " + + "[bundle=" + _path + ", key=" + key + "]."); + return key + StringUtil.toString(args); + } + } + + /** The path that identifies the resource bundle we are using to + * obtain our messages. */ + protected String _path; + + /** The resource bundle from which we obtain our messages. */ + protected ResourceBundle _bundle; +} diff --git a/src/java/com/threerings/util/MessageManager.java b/src/java/com/threerings/util/MessageManager.java new file mode 100644 index 000000000..ca7a84e64 --- /dev/null +++ b/src/java/com/threerings/util/MessageManager.java @@ -0,0 +1,103 @@ +// +// $Id: MessageManager.java,v 1.1 2002/01/29 20:44:35 mdb Exp $ + +package com.threerings.util; + +import java.util.HashMap; +import java.util.Locale; +import java.util.ResourceBundle; + +/** + * The message manager provides a thin wrapper around Java's built-in + * localization support, supporting a policy of dividing up localization + * resources into logical units, all of the translations for which are + * contained in a single messages file. + * + *

The message manager assumes that the locale remains constant for + * the duration of its operation. If the locale were to change during the + * operation of the client, a call to {@link #setLocale} should be made to + * inform the message manager of the new locale (which will clear the + * message bundle cache). + */ +public class MessageManager +{ + /** + * Constructs a message manager with the supplied resource prefix and + * the default locale. The prefix will be prepended to the path of all + * resource bundles prior to their resolution. For example, if a + * prefix of rsrc.messages was provided and a message + * bundle with the name game.chess was later requested, + * the message manager would attempt to load a resource bundle with + * the path rsrc.messages.game.chess and would eventually + * search for a file in the classpath with the path + * rsrc/messages/game/chess.properties. + * + *

See the documentation for {@link + * ResourceBundle#getBundle(String,Locale,ClassLoader)} for a more + * detailed explanation of how resource bundle paths are resolved. + */ + public MessageManager (String resourcePrefix) + { + // keep the prefix + _prefix = resourcePrefix; + + // use the default locale + _locale = Locale.getDefault(); + + // make sure the prefix ends with a dot + if (!_prefix.endsWith(".")) { + _prefix += "."; + } + } + + /** + * Sets the locale to the specified locale. Subsequent message bundles + * fetched via the message manager will use the new locale. The + * message bundle cache will also be cleared. + */ + public void setLocale (Locale locale) + { + _locale = locale; + _cache.clear(); + } + + /** + * Fetches the message bundle for the specified path. If no bundle can + * be located with the specified path, a special bundle is returned + * that returns the untranslated message identifiers instead of an + * associated translation. This is done so that error code to handle a + * failed bundle load need not be replicated wherever bundles are + * used. Instead an error will be logged and the requesting service + * can continue to function in an impaired state. + */ + public MessageBundle getBundle (String path) + { + // first look in the cache + MessageBundle bundle = (MessageBundle)_cache.get(path); + if (bundle != null) { + return bundle; + } + + // if it's not cached, we'll need to resolve it + String fqpath = _prefix + path; + ResourceBundle rbundle = ResourceBundle.getBundle(fqpath, _locale); + if (rbundle == null) { + Log.warning("Unable to resolve resource bundle " + + "[path=" + fqpath + "]."); + } + + // create our message bundle, cache it and return it + bundle = new MessageBundle(path, rbundle); + _cache.put(path, bundle); + return bundle; + } + + /** The prefix we prepend to resource paths prior to loading. */ + protected String _prefix; + + /** The locale for which we're obtaining message bundles. */ + protected Locale _locale; + + /** A cache of instantiated message bundles. */ + protected HashMap _cache = new HashMap(); +}