001: /* MessageFormats.java
002:
003: {{IS_NOTE
004:
005: Purpose:
006: Description:
007: History:
008: 2002/02/08 11:03:32, Create, Tom M. Yeh.
009: }}IS_NOTE
010:
011: Copyright (C) 2001 Potix Corporation. All Rights Reserved.
012:
013: {{IS_RIGHT
014: This program is distributed under GPL Version 2.0 in the hope that
015: it will be useful, but WITHOUT ANY WARRANTY.
016: }}IS_RIGHT
017: */
018: package org.zkoss.text;
019:
020: import java.util.LinkedList;
021: import java.util.List;
022: import java.util.Map;
023: import java.util.HashMap;
024: import java.util.LinkedHashMap;
025: import java.util.Collection;
026: import java.util.Locale;
027: import java.net.InetAddress;
028: import java.text.MessageFormat;
029:
030: import org.zkoss.lang.D;
031: import org.zkoss.lang.Strings;
032: import org.zkoss.util.Locales;
033:
034: /**
035: * The message formatting relevant utilities.
036: *
037: * <p>See also java.text.MessageFormat.
038: *
039: * @author tomyeh
040: */
041: public class MessageFormats {
042: /** Creates a MessageFormat with the given pattern and uses it to
043: * format the given arguments.
044: *
045: * <p>An extension to java.text.MessageFormat.format by allowing
046: * to specify a Locale.
047: *
048: * @param locale the locale; null for {@link Locales#getCurrent}
049: */
050: public static final String format(String pattern, Object[] args,
051: Locale locale) {
052: return getFormat(pattern, locale).format(args,
053: new StringBuffer(), null).toString();
054: }
055:
056: private static MessageFormat getFormat(String pattern, Locale locale) {
057: if (locale == null)
058: locale = getLocale();
059: return new MessageFormat(pattern, locale);
060: }
061:
062: private static final Locale getLocale() {
063: return Locales.getCurrent();
064: }
065:
066: /** Creates a MessageFormat with the given pattern and uses it to
067: * format the given arguments, by use of
068: * {@link Locales#getCurrent}.
069: *
070: * <p>Note: java.text.MessageFormat.format uses Locale.getDefault,
071: * which might not be corrent in a multi-user environment.
072: */
073: public static final String format(String pattern, Object[] args) {
074: return format(pattern, args, null);
075: }
076:
077: /** Creates a MessageFormat with the given pattern and uses it to
078: * format the given arguments, by use of StringBuffer.
079: *
080: * <p>If you want to catenate a sequence of formated string, use
081: * this method.
082: */
083: public static final StringBuffer format(StringBuffer result,
084: String pattern, Object[] args, Locale locale) {
085: return getFormat(pattern, locale).format(args, result, null);
086: }
087:
088: /** Creates a MessageFormat with the given pattern and uses it to
089: * format the given arguments, by use of StringBuffer and
090: * {@link Locales#getCurrent}.
091: */
092: public static final StringBuffer format(StringBuffer result,
093: String pattern, Object[] args) {
094: return format(result, pattern, args, null);
095: }
096:
097: /** Parses a pattern and converts it to the format of
098: * java.text.MessageFormat.
099: * Names are the first element of a substring enclosing with {}
100: * in the pattern.
101: *
102: * <p>Example: "{a} is {b,number} of {a}" will return
103: * <code>new NameInfo("{0} is {1,number} of {0}", {"a", "b"})</code>.
104: *
105: * @see #formatByName(String, Map, Locale)
106: */
107: public static final NameInfo parseByName(String pattern) {
108: final Map names = new LinkedHashMap();
109: final int len = pattern.length();
110: final StringBuffer sb = new StringBuffer(len + 32);
111: int j = 0;
112: for (;;) {
113: final int k = Strings.anyOf(pattern, "'{", j);
114: if (k >= len) //not found
115: break; //done
116:
117: final char cc = pattern.charAt(k);
118: if (cc == '\'') {
119: final int l = pattern.indexOf('\'', k + 1);
120: if (l < 0) //not found
121: break; //done
122:
123: sb.append(pattern.substring(j, l + 1));
124: j = l + 1;
125: } else {
126: final int l = Strings.anyOf(pattern, ",}", k + 1);
127: if (l >= len) //not found
128: break; //done
129: final int m = pattern.indexOf('}', l);
130: if (m < 0) //not found
131: break; //done
132:
133: final String nm = pattern.substring(k + 1, l);
134: Integer pos = (Integer) names.get(nm);
135: if (pos == null) {
136: pos = new Integer(names.size());
137: names.put(nm, pos);
138: }
139: sb.append(pattern.substring(j, k + 1)).append(pos)
140: .append(pattern.substring(l, m + 1));
141: j = m + 1;
142: }
143: }
144: if (j < len)
145: sb.append(pattern.substring(j));
146: return new NameInfo(sb.toString(), names.keySet());
147: }
148:
149: /** The name info returned by {@link #parseByName}).
150: */
151: public static class NameInfo {
152: /** The pattern in the format of java.text.MessageFormat. */
153: public final String pattern;
154: /** The name of relative position. */
155: public final String[] names;
156:
157: NameInfo(String pattern, Collection names) {
158: this .pattern = pattern;
159: this .names = (String[]) names.toArray(new String[names
160: .size()]);
161: }
162:
163: NameInfo(String pattern, String[] names) {
164: this .pattern = pattern;
165: this .names = names;
166: }
167: }
168:
169: /** Formats a pattern by substituting names, enclosing with {}, with
170: * values found in the giving map.
171: *
172: * <p>This is an extension to java.text.MessageFormat.
173: * The only difference is that this method use arbitrary name
174: * instead of a number. For example, it use {name} instead of {0}.
175: * The quotation rule and formating pattern are the same as
176: * java.text.MessageFormat. Example, {var,number,$'#',###}.
177: *
178: * <p>It actually uses {@link #parseByName} to convert names to numbers,
179: * and then passes to java.text.MessageFormat.
180: *
181: * @param locale the locale; null for
182: * {@link Locales#getCurrent}
183: * @exception IllegalArgumentException if the pattern is invalid
184: * @see #parseByName
185: */
186: public static final String formatByName(String pattern,
187: Map mapping, Locale locale) {
188: final NameInfo ni = parseByName(pattern);
189: final Object[] args = new Object[ni.names.length];
190: for (int j = args.length; --j >= 0;)
191: args[j] = mapping.get(ni.names[j]);
192: return format(ni.pattern, args, locale);
193: }
194:
195: /** Formats a pattern by substituting names with values found in
196: * the giving map, by use of
197: * {@link Locales#getCurrent}.
198: *
199: * @see #parseByName
200: */
201: public static final String formatByName(String pattern, Map mapping) {
202: return formatByName(pattern, mapping, null);
203: }
204: }
|