Screw it, let's just do the right thing. We'll forget later.
- Use the chaining method to get a resource from ResourceManager. - Fixed getAll so that it will not overwrite a found property with one in the parent. Made it also understand locales and do the chaining. This change'll cause an extra object hash lookup or two for every translation key, but it's more Right. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4947 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -22,6 +22,8 @@
|
|||||||
package com.threerings.util {
|
package com.threerings.util {
|
||||||
|
|
||||||
import mx.resources.IResourceBundle;
|
import mx.resources.IResourceBundle;
|
||||||
|
import mx.resources.ResourceManager;
|
||||||
|
import mx.resources.IResourceManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A message bundle provides an easy mechanism by which to obtain
|
* A message bundle provides an easy mechanism by which to obtain
|
||||||
@@ -37,13 +39,10 @@ public class MessageBundle
|
|||||||
* from the supplied resource bundle. The path is provided purely for
|
* from the supplied resource bundle. The path is provided purely for
|
||||||
* reporting purposes.
|
* reporting purposes.
|
||||||
*/
|
*/
|
||||||
public function init (
|
public function init (msgmgr :MessageManager, path :String, parent :MessageBundle) :void
|
||||||
msgmgr :MessageManager, path :String, bundle :IResourceBundle,
|
|
||||||
parent :MessageBundle) :void
|
|
||||||
{
|
{
|
||||||
_msgmgr = msgmgr;
|
_msgmgr = msgmgr;
|
||||||
_path = path;
|
_path = path;
|
||||||
_bundle = bundle;
|
|
||||||
_parent = parent;
|
_parent = parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,24 +64,53 @@ public class MessageBundle
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds all messages whose key starts with the specified prefix to the
|
* Get all the messages that begin with the specified prefix.
|
||||||
* supplied array.
|
|
||||||
*
|
*
|
||||||
* @param includeParent if true, messages from our parent bundle (and its
|
* @param includeParent if true, messages from our parent bundle (and its
|
||||||
* parent bundle, all the way up the chain will be included).
|
* parent bundle, all the way up the chain will be included).
|
||||||
*/
|
*/
|
||||||
public function getAll (
|
public function getAll (prefix :String, includeParent :Boolean = true) :Array
|
||||||
prefix :String, messages :Array, includeParent :Boolean = true) :void
|
|
||||||
{
|
{
|
||||||
for (var key :String in _bundle.content) {
|
var messages :Array = []
|
||||||
if (StringUtil.startsWith(key, prefix)) {
|
for each (var value :Object in getAllMapped(prefix, includeParent)) {
|
||||||
messages.push(get(key));
|
messages.push(value);
|
||||||
|
}
|
||||||
|
return messages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all the messages and their keys that begin with the specified prefix.
|
||||||
|
*/
|
||||||
|
public function getAllMapped (prefix :String, includeParent :Boolean = true) :Object
|
||||||
|
{
|
||||||
|
var mgr :IResourceManager = ResourceManager.getInstance();
|
||||||
|
|
||||||
|
// search all locales, using the first one first, but including any
|
||||||
|
// non-overridden keys from backing locales
|
||||||
|
var messages :Object = {};
|
||||||
|
var key :String;
|
||||||
|
for each (var locale :String in mgr.getLocales()) {
|
||||||
|
var bundle :IResourceBundle = mgr.getResourceBundle(locale, _path);
|
||||||
|
if (bundle != null) {
|
||||||
|
for (key in bundle.content) {
|
||||||
|
// preserve the message found in an earlier locale
|
||||||
|
if (StringUtil.startsWith(key, prefix) && !(key in messages)) {
|
||||||
|
messages[key] = bundle.content[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeParent && _parent != null) {
|
if (includeParent && _parent != null) {
|
||||||
_parent.getAll(prefix, messages, includeParent);
|
// don't let parent messages overwrite any we've found
|
||||||
|
var parentMap :Object = _parent.getAllMapped(prefix, includeParent);
|
||||||
|
for (key in parentMap) {
|
||||||
|
if (!(key in messages)) {
|
||||||
|
messages[key] = parentMap[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return messages;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -93,32 +121,24 @@ public class MessageBundle
|
|||||||
* @param reportMissing whether or not the method should log an error
|
* @param reportMissing whether or not the method should log an error
|
||||||
* if the resource didn't exist.
|
* if the resource didn't exist.
|
||||||
*/
|
*/
|
||||||
protected function getResourceString (
|
protected function getResourceString (key :String, reportMissing :Boolean = true) :String
|
||||||
key :String, reportMissing :Boolean = true) :String
|
|
||||||
{
|
{
|
||||||
if (_bundle != null) {
|
var value :String = ResourceManager.getInstance().getString(_path, key);
|
||||||
var val :Object = _bundle.content[key];
|
|
||||||
if (val != null) {
|
|
||||||
return String(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have a parent, try getting the string from them
|
if (value == null) {
|
||||||
if (_parent != null) {
|
// if we have a parent, try getting the string from them
|
||||||
var value :String = _parent.getResourceString(key, false);
|
if (_parent != null) {
|
||||||
if (value != null) {
|
value = _parent.getResourceString(key, false);
|
||||||
return value;
|
|
||||||
}
|
}
|
||||||
// if we didn't find it in our parent, we want to fall
|
// if we didn't find it in our parent, we want to fall
|
||||||
// through and report missing appropriately
|
// through and report missing appropriately
|
||||||
|
if (value == null && reportMissing) {
|
||||||
|
Log.getLog(this).warning("Missing translation message " +
|
||||||
|
"[bundle=" + _path + ", key=" + key + "].");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reportMissing) {
|
return value;
|
||||||
Log.getLog(this).warning("Missing translation message " +
|
|
||||||
"[bundle=" + _path + ", key=" + key + "].");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -407,9 +427,6 @@ public class MessageBundle
|
|||||||
* obtain our messages. */
|
* obtain our messages. */
|
||||||
protected var _path :String;
|
protected var _path :String;
|
||||||
|
|
||||||
/** The resource bundle from which we obtain our messages. */
|
|
||||||
protected var _bundle :IResourceBundle;
|
|
||||||
|
|
||||||
/** Our parent bundle if we're not the global bundle. */
|
/** Our parent bundle if we're not the global bundle. */
|
||||||
protected var _parent :MessageBundle;
|
protected var _parent :MessageBundle;
|
||||||
|
|
||||||
|
|||||||
@@ -62,35 +62,10 @@ public class MessageManager
|
|||||||
*/
|
*/
|
||||||
public function MessageManager ()
|
public function MessageManager ()
|
||||||
{
|
{
|
||||||
// use the default locale
|
|
||||||
_locale = ResourceManager.getInstance().getLocales()[0];
|
|
||||||
|
|
||||||
// load up the global bundle
|
// load up the global bundle
|
||||||
_global = getBundle(GLOBAL_BUNDLE);
|
_global = getBundle(GLOBAL_BUNDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Get the locale that is being used to translate messages.
|
|
||||||
// * This may be useful if using standard translations, for example
|
|
||||||
// * new SimpleDateFormat("EEEE", getLocale()) to get the name of a weekday
|
|
||||||
// * that matches the language being used for all other client translations.
|
|
||||||
// */
|
|
||||||
// public function getLocale () :Locale
|
|
||||||
// {
|
|
||||||
// return _locale;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /**
|
|
||||||
// * 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 function setLocale (locale :Locale) :void
|
|
||||||
// {
|
|
||||||
// _locale = locale;
|
|
||||||
// _cache.clear();
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches the message bundle for the specified path. If no bundle can
|
* Fetches the message bundle for the specified path. If no bundle can
|
||||||
* be located with the specified path, a special bundle is returned
|
* be located with the specified path, a special bundle is returned
|
||||||
@@ -108,27 +83,18 @@ public class MessageManager
|
|||||||
return bundle;
|
return bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if it's not cached, we'll need to resolve it
|
// see if we should use a custom class for the bundle
|
||||||
var rbundle :IResourceBundle =
|
var mbclass :String = ResourceManager.getInstance().getString(path, MBUNDLE_CLASS_KEY);
|
||||||
ResourceManager.getInstance().getResourceBundle(_locale, path);
|
if (mbclass != null) {
|
||||||
|
try {
|
||||||
// if the resource bundle contains a special resource, we'll
|
var clazz :Class = ClassUtil.getClassByName(String(mbclass));
|
||||||
// interpret that as a derivation of MessageBundle to instantiate
|
bundle = new clazz();
|
||||||
// for handling that class
|
} catch (ee :Error) {
|
||||||
if (rbundle != null) {
|
Log.getLog(this).warning(
|
||||||
var mbclass :Object = rbundle.content[MBUNDLE_CLASS_KEY];
|
"Failure instantiating custom message bundle " +
|
||||||
if (mbclass != null) {
|
"[mbclass=" + mbclass + ", error=" + ee + "].");
|
||||||
try {
|
|
||||||
var clazz :Class = ClassUtil.getClassByName(String(mbclass));
|
|
||||||
bundle = new clazz();
|
|
||||||
} catch (ee :Error) {
|
|
||||||
Log.getLog(this).warning(
|
|
||||||
"Failure instantiating custom message bundle " +
|
|
||||||
"[mbclass=" + mbclass + ", error=" + ee + "].");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there was no custom class, or we failed to instantiate the
|
// if there was no custom class, or we failed to instantiate the
|
||||||
// custom class, use a standard message bundle
|
// custom class, use a standard message bundle
|
||||||
if (bundle == null) {
|
if (bundle == null) {
|
||||||
@@ -138,7 +104,7 @@ public class MessageManager
|
|||||||
// initialize our message bundle, cache it and return it (if we
|
// initialize our message bundle, cache it and return it (if we
|
||||||
// couldn't resolve the bundle, the message bundle will cope with
|
// couldn't resolve the bundle, the message bundle will cope with
|
||||||
// it's null resource bundle)
|
// it's null resource bundle)
|
||||||
bundle.init(this, path, rbundle, _global);
|
bundle.init(this, path, _global);
|
||||||
_cache.put(path, bundle);
|
_cache.put(path, bundle);
|
||||||
return bundle;
|
return bundle;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user