Produces concatenated messages in language-neutral way. New code
should probably use
java.util.Formatter instead.
MessageFormat takes a set of objects, formats them and then
inserts the formatted strings into the pattern at the appropriate places.
Note:
MessageFormat differs from the other
Format classes in that you create a
MessageFormatobject with one of its constructors (not with a
getInstancestyle factory method). The factory methods aren't necessary because
MessageFormat itself doesn't implement locale-specific
behavior. Any locale-specific behavior is defined by the pattern that you
provide as well as the subformats used for inserted arguments.
MessageFormat uses patterns of the following form:
MessageFormatPattern:
String
MessageFormatPattern FormatElement String
FormatElement:
{ ArgumentIndex }
{ ArgumentIndex , FormatType }
{ ArgumentIndex , FormatType , FormatStyle }
FormatType: one of
number date time choice
FormatStyle:
short
medium
long
full
integer
currency
percent
SubformatPattern
String:
StringPart<sub>opt</sub>
String StringPart
StringPart:
''
' QuotedString '
UnquotedString
SubformatPattern:
SubformatPatternPart<sub>opt</sub>
SubformatPattern SubformatPatternPart
SubFormatPatternPart:
' QuotedPattern '
UnquotedPattern
Within a String,
"''" represents a single quote. A
QuotedString can contain arbitrary characters except single quotes;
the surrounding single quotes are removed. An UnquotedString can
contain arbitrary characters except single quotes and left curly brackets.
Thus, a string that should result in the formatted message "'{0}'" can be
written as
"'''{'0}''"} or
"'''{0}'''"}.
Within a SubformatPattern, different rules apply. A QuotedPattern
can contain arbitrary characters except single quotes, but the surrounding
single quotes are not removed, so they may be interpreted
by the subformat. For example,
"{1,number,$'#',##}"} will
produce a number format with the hash-sign quoted, with a result such as:
"$#31,45". An UnquotedPattern can contain arbitrary characters except
single quotes, but curly braces within it must be balanced. For example,
"ab {0} de"} and
"ab '' de"} are valid subformat
patterns, but
"ab {0'}' de"} and
"ab de"} are
not.
Warning:
The rules for using quotes within message format patterns unfortunately
have shown to be somewhat confusing. In particular, it isn't always obvious
to localizers whether single quotes need to be doubled or not. Make sure to
inform localizers about the rules, and tell them (for example, by using
comments in resource bundle source files) which strings will be processed by
MessageFormat. Note that localizers may need to use single quotes in
translated strings where the original version doesn't have them.
Note also that the simplest way to avoid the problem is to use the real
apostrophe (single quote) character \u2019 (') for human-readable text, and
to use the ASCII apostrophe (\u0027 ' ) only in program syntax, like quoting
in
MessageFormat. See the annotations for U+0027 Apostrophe in The Unicode
Standard.
The ArgumentIndex value is a non-negative integer written using the
digits '0' through '9', and represents an index into the
arguments array passed to the
format methods or
the result array returned by the
parse methods.
The FormatType and FormatStyle values are used to create a
Format instance for the format element. The following table
shows how the values map to
Format instances. Combinations not shown in the
table are illegal. A SubformatPattern must be a valid pattern string
for the
Format subclass used.
Format Type |
Format Style |
Subformat Created |
(none) |
null |
number |
(none) |
NumberFormat.getInstance(getLocale()) |
integer |
NumberFormat.getIntegerInstance(getLocale()) |
currency |
NumberFormat.getCurrencyInstance(getLocale()) |
percent |
NumberFormat.getPercentInstance(getLocale()) |
SubformatPattern |
new DecimalFormat(subformatPattern, new DecimalFormatSymbols(getLocale())) |
date |
(none) |
DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale()) |
short |
DateFormat.getDateInstance(DateFormat.SHORT, getLocale()) |
medium |
DateFormat.getDateInstance(DateFormat.DEFAULT, getLocale()) |
long |
DateFormat.getDateInstance(DateFormat.LONG, getLocale()) |
full |
DateFormat.getDateInstance(DateFormat.FULL, getLocale()) |
SubformatPattern |
new SimpleDateFormat(subformatPattern, getLocale()) |
time |
(none) |
DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale()) |
short |
DateFormat.getTimeInstance(DateFormat.SHORT, getLocale()) |
medium |
DateFormat.getTimeInstance(DateFormat.DEFAULT, getLocale()) |
long |
DateFormat.getTimeInstance(DateFormat.LONG, getLocale()) |
full |
DateFormat.getTimeInstance(DateFormat.FULL, getLocale()) |
SubformatPattern |
new SimpleDateFormat(subformatPattern, getLocale()) |
choice |
SubformatPattern |
new ChoiceFormat(subformatPattern) |
Usage Information
Here are some examples of usage:
Object[] arguments = {
Integer.valueOf(7), new Date(System.currentTimeMillis()),
"a disturbance in the Force"};
String result = MessageFormat.format(
"At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
arguments);
Output:
At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
Typically, the message format will come from resources, and the
arguments will be dynamically set at runtime.
Example 2:
Object[] testArgs = {Long.valueOf(3), "MyDisk"};
MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0} file(s).");
System.out.println(form.format(testArgs));
Output with different testArgs:
The disk "MyDisk" contains 0 file(s).
The disk "MyDisk" contains 1 file(s).
The disk "MyDisk" contains 1,273 file(s).
For more sophisticated patterns, you can use a
ChoiceFormat to
get output such as:
MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
double[] filelimits = {0,1,2};
String[] filepart = {"no files","one file","{0,number} files"};
ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
form.setFormatByArgumentIndex(0, fileform);
Object[] testArgs = {Long.valueOf(12373), "MyDisk"};
System.out.println(form.format(testArgs));
Output (with different testArgs):
The disk "MyDisk" contains no files.
The disk "MyDisk" contains one file.
The disk "MyDisk" contains 1,273 files.
You can either do this programmatically, as in the above
example, or by using a pattern (see
ChoiceFormat for more
information) as in:
form.applyPattern("There {0,choice,0#are no files|1#is one file|1<are {0,number,integer} files}.");
Note: As we see above, the string produced by a
ChoiceFormat in
MessageFormat is treated
specially; occurances of '{' are used to indicated subformats, and cause
recursion. If you create both a
MessageFormat and
ChoiceFormat programmatically (instead of using the string
patterns), then be careful not to produce a format that recurses on itself,
which will cause an infinite loop.
When a single argument is parsed more than once in the string, the last match
will be the final result of the parsing. For example:
MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
Object[] objs = {new Double(3.1415)};
String result = mf.format(objs);
// result now equals "3.14, 3.1"
objs = null;
objs = mf.parse(result, new ParsePosition(0));
// objs now equals {new Double(3.1)}
Likewise, parsing with a
MessageFormat object using patterns
containing multiple occurrences of the same argument would return the last
match. For example:
MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
String forParsing = "x, y, z";
Object[] objs = mf.parse(forParsing, new ParsePosition(0));
// result now equals {new String("z")}
Message formats are not synchronized. It is recommended to create separate
format instances for each thread. If multiple threads access a format
concurrently, it must be synchronized externally.