diff --git a/src/java/com/threerings/util/MessageBundle.java b/src/java/com/threerings/util/MessageBundle.java index 44eb146f3..74acae36b 100644 --- a/src/java/com/threerings/util/MessageBundle.java +++ b/src/java/com/threerings/util/MessageBundle.java @@ -1,5 +1,5 @@ // -// $Id: MessageBundle.java,v 1.2 2002/02/09 01:35:26 mdb Exp $ +// $Id: MessageBundle.java,v 1.3 2002/02/28 23:13:54 mdb Exp $ package com.threerings.util; @@ -38,6 +38,12 @@ public class MessageBundle */ public String get (String key) { + // if this string is tainted, we don't translate it, instead we + // simply remove the taint character and return it to the caller + if (key.startsWith(TAINT_CHAR)) { + return key.substring(1); + } + try { return _bundle.getString(key); @@ -132,22 +138,128 @@ public class MessageBundle { // to be more efficient about creating unnecessary objects, we // do some checking before splitting - int tidx = compoundKey.indexOf("\t"); + int tidx = compoundKey.indexOf('|'); if (tidx == -1) { return get(compoundKey); } else { String key = compoundKey.substring(0, tidx); String argstr = compoundKey.substring(tidx+1); - String[] args = StringUtil.split(argstr, "\t"); + String[] args = StringUtil.split(argstr, "|"); + // unescape and translate the arguments + for (int i = 0; i < args.length; i++) { + args[i] = xlate(unescape(args[i])); + } return get(key, args); } } + /** + * Call this to "taint" any string that has been entered by an entity + * outside the application so that the translation code knows not to + * attempt to translate this string when doing recursive translations + * ({@see #xlate}). + */ + public static String taint (String text) + { + return TAINT_CHAR + text; + } + + /** + * Composes a message key with an array of arguments. The message can + * subsequently be translated in a single call using {@link #xlate}. + */ + public static String compose (String key, String[] args) + { + StringBuffer buf = new StringBuffer(); + buf.append(key); + buf.append('|'); + for (int i = 0; i < args.length; i++) { + if (i > 0) { + buf.append('|'); + } + // escape the string while adding to the buffer + String arg = args[i]; + int alength = arg.length(); + for (int p = 0; p < alength; p++) { + char ch = arg.charAt(p); + if (ch == '|') { + buf.append("\\!"); + } else if (ch == '\\') { + buf.append("\\\\"); + } else { + buf.append(ch); + } + } + } + return buf.toString(); + } + + /** + * Unescapes characters that are escaped in a call to compose. + */ + protected static String unescape (String value) + { + int bsidx = value.indexOf('\\'); + if (bsidx == -1) { + return value; + } + + StringBuffer buf = new StringBuffer(); + int vlength = value.length(); + for (int i = 0; i < vlength; i++) { + char ch = value.charAt(i); + if (ch != '\\') { + buf.append(ch); + } else if (i < vlength-1) { + // look at the next character + ch = value.charAt(++i); + buf.append((ch == '!') ? '|' : ch); + } else { + buf.append(ch); + } + } + + return buf.toString(); + } + + /** + * A convenience method for calling {@link #compose(String,String[])} + * with a single argument. + */ + public static String compose (String key, String arg) + { + return compose(key, new String[] { arg }); + } + + /** + * A convenience method for calling {@link #compose(String,String[])} + * with two arguments. + */ + public static String compose (String key, String arg1, String arg2) + { + return compose(key, new String[] { arg1, arg2 }); + } + + /** + * A convenience method for calling {@link #compose(String,String[])} + * with three arguments. + */ + public static String compose ( + String key, String arg1, String arg2, String arg3) + { + return compose(key, new String[] { arg1, arg2, arg3 }); + } + /** 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; + + /** Text prefixed by this character will be considered tainted when + * doing recursive translations and won't be translated. */ + protected static final String TAINT_CHAR = "~"; + // protected static final String TAINT_CHAR = '~'; }