Formatting |
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:The fastest way to solve this problem is to create aThere are no files on XDisk. There is one file on XDisk. There are 2 files on XDisk.MessageFormat
pattern like this:Unfortunately, the preceding pattern results in incorrect grammar:There are {0,number} file(s) on {1}.You can do better than that, provided that you use theThere are 1 file(s) on XDisk.ChoiceFormat
class. In this section, you'll learn how to deal with plurals in a message by stepping through a sample program calledChoiceFormatDemo.java
. This program also makes use of theMessageFormat
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 aThere | are no files | on | XDisk | . There | is one file | on | XDisk | . There | are 2 files | on | XDisk | . |______________| |_______| ^ ^ | | variable variableMessageFormat
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 aMessageFormat
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:
- The phrase that this argument replaces varies with the number of files. To construct this phrase at run time, you need to map the number of files to a particular
String
. For example, the number 1 will map to theString
"is one file." TheChoiceFormat
class allows you to perform the necessary mapping.- If the disk contains multiple files then the phrase includes an integer. The
MessageFormat
class lets you insert a number into a phrase.2. Create a ResourceBundle
Because the message text must be translated, isolate it in aResourceBundle
:The example program backs theResourceBundle bundle = ResourceBundle.getBundle("ChoiceBundle",currentLocale);ResourceBundle
with properties files. TheChoiceBundle_en_US.properties
file contains the following lines:The contents of this properties file shows how the message will be constructed and formatted. The first line contains the pattern forpattern = There {0} on {1}. noFiles = are no files oneFile = is one file multipleFiles = are {2} filesMessageFormat
. (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 number.The French version of the properties file,
ChoiceBundle_fr_FR.properties
, is as follows:pattern = Il {0} sur {1}. noFiles = n' y a pas des fichiers oneFile = y a un fichier multipleFiles = y a {2} fichiers3. Create a Message Formatter
In this step you instantiateMessageFormat
and set itsLocale
:MessageFormat messageForm = new MessageFormat(""); messageForm.setLocale(currentLocale);4. Create a Choice Formatter
TheChoiceFormat
object allows you to choose, based on adouble
number, a particularString
. The range ofdouble
numbers, and theString
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 thedouble
array to the element in theString
array that has the same index. In the sample code, the 0 maps to theString
returned by callingbundle.getString("noFiles")
. By coincidence, the index is the same as the value in thefileLimits
array. If the code had setfileLimits[0]
to 7, thenChoiceFormat
would map the number 7 tofileStrings[0]
.You specify the
double
andString
arrays when instantiatingChoiceFormat
:ChoiceFormat choiceForm = new ChoiceFormat(fileLimits, fileStrings);5. Apply the Pattern
Remember the pattern you constructed in step 1? It's time to retrieve the pattern from theResourceBundle
and apply it to theMessageFormat
object:String pattern = bundle.getString("pattern"); messageForm.applyPattern(pattern);6. Assign the Formats
In this step, you assign theChoiceFormat
object created in step 4 to theMessageFormat
object:TheFormat[] formats = {choiceForm, null, NumberFormat.getInstance()}; messageForm.setFormats(formats);setFormats
method assignsFormat
objects to the arguments in the message pattern. You must invoke theapplyPattern
method before you call thesetFormats
method. The following table shows how the elements of theFormat
array correspond to the arguments in the message pattern:
Array Element Pattern Argument choiceForm
{0}
null
{1}
NumberFormat.getInstance()
{2}
7. Set the Arguments and Format the Message
At run time, the program assigns the variables to the array of arguments it passes to theMessageFormat
object. The elements in the array correspond to the arguments in the pattern. For example,messageArgument[1]
maps to pattern argument {1}, which is aString
containing the name of the disk. In the previous step, the program assigned aChoiceFormat
object to argument {0} of the pattern. Therefore, the number assigned tomessageArgument[0]
determines whichString
theChoiceFormat
object selects. IfmessageArgument[0]
is greater than or equal to 2, then theString
"are {2} files" replaces argument {0} in the pattern. The number assigned tomessageArgument[2]
will be substitued 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); }8. Run the Demo Program
Compare the messages displayed by the program with the phrases in theResourceBundle
of step 2. Notice that theChoiceFormat
object selects the correct phrase, which theMessageFormat
object uses to construct the proper message. The output of theChoiceFormatDemo
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.
Formatting |