2 *******************************************************************************
\r
3 * Copyright (C) 2004-2008, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.text;
\r
9 import java.lang.reflect.InvocationTargetException;
\r
10 import java.lang.reflect.Method;
\r
11 import java.text.FieldPosition;
\r
12 import java.text.Format;
\r
13 import java.text.ParseException;
\r
14 import java.text.ParsePosition;
\r
15 import java.util.Locale;
\r
17 import com.ibm.icu.util.ULocale;
\r
20 * <code>MessageFormat</code> provides a means to produce concatenated
\r
21 * messages in language-neutral way. Use this to construct messages
\r
22 * displayed for end users.
\r
25 * <code>MessageFormat</code> takes a set of objects, formats them, then
\r
26 * inserts the formatted strings into the pattern at the appropriate places.
\r
29 * <strong>Note:</strong>
\r
30 * <code>MessageFormat</code> differs from the other <code>Format</code>
\r
31 * classes in that you create a <code>MessageFormat</code> object with one
\r
32 * of its constructors (not with a <code>getInstance</code> style factory
\r
33 * method). The factory methods aren't necessary because <code>MessageFormat</code>
\r
34 * itself doesn't implement locale specific behavior. Any locale specific
\r
35 * behavior is defined by the pattern that you provide as well as the
\r
36 * subformats used for inserted arguments.
\r
38 * <h4><a name="patterns">Patterns and Their Interpretation</a></h4>
\r
40 * <code>MessageFormat</code> uses patterns of the following form:
\r
42 * <i>MessageFormatPattern:</i>
\r
44 * <i>MessageFormatPattern</i> <i>FormatElement</i> <i>String</i>
\r
46 * <i>FormatElement:</i>
\r
47 * { <i>ArgumentIndex</i> }
\r
48 * { <i>ArgumentIndex</i> , <i>FormatType</i> }
\r
49 * { <i>ArgumentIndex</i> , <i>FormatType</i> , <i>FormatStyle</i> }
\r
51 * <i>FormatType: one of </i>
\r
52 * number date time choice
\r
54 * <i>FormatStyle:</i>
\r
62 * <i>SubformatPattern</i>
\r
65 * <i>StringPart<sub>opt</sub></i>
\r
66 * <i>String</i> <i>StringPart</i>
\r
68 * <i>StringPart:</i>
\r
70 * ' <i>QuotedString</i> '
\r
71 * <i>UnquotedString</i>
\r
73 * <i>SubformatPattern:</i>
\r
74 * <i>SubformatPatternPart<sub>opt</sub></i>
\r
75 * <i>SubformatPattern</i> <i>SubformatPatternPart</i>
\r
77 * <i>SubFormatPatternPart:</i>
\r
78 * ' <i>QuotedPattern</i> '
\r
79 * <i>UnquotedPattern</i>
\r
80 * </pre></blockquote>
\r
83 * Within a <i>String</i>, <code>"''"</code> represents a single
\r
84 * quote. A <i>QuotedString</i> can contain arbitrary characters
\r
85 * except single quotes; the surrounding single quotes are removed.
\r
86 * An <i>UnquotedString</i> can contain arbitrary characters
\r
87 * except single quotes and left curly brackets. Thus, a string that
\r
88 * should result in the formatted message "'{0}'" can be written as
\r
89 * <code>"'''{'0}''"</code> or <code>"'''{0}'''"</code>.
\r
91 * Within a <i>SubformatPattern</i>, different rules apply.
\r
92 * A <i>QuotedPattern</i> can contain arbitrary characters
\r
93 * except single quotes; but the surrounding single quotes are
\r
94 * <strong>not</strong> removed, so they may be interpreted by the
\r
95 * subformat. For example, <code>"{1,number,$'#',##}"</code> will
\r
96 * produce a number format with the pound-sign quoted, with a result
\r
97 * such as: "$#31,45".
\r
98 * An <i>UnquotedPattern</i> can contain arbitrary characters
\r
99 * except single quotes, but curly braces within it must be balanced.
\r
100 * For example, <code>"ab {0} de"</code> and <code>"ab '}' de"</code>
\r
101 * are valid subformat patterns, but <code>"ab {0'}' de"</code> and
\r
102 * <code>"ab } de"</code> are not.
\r
104 * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
\r
105 * format patterns unfortunately have shown to be somewhat confusing.
\r
106 * In particular, it isn't always obvious to localizers whether single
\r
107 * quotes need to be doubled or not. Make sure to inform localizers about
\r
108 * the rules, and tell them (for example, by using comments in resource
\r
109 * bundle source files) which strings will be processed by MessageFormat.
\r
110 * Note that localizers may need to use single quotes in translated
\r
111 * strings where the original version doesn't have them.
\r
112 * <br>Note also that the simplest way to avoid the problem is to
\r
113 * use the real apostrophe (single quote) character \u2019 (') for
\r
114 * human-readable text, and to use the ASCII apostrophe (\u0027 ' )
\r
115 * only in program syntax, like quoting in MessageFormat.
\r
116 * See the annotations for U+0027 Apostrophe in The Unicode Standard.</p>
\r
119 * The <i>ArgumentIndex</i> value is a non-negative integer written
\r
120 * using the digits '0' through '9', and represents an index into the
\r
121 * <code>arguments</code> array passed to the <code>format</code> methods
\r
122 * or the result array returned by the <code>parse</code> methods.
\r
124 * The <i>FormatType</i> and <i>FormatStyle</i> values are used to create
\r
125 * a <code>Format</code> instance for the format element. The following
\r
126 * table shows how the values map to Format instances. Combinations not
\r
127 * shown in the table are illegal. A <i>SubformatPattern</i> must
\r
128 * be a valid pattern string for the Format subclass used.
\r
134 * <th>Subformat Created
\r
136 * <td colspan=2><i>(none)</i>
\r
137 * <td><code>null</code>
\r
139 * <td rowspan=5><code>number</code>
\r
140 * <td><i>(none)</i>
\r
141 * <td><code>NumberFormat.getInstance(getLocale())</code>
\r
143 * <td><code>integer</code>
\r
144 * <td><code>NumberFormat.getIntegerInstance(getLocale())</code>
\r
146 * <td><code>currency</code>
\r
147 * <td><code>NumberFormat.getCurrencyInstance(getLocale())</code>
\r
149 * <td><code>percent</code>
\r
150 * <td><code>NumberFormat.getPercentInstance(getLocale())</code>
\r
152 * <td><i>SubformatPattern</i>
\r
153 * <td><code>new DecimalFormat(subformatPattern, new DecimalFormatSymbols(getLocale()))</code>
\r
155 * <td rowspan=6><code>date</code>
\r
156 * <td><i>(none)</i>
\r
157 * <td><code>DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale())</code>
\r
159 * <td><code>short</code>
\r
160 * <td><code>DateFormat.getDateInstance(DateFormat.SHORT, getLocale())</code>
\r
162 * <td><code>medium</code>
\r
163 * <td><code>DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale())</code>
\r
165 * <td><code>long</code>
\r
166 * <td><code>DateFormat.getDateInstance(DateFormat.LONG, getLocale())</code>
\r
168 * <td><code>full</code>
\r
169 * <td><code>DateFormat.getDateInstance(DateFormat.FULL, getLocale())</code>
\r
171 * <td><i>SubformatPattern</i>
\r
172 * <td><code>new SimpleDateFormat(subformatPattern, getLocale())
\r
174 * <td rowspan=6><code>time</code>
\r
175 * <td><i>(none)</i>
\r
176 * <td><code>DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale())</code>
\r
178 * <td><code>short</code>
\r
179 * <td><code>DateFormat.getTimeInstance(DateFormat.SHORT, getLocale())</code>
\r
181 * <td><code>medium</code>
\r
182 * <td><code>DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale())</code>
\r
184 * <td><code>long</code>
\r
185 * <td><code>DateFormat.getTimeInstance(DateFormat.LONG, getLocale())</code>
\r
187 * <td><code>full</code>
\r
188 * <td><code>DateFormat.getTimeInstance(DateFormat.FULL, getLocale())</code>
\r
190 * <td><i>SubformatPattern</i>
\r
191 * <td><code>new SimpleDateFormat(subformatPattern, getLocale())
\r
193 * <td><code>choice</code>
\r
194 * <td><i>SubformatPattern</i>
\r
195 * <td><code>new ChoiceFormat(subformatPattern)</code>
\r
199 * <h4>Usage Information</h4>
\r
202 * Here are some examples of usage:
\r
205 * Object[] arguments = {
\r
207 * new Date(System.currentTimeMillis()),
\r
208 * "a disturbance in the Force"
\r
211 * String result = MessageFormat.format(
\r
212 * "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
\r
215 * <em>output</em>: At 12:30 PM on Jul 3, 2053, there was a disturbance
\r
216 * in the Force on planet 7.
\r
220 * Typically, the message format will come from resources, and the
\r
221 * arguments will be dynamically set at runtime.
\r
227 * Object[] testArgs = {new Long(3), "MyDisk"};
\r
229 * MessageFormat form = new MessageFormat(
\r
230 * "The disk \"{1}\" contains {0} file(s).");
\r
232 * System.out.println(form.format(testArgs));
\r
234 * // output, with different testArgs
\r
235 * <em>output</em>: The disk "MyDisk" contains 0 file(s).
\r
236 * <em>output</em>: The disk "MyDisk" contains 1 file(s).
\r
237 * <em>output</em>: The disk "MyDisk" contains 1,273 file(s).
\r
242 * For more sophisticated patterns, you can use a <code>ChoiceFormat</code> to get
\r
246 * MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
\r
247 * double[] filelimits = {0,1,2};
\r
248 * String[] filepart = {"no files","one file","{0,number} files"};
\r
249 * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
\r
250 * form.setFormatByArgumentIndex(0, fileform);
\r
252 * Object[] testArgs = {new Long(12373), "MyDisk"};
\r
254 * System.out.println(form.format(testArgs));
\r
256 * // output, with different testArgs
\r
257 * output: The disk "MyDisk" contains no files.
\r
258 * output: The disk "MyDisk" contains one file.
\r
259 * output: The disk "MyDisk" contains 1,273 files.
\r
262 * You can either do this programmatically, as in the above example,
\r
263 * or by using a pattern (see
\r
264 * {@link ChoiceFormat}
\r
265 * for more information) as in:
\r
268 * form.applyPattern(
\r
269 * "There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.");
\r
273 * <strong>Note:</strong> As we see above, the string produced
\r
274 * by a <code>ChoiceFormat</code> in <code>MessageFormat</code> is treated specially;
\r
275 * occurances of '{' are used to indicated subformats, and cause recursion.
\r
276 * If you create both a <code>MessageFormat</code> and <code>ChoiceFormat</code>
\r
277 * programmatically (instead of using the string patterns), then be careful not to
\r
278 * produce a format that recurses on itself, which will cause an infinite loop.
\r
280 * When a single argument is parsed more than once in the string, the last match
\r
281 * will be the final result of the parsing. For example,
\r
283 * MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
\r
284 * Object[] objs = {new Double(3.1415)};
\r
285 * String result = mf.format( objs );
\r
286 * // result now equals "3.14, 3.1"
\r
288 * objs = mf.parse(result, new ParsePosition(0));
\r
289 * // objs now equals {new Double(3.1)}
\r
292 * Likewise, parsing with a MessageFormat object using patterns containing
\r
293 * multiple occurances of the same argument would return the last match. For
\r
296 * MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
\r
297 * String forParsing = "x, y, z";
\r
298 * Object[] objs = mf.parse(forParsing, new ParsePosition(0));
\r
299 * // result now equals {new String("z")}
\r
302 * <h4><a name="synchronization">Synchronization</a></h4>
\r
305 * Message formats are not synchronized.
\r
306 * It is recommended to create separate format instances for each thread.
\r
307 * If multiple threads access a format concurrently, it must be synchronized
\r
310 * @see java.util.Locale
\r
312 * @see NumberFormat
\r
313 * @see DecimalFormat
\r
314 * @see ChoiceFormat
\r
315 * @author Mark Davis
\r
318 public class MessageFormat extends Format {
\r
319 static final long serialVersionUID = 1L;
\r
324 public final java.text.MessageFormat messageFormat;
\r
328 * @param delegate the DateFormat to which to delegate
\r
330 public MessageFormat(java.text.MessageFormat delegate) {
\r
331 this.messageFormat = delegate;
\r
335 * Constructs a MessageFormat for the default locale and the
\r
336 * specified pattern.
\r
337 * The constructor first sets the locale, then parses the pattern and
\r
338 * creates a list of subformats for the format elements contained in it.
\r
339 * Patterns and their interpretation are specified in the
\r
340 * <a href="#patterns">class description</a>.
\r
342 * @param pattern the pattern for this message format
\r
343 * @exception IllegalArgumentException if the pattern is invalid
\r
346 public MessageFormat(String pattern) {
\r
347 this(new java.text.MessageFormat(pattern));
\r
351 * Constructs a MessageFormat for the specified locale and
\r
353 * The constructor first sets the locale, then parses the pattern and
\r
354 * creates a list of subformats for the format elements contained in it.
\r
355 * Patterns and their interpretation are specified in the
\r
356 * <a href="#patterns">class description</a>.
\r
358 * @param pattern the pattern for this message format
\r
359 * @param locale the locale for this message format
\r
360 * @exception IllegalArgumentException if the pattern is invalid
\r
363 public MessageFormat(String pattern, Locale locale) {
\r
364 // locale is ignored
\r
365 this(new java.text.MessageFormat(pattern));
\r
369 * Constructs a MessageFormat for the specified locale and
\r
371 * The constructor first sets the locale, then parses the pattern and
\r
372 * creates a list of subformats for the format elements contained in it.
\r
373 * Patterns and their interpretation are specified in the
\r
374 * <a href="#patterns">class description</a>.
\r
376 * @param pattern the pattern for this message format
\r
377 * @param locale the locale for this message format
\r
378 * @exception IllegalArgumentException if the pattern is invalid
\r
381 public MessageFormat(String pattern, ULocale locale) {
\r
382 // locale is ignored
\r
387 * Sets the locale to be used when creating or comparing subformats.
\r
388 * This affects subsequent calls to the {@link #applyPattern applyPattern}
\r
389 * and {@link #toPattern toPattern} methods as well as to the
\r
390 * <code>format</code> and
\r
391 * {@link #formatToCharacterIterator formatToCharacterIterator} methods.
\r
393 * @param locale the locale to be used when creating or comparing subformats
\r
396 public void setLocale(Locale locale) {
\r
397 messageFormat.setLocale(locale);
\r
401 * Sets the locale to be used when creating or comparing subformats.
\r
402 * This affects subsequent calls to the {@link #applyPattern applyPattern}
\r
403 * and {@link #toPattern toPattern} methods as well as to the
\r
404 * <code>format</code> and
\r
405 * {@link #formatToCharacterIterator formatToCharacterIterator} methods.
\r
407 * @param locale the locale to be used when creating or comparing subformats
\r
410 public void setLocale(ULocale locale) {
\r
411 messageFormat.setLocale(locale.toLocale());
\r
415 * Gets the locale that's used when creating or comparing subformats.
\r
417 * @return the locale used when creating or comparing subformats
\r
420 public Locale getLocale() {
\r
421 return messageFormat.getLocale();
\r
425 * Gets the locale that's used when creating or comparing subformats.
\r
427 * @return the locale used when creating or comparing subformats
\r
430 public ULocale getULocale() {
\r
431 return ULocale.forLocale(messageFormat.getLocale());
\r
435 * Sets the pattern used by this message format.
\r
436 * The method parses the pattern and creates a list of subformats
\r
437 * for the format elements contained in it.
\r
438 * Patterns and their interpretation are specified in the
\r
439 * <a href="#patterns">class description</a>.
\r
441 * @param pattern the pattern for this message format
\r
442 * @exception IllegalArgumentException if the pattern is invalid
\r
445 public void applyPattern(String pattern) {
\r
446 messageFormat.applyPattern(pattern);
\r
450 * Returns a pattern representing the current state of the message format.
\r
451 * The string is constructed from internal information and therefore
\r
452 * does not necessarily equal the previously applied pattern.
\r
454 * @return a pattern representing the current state of the message format
\r
457 public String toPattern() {
\r
458 return messageFormat.toPattern();
\r
462 * Sets the formats to use for the values passed into
\r
463 * <code>format</code> methods or returned from <code>parse</code>
\r
464 * methods. The indices of elements in <code>newFormats</code>
\r
465 * correspond to the argument indices used in the previously set
\r
467 * The order of formats in <code>newFormats</code> thus corresponds to
\r
468 * the order of elements in the <code>arguments</code> array passed
\r
469 * to the <code>format</code> methods or the result array returned
\r
470 * by the <code>parse</code> methods.
\r
472 * If an argument index is used for more than one format element
\r
473 * in the pattern string, then the corresponding new format is used
\r
474 * for all such format elements. If an argument index is not used
\r
475 * for any format element in the pattern string, then the
\r
476 * corresponding new format is ignored. If fewer formats are provided
\r
477 * than needed, then only the formats for argument indices less
\r
478 * than <code>newFormats.length</code> are replaced.
\r
480 * @param newFormats the new formats to use
\r
481 * @exception NullPointerException if <code>newFormats</code> is null
\r
483 * @throws UnsupportedOperationException if the underlying JVM does not
\r
484 * support this method.
\r
486 public void setFormatsByArgumentIndex(Format[] newFormats) {
\r
487 if (sfsbai == null) {
\r
488 synchronized (missing) {
\r
490 Class[] params = { Format[].class };
\r
491 sfsbai = java.text.MessageFormat.class.getMethod("setFormatsByArgumentIndex", params);
\r
493 catch (NoSuchMethodException e) {
\r
498 if (sfsbai != missing) {
\r
500 Format[] unwrapped = new Format[newFormats.length];
\r
501 for (int i = 0; i < newFormats.length; ++i) {
\r
502 unwrapped[i] = unwrap(newFormats[i]);
\r
504 Object[] args = { unwrapped };
\r
505 ((Method)sfsbai).invoke(messageFormat, args);
\r
508 catch (IllegalAccessException e) {
\r
511 catch (InvocationTargetException e) {
\r
515 throw new UnsupportedOperationException();
\r
517 private static Object sfsbai;
\r
520 * Sets the formats to use for the format elements in the
\r
521 * previously set pattern string.
\r
522 * The order of formats in <code>newFormats</code> corresponds to
\r
523 * the order of format elements in the pattern string.
\r
525 * If more formats are provided than needed by the pattern string,
\r
526 * the remaining ones are ignored. If fewer formats are provided
\r
527 * than needed, then only the first <code>newFormats.length</code>
\r
528 * formats are replaced.
\r
530 * Since the order of format elements in a pattern string often
\r
531 * changes during localization, it is generally better to use the
\r
532 * {@link #setFormatsByArgumentIndex setFormatsByArgumentIndex}
\r
533 * method, which assumes an order of formats corresponding to the
\r
534 * order of elements in the <code>arguments</code> array passed to
\r
535 * the <code>format</code> methods or the result array returned by
\r
536 * the <code>parse</code> methods.
\r
538 * @param newFormats the new formats to use
\r
539 * @exception NullPointerException if <code>newFormats</code> is null
\r
542 public void setFormats(Format[] newFormats) {
\r
543 messageFormat.setFormats(newFormats);
\r
547 * Sets the format to use for the format elements within the
\r
548 * previously set pattern string that use the given argument
\r
550 * The argument index is part of the format element definition and
\r
551 * represents an index into the <code>arguments</code> array passed
\r
552 * to the <code>format</code> methods or the result array returned
\r
553 * by the <code>parse</code> methods.
\r
555 * If the argument index is used for more than one format element
\r
556 * in the pattern string, then the new format is used for all such
\r
557 * format elements. If the argument index is not used for any format
\r
558 * element in the pattern string, then the new format is ignored.
\r
560 * @param argumentIndex the argument index for which to use the new format
\r
561 * @param newFormat the new format to use
\r
563 * @throws UnsupportedOperationException if the underlying JVM does not
\r
564 * support this method.
\r
566 public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) {
\r
567 if (sfbai == null) {
\r
568 synchronized (missing) {
\r
570 Class[] params = { Integer.TYPE, Format.class };
\r
571 sfbai = java.text.MessageFormat.class.getMethod("setFormatByArgumentIndex", params);
\r
573 catch (NoSuchMethodException e) {
\r
578 if (sfbai != missing) {
\r
580 Object[] args = { new Integer(argumentIndex), newFormat };
\r
581 ((Method)sfbai).invoke(messageFormat, args);
\r
584 catch (IllegalAccessException e) {
\r
587 catch (InvocationTargetException e) {
\r
591 throw new UnsupportedOperationException();
\r
593 private static Object sfbai;
\r
596 * Sets the format to use for the format element with the given
\r
597 * format element index within the previously set pattern string.
\r
598 * The format element index is the zero-based number of the format
\r
599 * element counting from the start of the pattern string.
\r
601 * Since the order of format elements in a pattern string often
\r
602 * changes during localization, it is generally better to use the
\r
603 * {@link #setFormatByArgumentIndex setFormatByArgumentIndex}
\r
604 * method, which accesses format elements based on the argument
\r
605 * index they specify.
\r
607 * @param formatElementIndex the index of a format element within the pattern
\r
608 * @param newFormat the format to use for the specified format element
\r
609 * @exception ArrayIndexOutOfBoundsException if formatElementIndex is equal to or
\r
610 * larger than the number of format elements in the pattern string
\r
613 public void setFormat(int formatElementIndex, Format newFormat) {
\r
614 messageFormat.setFormat(formatElementIndex, unwrap(newFormat));
\r
618 * Gets the formats used for the values passed into
\r
619 * <code>format</code> methods or returned from <code>parse</code>
\r
620 * methods. The indices of elements in the returned array
\r
621 * correspond to the argument indices used in the previously set
\r
623 * The order of formats in the returned array thus corresponds to
\r
624 * the order of elements in the <code>arguments</code> array passed
\r
625 * to the <code>format</code> methods or the result array returned
\r
626 * by the <code>parse</code> methods.
\r
628 * If an argument index is used for more than one format element
\r
629 * in the pattern string, then the format used for the last such
\r
630 * format element is returned in the array. If an argument index
\r
631 * is not used for any format element in the pattern string, then
\r
632 * null is returned in the array.
\r
634 * @return the formats used for the arguments within the pattern
\r
636 * @throws UnsupportedOperationException if the underlying JVM does not
\r
637 * support this method.
\r
639 public Format[] getFormatsByArgumentIndex() {
\r
640 if (gfbai == null) {
\r
641 synchronized (missing) {
\r
643 gfbai = java.text.MessageFormat.class.getMethod("getFormatsByArgumentIndex", null);
\r
645 catch (NoSuchMethodException e) {
\r
650 if (gfbai != missing) {
\r
652 Format[] result = (Format[])((Method)gfbai).invoke(messageFormat, null);
\r
653 for (int i = 0; i < result.length; ++i) {
\r
654 result[i] = wrap(result[i]);
\r
658 catch (IllegalAccessException e) {
\r
661 catch (InvocationTargetException e) {
\r
665 throw new UnsupportedOperationException();
\r
667 private static Object gfbai;
\r
668 private static final Object missing = new Object();
\r
671 * Gets the formats used for the format elements in the
\r
672 * previously set pattern string.
\r
673 * The order of formats in the returned array corresponds to
\r
674 * the order of format elements in the pattern string.
\r
676 * Since the order of format elements in a pattern string often
\r
677 * changes during localization, it's generally better to use the
\r
678 * {@link #getFormatsByArgumentIndex getFormatsByArgumentIndex}
\r
679 * method, which assumes an order of formats corresponding to the
\r
680 * order of elements in the <code>arguments</code> array passed to
\r
681 * the <code>format</code> methods or the result array returned by
\r
682 * the <code>parse</code> methods.
\r
684 * @return the formats used for the format elements in the pattern
\r
687 public Format[] getFormats() {
\r
688 Format[] result = messageFormat.getFormats();
\r
689 for (int i = 0; i < result.length; ++i) {
\r
690 result[i] = wrap(result[i]);
\r
696 * Formats an array of objects and appends the <code>MessageFormat</code>'s
\r
697 * pattern, with format elements replaced by the formatted objects, to the
\r
698 * provided <code>StringBuffer</code>.
\r
700 * The text substituted for the individual format elements is derived from
\r
701 * the current subformat of the format element and the
\r
702 * <code>arguments</code> element at the format element's argument index
\r
703 * as indicated by the first matching line of the following table. An
\r
704 * argument is <i>unavailable</i> if <code>arguments</code> is
\r
705 * <code>null</code> or has fewer than argumentIndex+1 elements.
\r
711 * <th>Formatted Text
\r
714 * <td><i>unavailable</i>
\r
715 * <td><code>"{" + argumentIndex + "}"</code>
\r
718 * <td><code>null</code>
\r
719 * <td><code>"null"</code>
\r
721 * <td><code>instanceof ChoiceFormat</code>
\r
723 * <td><code>subformat.format(argument).indexOf('{') >= 0 ?<br>
\r
724 * (new MessageFormat(subformat.format(argument), getLocale())).format(argument) :
\r
725 * subformat.format(argument)</code>
\r
727 * <td><code>!= null</code>
\r
729 * <td><code>subformat.format(argument)</code>
\r
731 * <td><code>null</code>
\r
732 * <td><code>instanceof Number</code>
\r
733 * <td><code>NumberFormat.getInstance(getLocale()).format(argument)</code>
\r
735 * <td><code>null</code>
\r
736 * <td><code>instanceof Date</code>
\r
737 * <td><code>DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, getLocale()).format(argument)</code>
\r
739 * <td><code>null</code>
\r
740 * <td><code>instanceof String</code>
\r
741 * <td><code>argument</code>
\r
743 * <td><code>null</code>
\r
745 * <td><code>argument.toString()</code>
\r
748 * If <code>pos</code> is non-null, and refers to
\r
749 * <code>Field.ARGUMENT</code>, the location of the first formatted
\r
750 * string will be returned.
\r
752 * @param arguments an array of objects to be formatted and substituted.
\r
753 * @param result where text is appended.
\r
754 * @param pos On input: an alignment field, if desired.
\r
755 * On output: the offsets of the alignment field.
\r
756 * @exception IllegalArgumentException if an argument in the
\r
757 * <code>arguments</code> array is not of the type
\r
758 * expected by the format element(s) that use it.
\r
761 public final StringBuffer format(Object[] arguments, StringBuffer result,
\r
764 return messageFormat.format(arguments, result, pos);
\r
768 * Creates a MessageFormat with the given pattern and uses it
\r
769 * to format the given arguments. This is equivalent to
\r
771 * <code>(new {@link #MessageFormat(String) MessageFormat}(pattern)).{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
\r
774 * @exception IllegalArgumentException if the pattern is invalid,
\r
775 * or if an argument in the <code>arguments</code> array
\r
776 * is not of the type expected by the format element(s)
\r
780 public static String format(String pattern, Object[] arguments) {
\r
781 return java.text.MessageFormat.format(pattern, arguments);
\r
786 * Formats an array of objects and appends the <code>MessageFormat</code>'s
\r
787 * pattern, with format elements replaced by the formatted objects, to the
\r
788 * provided <code>StringBuffer</code>.
\r
789 * This is equivalent to
\r
791 * <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}((Object[]) arguments, result, pos)</code>
\r
794 * @param arguments an array of objects to be formatted and substituted.
\r
795 * @param result where text is appended.
\r
796 * @param pos On input: an alignment field, if desired.
\r
797 * On output: the offsets of the alignment field.
\r
798 * @exception IllegalArgumentException if an argument in the
\r
799 * <code>arguments</code> array is not of the type
\r
800 * expected by the format element(s) that use it.
\r
803 public final StringBuffer format(Object arguments, StringBuffer result,
\r
806 return messageFormat.format(arguments, result, pos);
\r
811 * Parses the string.
\r
813 * <p>Caveats: The parse may fail in a number of circumstances.
\r
816 * <li>If one of the arguments does not occur in the pattern.
\r
817 * <li>If the format of an argument loses information, such as
\r
818 * with a choice format where a large number formats to "many".
\r
819 * <li>Does not yet handle recursion (where
\r
820 * the substituted strings contain {n} references.)
\r
821 * <li>Will not always find a match (or the correct match)
\r
822 * if some part of the parse is ambiguous.
\r
823 * For example, if the pattern "{1},{2}" is used with the
\r
824 * string arguments {"a,b", "c"}, it will format as "a,b,c".
\r
825 * When the result is parsed, it will return {"a", "b,c"}.
\r
826 * <li>If a single argument is parsed more than once in the string,
\r
827 * then the later parse wins.
\r
829 * When the parse fails, use ParsePosition.getErrorIndex() to find out
\r
830 * where in the string did the parsing failed. The returned error
\r
831 * index is the starting offset of the sub-patterns that the string
\r
832 * is comparing with. For example, if the parsing string "AAA {0} BBB"
\r
833 * is comparing against the pattern "AAD {0} BBB", the error index is
\r
834 * 0. When an error occurs, the call to this method will return null.
\r
835 * If the source is null, return an empty array.
\r
838 public Object[] parse(String source, ParsePosition pos) {
\r
839 return messageFormat.parse(source, pos);
\r
843 * Parses text from the beginning of the given string to produce an object
\r
845 * The method may not use the entire text of the given string.
\r
847 * See the {@link #parse(String, ParsePosition)} method for more information
\r
848 * on message parsing.
\r
850 * @param source A <code>String</code> whose beginning should be parsed.
\r
851 * @return An <code>Object</code> array parsed from the string.
\r
852 * @exception ParseException if the beginning of the specified string
\r
853 * cannot be parsed.
\r
856 public Object[] parse(String source) throws ParseException {
\r
857 return messageFormat.parse(source);
\r
861 * Parses text from a string to produce an object array.
\r
863 * The method attempts to parse text starting at the index given by
\r
864 * <code>pos</code>.
\r
865 * If parsing succeeds, then the index of <code>pos</code> is updated
\r
866 * to the index after the last character used (parsing does not necessarily
\r
867 * use all characters up to the end of the string), and the parsed
\r
868 * object array is returned. The updated <code>pos</code> can be used to
\r
869 * indicate the starting point for the next call to this method.
\r
870 * If an error occurs, then the index of <code>pos</code> is not
\r
871 * changed, the error index of <code>pos</code> is set to the index of
\r
872 * the character where the error occurred, and null is returned.
\r
874 * See the {@link #parse(String, ParsePosition)} method for more information
\r
875 * on message parsing.
\r
877 * @param source A <code>String</code>, part of which should be parsed.
\r
878 * @param pos A <code>ParsePosition</code> object with index and error
\r
879 * index information as described above.
\r
880 * @return An <code>Object</code> array parsed from the string. In case of
\r
881 * error, returns null.
\r
882 * @exception NullPointerException if <code>pos</code> is null.
\r
885 public Object parseObject(String source, ParsePosition pos) {
\r
886 return messageFormat.parse(source, pos);
\r
890 * Convert an 'apostrophe-friendly' pattern into a standard
\r
891 * pattern. Standard patterns treat all apostrophes as
\r
892 * quotes, which is problematic in some languages, e.g.
\r
893 * French, where apostrophe is commonly used. This utility
\r
894 * assumes that only an unpaired apostrophe immediately before
\r
895 * a brace is a true quote. Other unpaired apostrophes are paired,
\r
896 * and the resulting standard pattern string is returned.
\r
898 * <p><b>Note</b> it is not guaranteed that the returned pattern
\r
899 * is indeed a valid pattern. The only effect is to convert
\r
900 * between patterns having different quoting semantics.
\r
902 * @param pattern the 'apostrophe-friendly' patttern to convert
\r
903 * @return the standard equivalent of the original pattern
\r
906 public static String autoQuoteApostrophe(String pattern) {
\r
907 StringBuffer buf = new StringBuffer(pattern.length()*2);
\r
908 int state = STATE_INITIAL;
\r
909 int braceCount = 0;
\r
910 for (int i = 0, j = pattern.length(); i < j; ++i) {
\r
911 char c = pattern.charAt(i);
\r
913 case STATE_INITIAL:
\r
916 state = STATE_SINGLE_QUOTE;
\r
918 case CURLY_BRACE_LEFT:
\r
919 state = STATE_MSG_ELEMENT;
\r
924 case STATE_SINGLE_QUOTE:
\r
927 state = STATE_INITIAL;
\r
929 case CURLY_BRACE_LEFT:
\r
930 case CURLY_BRACE_RIGHT:
\r
931 state = STATE_IN_QUOTE;
\r
934 buf.append(SINGLE_QUOTE);
\r
935 state = STATE_INITIAL;
\r
939 case STATE_IN_QUOTE:
\r
942 state = STATE_INITIAL;
\r
946 case STATE_MSG_ELEMENT:
\r
948 case CURLY_BRACE_LEFT:
\r
951 case CURLY_BRACE_RIGHT:
\r
952 if (--braceCount == 0) {
\r
953 state = STATE_INITIAL;
\r
958 default: // Never happens.
\r
964 if (state == STATE_SINGLE_QUOTE || state == STATE_IN_QUOTE) {
\r
965 buf.append(SINGLE_QUOTE);
\r
967 return new String(buf);
\r
971 * Creates and returns a copy of this object.
\r
973 * @return a clone of this instance.
\r
976 public Object clone() {
\r
977 return new MessageFormat((java.text.MessageFormat)messageFormat.clone());
\r
981 * Equality comparison between two message format objects
\r
984 public boolean equals(Object obj) {
\r
986 return messageFormat.equals(((MessageFormat)obj).messageFormat);
\r
988 catch (Exception e) {
\r
994 * Generates a hash code for the message format object.
\r
997 public int hashCode() {
\r
998 return messageFormat.hashCode();
\r
1002 * Return a string suitable for debugging.
\r
1003 * @return a string suitable for debugging
\r
1004 * @stable ICU 3.4.2
\r
1006 public String toString() {
\r
1007 return messageFormat.toPattern();
\r
1010 private static Format unwrap(Format f) {
\r
1011 if (f instanceof DateFormat) {
\r
1012 return ((DateFormat)f).dateFormat;
\r
1013 } else if (f instanceof NumberFormat) {
\r
1014 return ((NumberFormat)f).numberFormat;
\r
1015 } else if (f instanceof MessageFormat) {
\r
1016 return ((MessageFormat)f).messageFormat;
\r
1022 private static Format wrap(Format f) {
\r
1023 if (f instanceof java.text.DateFormat) {
\r
1024 return new DateFormat((java.text.DateFormat)f);
\r
1025 } else if (f instanceof java.text.DecimalFormat) {
\r
1026 return new DecimalFormat((java.text.DecimalFormat)f);
\r
1027 } else if (f instanceof java.text.MessageFormat) {
\r
1028 return new MessageFormat((java.text.MessageFormat)f);
\r
1034 private static final char SINGLE_QUOTE = '\'';
\r
1035 private static final char CURLY_BRACE_LEFT = '{';
\r
1036 private static final char CURLY_BRACE_RIGHT = '}';
\r
1038 private static final int STATE_INITIAL = 0;
\r
1039 private static final int STATE_SINGLE_QUOTE = 1;
\r
1040 private static final int STATE_IN_QUOTE = 2;
\r
1041 private static final int STATE_MSG_ELEMENT = 3;
\r