Widened.
git-svn-id: https://samskivert.googlecode.com/svn/trunk@2021 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -31,26 +31,23 @@ import com.samskivert.text.MessageUtil;
|
|||||||
import com.samskivert.util.StringUtil;
|
import com.samskivert.util.StringUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The message manager handles the translation messages for a web
|
* The message manager handles the translation messages for a web application. The webapp should
|
||||||
* application. The webapp should construct the message manager with the
|
* construct the message manager with the name of its message properties file and it can then make
|
||||||
* name of its message properties file and it can then make use of the
|
* use of the message manager to generate locale specific messages for a request.
|
||||||
* message manager to generate locale specific messages for a request.
|
|
||||||
*/
|
*/
|
||||||
public class MessageManager
|
public class MessageManager
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Constructs a message manager with the specified bundle path. The
|
* Constructs a message manager with the specified bundle path. The message manager will be
|
||||||
* message manager will be instantiating a <code>ResourceBundle</code>
|
* instantiating a <code>ResourceBundle</code> with the supplied path, so it should conform to
|
||||||
* with the supplied path, so it should conform to the naming
|
* the naming conventions defined by that class.
|
||||||
* conventions defined by that class.
|
|
||||||
*
|
*
|
||||||
* @param siteIdent an optional site identifier that can be used to
|
* @param siteIdent an optional site identifier that can be used to identify the site via which
|
||||||
* identify the site via which an http request was made.
|
* an http request was made.
|
||||||
*
|
*
|
||||||
* @see java.util.ResourceBundle
|
* @see java.util.ResourceBundle
|
||||||
*/
|
*/
|
||||||
public MessageManager (String bundlePath, Locale deflocale,
|
public MessageManager (String bundlePath, Locale deflocale, SiteIdentifier siteIdent)
|
||||||
SiteIdentifier siteIdent)
|
|
||||||
{
|
{
|
||||||
// keep these for later
|
// keep these for later
|
||||||
_bundlePath = bundlePath;
|
_bundlePath = bundlePath;
|
||||||
@@ -59,19 +56,16 @@ public class MessageManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the message manager is to be used in a multi-site environment,
|
* If the message manager is to be used in a multi-site environment, it can be configured to
|
||||||
* it can be configured to load site-specific message resources in
|
* load site-specific message resources in addition to the default application message
|
||||||
* addition to the default application message resources. It must be
|
* resources. It must be configured with the facilities to load site-specific resources by a
|
||||||
* configured with the facilities to load site-specific resources by a
|
|
||||||
* call to this function.
|
* call to this function.
|
||||||
*
|
*
|
||||||
* @param siteBundlePath the path to the site-specific message
|
* @param siteBundlePath the path to the site-specific message resources.
|
||||||
* resources.
|
* @param siteLoader a site-specific resource loader, properly configured with a site
|
||||||
* @param siteLoader a site-specific resource loader, properly
|
* identifier.
|
||||||
* configured with a site identifier.
|
|
||||||
*/
|
*/
|
||||||
public void activateSiteSpecificMessages (String siteBundlePath,
|
public void activateSiteSpecificMessages (String siteBundlePath, SiteResourceLoader siteLoader)
|
||||||
SiteResourceLoader siteLoader)
|
|
||||||
{
|
{
|
||||||
_siteBundlePath = siteBundlePath;
|
_siteBundlePath = siteBundlePath;
|
||||||
_siteLoader = siteLoader;
|
_siteLoader = siteLoader;
|
||||||
@@ -86,9 +80,8 @@ public class MessageManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up the message with the specified path in the resource bundle
|
* Looks up the message with the specified path in the resource bundle most appropriate for the
|
||||||
* most appropriate for the locales described as preferred by the
|
* locales described as preferred by the request. Always reports missing paths.
|
||||||
* request. Always reports missing paths.
|
|
||||||
*/
|
*/
|
||||||
public String getMessage (HttpServletRequest req, String path)
|
public String getMessage (HttpServletRequest req, String path)
|
||||||
{
|
{
|
||||||
@@ -96,31 +89,27 @@ public class MessageManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up the message with the specified path in the resource bundle
|
* Looks up the message with the specified path in the resource bundle most appropriate for the
|
||||||
* most appropriate for the locales described as preferred by the
|
* locales described as preferred by the request, then substitutes the supplied arguments into
|
||||||
* request, then substitutes the supplied arguments into that message
|
* that message using a <code>MessageFormat</code> object.
|
||||||
* using a <code>MessageFormat</code> object.
|
|
||||||
*
|
*
|
||||||
* @see java.text.MessageFormat
|
* @see java.text.MessageFormat
|
||||||
*/
|
*/
|
||||||
public String getMessage (HttpServletRequest req, String path,
|
public String getMessage (HttpServletRequest req, String path, Object[] args)
|
||||||
Object[] args)
|
|
||||||
{
|
{
|
||||||
String msg = getMessage(req, path, true);
|
String msg = getMessage(req, path, true);
|
||||||
// we may cache message formatters later, but for now just use the
|
// we may cache message formatters later, but for now just use the static convenience
|
||||||
// static convenience function
|
// function
|
||||||
return MessageFormat.format(MessageUtil.escape(msg), args);
|
return MessageFormat.format(MessageUtil.escape(msg), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up the message with the specified path in the resource bundle
|
* Looks up the message with the specified path in the resource bundle most appropriate for the
|
||||||
* most appropriate for the locales described as preferred by the
|
* locales described as preferred by the request. If requested it will log a missing path and
|
||||||
* request. If requested it will log a missing path and return the
|
* return the path as the translation (which should make it obvious in the servlet that the
|
||||||
* path as the translation (which should make it obvious in the
|
* translation is missing) otherwise it returns null.
|
||||||
* servlet that the translation is missing) otherwise it returns null.
|
|
||||||
*/
|
*/
|
||||||
protected String getMessage (HttpServletRequest req, String path,
|
protected String getMessage (HttpServletRequest req, String path, boolean reportMissing)
|
||||||
boolean reportMissing)
|
|
||||||
{
|
{
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
return "[null message key]";
|
return "[null message key]";
|
||||||
@@ -139,8 +128,8 @@ public class MessageManager
|
|||||||
String[] args = StringUtil.split(argstr, "|");
|
String[] args = StringUtil.split(argstr, "|");
|
||||||
// unescape and translate the arguments
|
// unescape and translate the arguments
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
// if the argument is tainted, do no further translation
|
// if the argument is tainted, do no further translation (it might contain |s or
|
||||||
// (it might contain |s or other fun stuff)
|
// other fun stuff)
|
||||||
if (args[i].startsWith(MessageUtil.TAINT_CHAR)) {
|
if (args[i].startsWith(MessageUtil.TAINT_CHAR)) {
|
||||||
args[i] = MessageUtil.unescape(args[i].substring(1));
|
args[i] = MessageUtil.unescape(args[i].substring(1));
|
||||||
} else {
|
} else {
|
||||||
@@ -150,9 +139,9 @@ public class MessageManager
|
|||||||
return getMessage(req, key, args);
|
return getMessage(req, key, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
// load up the matching resource bundles (the array will contain the
|
// load up the matching resource bundles (the array will contain the site-specific
|
||||||
// site-specific resources first and the application resources second);
|
// resources first and the application resources second); use the locale preferred by the
|
||||||
// use the locale preferred by the client if possible
|
// client if possible
|
||||||
ResourceBundle[] bundles = resolveBundles(req);
|
ResourceBundle[] bundles = resolveBundles(req);
|
||||||
String message = null;
|
String message = null;
|
||||||
if (bundles != null) {
|
if (bundles != null) {
|
||||||
@@ -163,8 +152,7 @@ public class MessageManager
|
|||||||
message = bundles[i].getString(path);
|
message = bundles[i].getString(path);
|
||||||
}
|
}
|
||||||
} catch (MissingResourceException mre) {
|
} catch (MissingResourceException mre) {
|
||||||
// no complaints, just try the bundle in the enclosing
|
// no complaints, just try the bundle in the enclosing scope
|
||||||
// scope
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,13 +170,11 @@ public class MessageManager
|
|||||||
// avoid trivial infinite recursion
|
// avoid trivial infinite recursion
|
||||||
if (ref.equals(path)) {
|
if (ref.equals(path)) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
"Illegal self-referential message " + path + " = " +
|
"Illegal self-referential message " + path + " = " + message + ".");
|
||||||
message + ".");
|
|
||||||
}
|
}
|
||||||
if (ref.length() > 0 && !Character.isDigit(ref.charAt(0))) {
|
if (ref.length() > 0 && !Character.isDigit(ref.charAt(0))) {
|
||||||
String refmsg = getMessage(req, ref, true);
|
String refmsg = getMessage(req, ref, true);
|
||||||
message = message.substring(0, oidx) +
|
message = message.substring(0, oidx) + refmsg + message.substring(cidx+1);
|
||||||
refmsg + message.substring(cidx+1);
|
|
||||||
oidx += refmsg.length();
|
oidx += refmsg.length();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -206,13 +192,12 @@ public class MessageManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds the closest matching resource bundle for the locales
|
* Finds the closest matching resource bundle for the locales specified as preferred by the
|
||||||
* specified as preferred by the client in the supplied http request.
|
* client in the supplied http request.
|
||||||
*/
|
*/
|
||||||
protected ResourceBundle[] resolveBundles (HttpServletRequest req)
|
protected ResourceBundle[] resolveBundles (HttpServletRequest req)
|
||||||
{
|
{
|
||||||
// first look to see if we've cached the bundles for this request
|
// first look to see if we've cached the bundles for this request in the request object
|
||||||
// in the request object
|
|
||||||
ResourceBundle[] bundles = null;
|
ResourceBundle[] bundles = null;
|
||||||
if (req != null) {
|
if (req != null) {
|
||||||
bundles = (ResourceBundle[])req.getAttribute(getBundleCacheName());
|
bundles = (ResourceBundle[])req.getAttribute(getBundleCacheName());
|
||||||
@@ -245,15 +230,14 @@ public class MessageManager
|
|||||||
if (siteLoader != null) {
|
if (siteLoader != null) {
|
||||||
bundles[0] = resolveBundle(req, _siteBundlePath, siteLoader, false);
|
bundles[0] = resolveBundle(req, _siteBundlePath, siteLoader, false);
|
||||||
} else if (siteString != null) {
|
} else if (siteString != null) {
|
||||||
// or just try prefixing the site string to the normal bundle path
|
// or just try prefixing the site string to the normal bundle path and see if that
|
||||||
// and see if that turns something up
|
// turns something up
|
||||||
bundles[0] = resolveBundle(req, siteString + "_" + _bundlePath,
|
bundles[0] = resolveBundle(req, siteString + "_" + _bundlePath,
|
||||||
getClass().getClassLoader(), true);
|
getClass().getClassLoader(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// then from the default classloader
|
// then from the default classloader
|
||||||
bundles[1] = resolveBundle(
|
bundles[1] = resolveBundle(req, _bundlePath, getClass().getClassLoader(), false);
|
||||||
req, _bundlePath, getClass().getClassLoader(), false);
|
|
||||||
|
|
||||||
// if we found either or both bundles, cache 'em
|
// if we found either or both bundles, cache 'em
|
||||||
if (bundles[0] != null || bundles[1] != null && req != null) {
|
if (bundles[0] != null || bundles[1] != null && req != null) {
|
||||||
@@ -264,12 +248,11 @@ public class MessageManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolves the default resource bundle based on the locale
|
* Resolves the default resource bundle based on the locale information provided in the
|
||||||
* information provided in the supplied http request object.
|
* supplied http request object.
|
||||||
*/
|
*/
|
||||||
protected ResourceBundle resolveBundle (
|
protected ResourceBundle resolveBundle (HttpServletRequest req, String bundlePath,
|
||||||
HttpServletRequest req, String bundlePath, ClassLoader loader,
|
ClassLoader loader, boolean silent)
|
||||||
boolean silent)
|
|
||||||
{
|
{
|
||||||
ResourceBundle bundle = null;
|
ResourceBundle bundle = null;
|
||||||
|
|
||||||
@@ -279,16 +262,13 @@ public class MessageManager
|
|||||||
Locale locale = (Locale)locales.nextElement();
|
Locale locale = (Locale)locales.nextElement();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// java caches resource bundles, so we don't need to
|
// java caches resource bundles, so we don't need to reinvent the wheel here.
|
||||||
// reinvent the wheel here. however, java also falls back
|
// however, java also falls back from a specific bundle to a more general one
|
||||||
// from a specific bundle to a more general one if it
|
// if it can't find a specific bundle. that's real nice of it, but we want
|
||||||
// can't find a specific bundle. that's real nice of it,
|
// first to see whether or not we have exact matches on any of the preferred
|
||||||
// but we want first to see whether or not we have exact
|
// locales specified by the client. if we don't, then we can rely on java's
|
||||||
// matches on any of the preferred locales specified by
|
|
||||||
// the client. if we don't, then we can rely on java's
|
|
||||||
// fallback mechanisms
|
// fallback mechanisms
|
||||||
bundle = ResourceBundle.getBundle(
|
bundle = ResourceBundle.getBundle(bundlePath, locale, loader);
|
||||||
bundlePath, locale, loader);
|
|
||||||
|
|
||||||
// if it's an exact match, off we go
|
// if it's an exact match, off we go
|
||||||
if (bundle.getLocale().equals(locale)) {
|
if (bundle.getLocale().equals(locale)) {
|
||||||
@@ -296,28 +276,25 @@ public class MessageManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
} catch (MissingResourceException mre) {
|
} catch (MissingResourceException mre) {
|
||||||
// no need to freak out quite yet, see if we have
|
// no need to freak out quite yet, see if we have something for one of the
|
||||||
// something for one of the other preferred locales
|
// other preferred locales
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we were unable to find an exact match for any of the user's
|
// if we were unable to find an exact match for any of the user's preferred locales, take
|
||||||
// preferred locales, take their most preferred and let java
|
// their most preferred and let java perform it's fallback logic on that one
|
||||||
// perform it's fallback logic on that one
|
|
||||||
if (bundle == null) {
|
if (bundle == null) {
|
||||||
Locale locale = (req == null) ? _deflocale : req.getLocale();
|
Locale locale = (req == null) ? _deflocale : req.getLocale();
|
||||||
try {
|
try {
|
||||||
bundle = ResourceBundle.getBundle(bundlePath, locale, loader);
|
bundle = ResourceBundle.getBundle(bundlePath, locale, loader);
|
||||||
} catch (MissingResourceException mre) {
|
} catch (MissingResourceException mre) {
|
||||||
if (!silent) {
|
if (!silent) {
|
||||||
// if we were unable even to find a default bundle, we may
|
// if we were unable even to find a default bundle, we may want to log a
|
||||||
// want to log a warning
|
// warning
|
||||||
Log.warning("Unable to resolve any message bundle " +
|
Log.warning("Unable to resolve any message bundle [req=" + getURL(req) +
|
||||||
"[req=" + getURL(req) + ", locale=" + locale +
|
", locale=" + locale + ", bundlePath=" + bundlePath +
|
||||||
", bundlePath=" + bundlePath +
|
", classLoader=" + loader + ", siteBundlePath=" + _siteBundlePath +
|
||||||
", classLoader=" + loader +
|
|
||||||
", siteBundlePath=" + _siteBundlePath +
|
|
||||||
", siteLoader=" + _siteLoader + "].");
|
", siteLoader=" + _siteLoader + "].");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -341,23 +318,20 @@ public class MessageManager
|
|||||||
/** The path, relative to the classpath, to our resource bundles. */
|
/** The path, relative to the classpath, to our resource bundles. */
|
||||||
protected String _bundlePath;
|
protected String _bundlePath;
|
||||||
|
|
||||||
/** The path to the site-specific message bundles, fetched via the
|
/** The path to the site-specific message bundles, fetched via the site-specific resource
|
||||||
* site-specific resource loader. */
|
* loader. */
|
||||||
protected String _siteBundlePath;
|
protected String _siteBundlePath;
|
||||||
|
|
||||||
/** The resource loader with which to fetch our site-specific message
|
/** The resource loader with which to fetch our site-specific message bundles. */
|
||||||
* bundles. */
|
|
||||||
protected SiteResourceLoader _siteLoader;
|
protected SiteResourceLoader _siteLoader;
|
||||||
|
|
||||||
/** The site identifier we use to determine through which site a
|
/** The site identifier we use to determine through which site a request was made. */
|
||||||
* request was made. */
|
|
||||||
protected SiteIdentifier _siteIdent;
|
protected SiteIdentifier _siteIdent;
|
||||||
|
|
||||||
/** The locale to use if we are accessed without an HTTP request. */
|
/** The locale to use if we are accessed without an HTTP request. */
|
||||||
protected Locale _deflocale;
|
protected Locale _deflocale;
|
||||||
|
|
||||||
/** The attribute name that we use for caching resource bundles in
|
/** The attribute name that we use for caching resource bundles in request objects. */
|
||||||
* request objects. */
|
|
||||||
protected static final String BUNDLE_CACHE_PREFIX =
|
protected static final String BUNDLE_CACHE_PREFIX =
|
||||||
"com.samskivert.servlet.MessageManager:CachedResourceBundle:";
|
"com.samskivert.servlet.MessageManager:CachedResourceBundle:";
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user