zcommon/src/main/java/org/zkoss/text/MessageFormats.java
/* MessageFormats.java
Purpose:
Description:
History:
2002/02/08 11:03:32, Create, Tom M. Yeh.
Copyright (C) 2001 Potix Corporation. All Rights Reserved.
{{IS_RIGHT
This program is distributed under LGPL Version 2.1 in the hope that
it will be useful, but WITHOUT ANY WARRANTY.
}}IS_RIGHT
*/
package org.zkoss.text;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Collection;
import java.util.Locale;
import java.net.InetAddress;
import java.text.MessageFormat;
import org.zkoss.lang.Strings;
import org.zkoss.util.Locales;
/**
* The message formatting relevant utilities.
*
* <p>See also java.text.MessageFormat.
*
* @author tomyeh
*/
public class MessageFormats {
/** Creates a MessageFormat with the given pattern and uses it to
* format the given arguments.
*
* <p>An extension to java.text.MessageFormat.format by allowing
* to specify a Locale.
*
* @param locale the locale; null for {@link Locales#getCurrent}
*/
public static final String
format(String pattern, Object[] args, Locale locale) {
return getFormat(pattern, locale)
.format(args, new StringBuffer(), null).toString();
}
private static MessageFormat getFormat(String pattern, Locale locale) {
if (locale == null)
locale = getLocale();
return new MessageFormat(pattern, locale);
}
private static final Locale getLocale() {
return Locales.getCurrent();
}
/** Creates a MessageFormat with the given pattern and uses it to
* format the given arguments, by use of
* {@link Locales#getCurrent}.
*
* <p>Note: java.text.MessageFormat.format uses Locale.getDefault,
* which might not be correct in a multi-user environment.
*/
public static final String format(String pattern, Object[] args) {
return format(pattern, args, null);
}
/** Creates a MessageFormat with the given pattern and uses it to
* format the given arguments, by use of StringBuffer.
*
* <p>If you want to concatenate a sequence of formated string, use
* this method.
*/
public static final StringBuffer format(
StringBuffer result, String pattern, Object[] args, Locale locale) {
return getFormat(pattern, locale).format(args, result, null);
}
/** Creates a MessageFormat with the given pattern and uses it to
* format the given arguments, by use of StringBuffer and
* {@link Locales#getCurrent}.
*/
public static final StringBuffer format(
StringBuffer result, String pattern, Object[] args) {
return format(result, pattern, args, null);
}
/** Parses a pattern and converts it to the format of
* java.text.MessageFormat.
* Names are the first element of a substring enclosing with {}
* in the pattern.
*
* <p>Example: "{a} is {b,number} of {a}" will return
* <code>new NameInfo("{0} is {1,number} of {0}", {"a", "b"})</code>.
*
* @see #formatByName(String, Map, Locale)
*/
public static final NameInfo parseByName(String pattern) {
final Map<String,Integer> names = new LinkedHashMap<String,Integer>();
final int len = pattern.length();
final StringBuffer sb = new StringBuffer(len + 32);
int j = 0;
for (;;) {
final int k = Strings.anyOf(pattern, "'{", j);
if (k >= len) //not found
break; //done
final char cc = pattern.charAt(k);
if (cc == '\'') {
final int l = pattern.indexOf('\'', k + 1);
if (l < 0) //not found
break; //done
sb.append(pattern.substring(j, l + 1));
j = l + 1;
} else {
final int l = Strings.anyOf(pattern, ",}", k + 1);
if (l >= len) //not found
break; //done
final int m = pattern.indexOf('}', l);
if (m < 0) //not found
break; //done
final String nm = pattern.substring(k + 1, l);
Integer pos = names.get(nm);
if (pos == null) {
pos = new Integer(names.size());
names.put(nm, pos);
}
sb.append(pattern.substring(j, k + 1))
.append(pos).append(pattern.substring(l, m + 1));
j = m + 1;
}
}
if (j < len)
sb.append(pattern.substring(j));
return new NameInfo(sb.toString(), names.keySet());
}
/** The name info returned by {@link #parseByName}).
*/
public static class NameInfo {
/** The pattern in the format of java.text.MessageFormat. */
public final String pattern;
/** The name of relative position. */
public final String[] names;
NameInfo(String pattern, Collection<String> names) {
this.pattern = pattern;
this.names = names.toArray(new String[names.size()]);
}
NameInfo(String pattern, String[] names) {
this.pattern = pattern;
this.names = names;
}
}
/** Formats a pattern by substituting names, enclosing with {}, with
* values found in the giving map.
*
* <p>This is an extension to java.text.MessageFormat.
* The only difference is that this method use arbitrary name
* instead of a number. For example, it use {name} instead of {0}.
* The quotation rule and formating pattern are the same as
* java.text.MessageFormat. Example, {var,number,$'#',###}.
*
* <p>It actually uses {@link #parseByName} to convert names to numbers,
* and then passes to java.text.MessageFormat.
*
* @param locale the locale; null for
* {@link Locales#getCurrent}
* @exception IllegalArgumentException if the pattern is invalid
* @see #parseByName
*/
public static final String
formatByName(String pattern, Map<String, ?> mapping, Locale locale) {
final NameInfo ni = parseByName(pattern);
final Object[] args = new Object[ni.names.length];
for (int j = args.length; --j >= 0;)
args[j] = mapping.get(ni.names[j]);
return format(ni.pattern, args, locale);
}
/** Formats a pattern by substituting names with values found in
* the giving map, by use of
* {@link Locales#getCurrent}.
*
* @see #parseByName
*/
public static final String formatByName(String pattern, Map<String, ?> mapping) {
return formatByName(pattern, mapping, null);
}
}