ChoiceFormat
class, you can map a
number to a word or a phrase, allowing you to construct grammatically
correct messages.
In English the plural and singular forms of a word are usually different. This can present a problem when you are constructing messages that refer to quantities. For example, if your message reports the number of files on a disk, the following variations are possible:
There are no files on XDisk. There is one file on XDisk. There are 2 files on XDisk.
The fastest way to solve this problem is to create a
MessageFormat
pattern like this:
There are {0,number} file(s) on {1}.
Unfortunately the preceding pattern results in incorrect grammar:
There are 1 file(s) on XDisk.
You can do better than that, provided that you use the
ChoiceFormat
class.
In this section you'll learn how to deal with plurals in a message by
stepping through a sample program called
ChoiceFormatDemo
.
This program also uses the MessageFormat
class, which is
discussed in the previous section, Dealing
with Compound Messages.
1. Define the Message Pattern
First, identify the variables in the message:
Next, replace the variables in the message with arguments, creating a
pattern that can be applied to a MessageFormat
object:
There {0} on {1}.
The argument for the disk name, which is represented by{1}
,
is easy enough to deal with. You just treat it like any other
String
variable in a MessageFormat
pattern.
This argument matches the element at index 1 in the array of argument
values. (See step 7.)
Dealing with argument{0}
is more complex, for a couple of reasons:
String
. For example, the number 1
will map to the String
containing the phrase is one
file
. The ChoiceFormat
class allows you to perform
the necessary mapping.
MessageFormat
class lets you insert a number
into a phrase.
ResourceBundle
:
ResourceBundle bundle = ResourceBundle.getBundle("ChoiceBundle", currentLocale);
The sample program backs the ResourceBundle
with
properties files. The
ChoiceBundle_en_US.properties
contains the following lines:
pattern = There {0} on {1}. noFiles = are no files oneFile = is one file multipleFiles = are {2} files
The contents of this properties file show how the message will be
constructed and formatted. The first line contains the pattern for
MessageFormat
. (See step 1.) The other lines contain
phrases that will replace argument {0}
in the pattern. The
phrase for the multipleFiles
key contains the argument
{2}
, which will be replaced by a number.
Here is the French version of the properties file,
ChoiceBundle_fr_FR.properties
pattern = Il {0} sur {1}. noFiles = n'y a pas de fichiers oneFile = y a un fichier multipleFiles = y a {2} fichiers
MessageFormat
and set its
Locale
:
MessageFormat messageForm = new MessageFormat(""); messageForm.setLocale(currentLocale);
ChoiceFormat
object allows you to choose, based on a
double
number, a particular String
. The
range of double
numbers, and the String
objects to which they map, are specified in arrays:
double[] fileLimits = {0,1,2}; String [] fileStrings = { bundle.getString("noFiles"), bundle.getString("oneFile"), bundle.getString("multipleFiles") };
ChoiceFormat
maps each element in the double
array to the element in the String
array that has the same
index. In the sample code the 0 maps to the String
returned by calling bundle.getString("noFiles")
.
By coincidence the index is the same as the value in the
fileLimits
array. If the code had set
fileLimits[0]
to seven, ChoiceFormat
would
map the number 7 to fileStrings[0]
.
You specify the double
and String
arrays when
instantiating ChoiceFormat
:
ChoiceFormat choiceForm = new ChoiceFormat(fileLimits, fileStrings);
ResourceBundle
and apply it to the
MessageFormat
object:
String pattern = bundle.getString("pattern"); messageForm.applyPattern(pattern);
MessageFormat
object the
ChoiceFormat
object created in step 4:
Format[] formats = {choiceForm, null, NumberFormat.getInstance()}; messageForm.setFormats(formats);
The setFormats
method assigns Format
objects
to the arguments in the message pattern. You must invoke the
applyPattern
method before you call the
setFormats
method. The following table shows how the
elements of the Format
array correspond to the arguments
in the message pattern:
Array Element | Pattern Argument |
---|---|
choiceForm
|
{0}
|
null
|
{1}
|
NumberFormat.getInstance()
|
{2}
|
MessageFormat
object. The elements in the
array correspond to the arguments in the pattern. For example,
messageArgument[1]
maps to pattern argument
{1}
, which is a String
containing the name of
the disk. In the previous step the program assigned a
ChoiceFormat
object to argument {0}
of the
pattern. Therefore the number assigned to
messageArgument[0]
determines which String
the ChoiceFormat
object selects. If
messageArgument[0]
is greater than or equal to 2, the
String
containing the phrase are {2} files
replaces argument {0}
in the pattern. The number assigned
to messageArgument[2]
will be substituted in place of
pattern argument {2}
. Here's the code that tries this
out:
Object[] messageArguments = {null, "XDisk", null}; for (int numFiles = 0; numFiles < 4; numFiles++) { messageArguments[0] = new Integer(numFiles); messageArguments[2] = new Integer(numFiles); String result = messageForm.format(messageArguments); System.out.println(result); }
ResourceBundle
of step 2. Notice that the
ChoiceFormat
object selects the correct phrase, which the
MessageFormat
object uses to construct the proper message.
The output of the ChoiceFormatDemo
program is as follows:
currentLocale = en_US There are no files on XDisk. There is one file on XDisk. There are 2 files on XDisk. There are 3 files on XDisk. currentLocale = fr_FR Il n'y a pas des fichiers sur XDisk. Il y a un fichier sur XDisk. Il y a 2 fichiers sur XDisk. Il y a 3 fichiers sur XDisk.