ICU-5903 support pluralformat in message pattern

(there are a number of whitespace changes in these files where trailing
whitespace was deleted, sorry)

X-SVN-Rev: 24369
This commit is contained in:
Doug Felt 2008-07-10 18:47:56 +00:00
parent b4515acba5
commit ff8a03216d
4 changed files with 191 additions and 123 deletions

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2007, International Business Machines Corporation and *
* Copyright (C) 2007-2008, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -12,6 +12,8 @@ import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.text.*;
import com.ibm.icu.util.ULocale;
import java.text.ChoiceFormat;
import java.text.Format;
import java.text.ParsePosition;
/**
@ -22,7 +24,7 @@ public class PluralFormatUnitTest extends TestFmwk {
public static void main(String[] args) throws Exception {
new PluralFormatUnitTest().run(args);
}
public void TestConstructor() {
// Test correct formatting of numbers.
PluralFormat plFmts[] = new PluralFormat[8];
@ -40,7 +42,7 @@ public class PluralFormatUnitTest extends TestFmwk {
PluralRules.DEFAULT,
"other{#}");
plFmts[7] = new PluralFormat(ULocale.getDefault(), "other{#}");
// These plural formats should produce the same output as a
// NumberFormat for the default locale.
NumberFormat numberFmt = NumberFormat.getInstance(ULocale.getDefault());
@ -60,7 +62,7 @@ public class PluralFormatUnitTest extends TestFmwk {
}
}
}
public void TestApplyPatternAndFormat() {
// Create rules for testing.
PluralRules oddAndEven = PluralRules.createRules("odd: n mod 2 is 1");
@ -68,11 +70,11 @@ public class PluralFormatUnitTest extends TestFmwk {
// Test full specified case for testing RuleSet
PluralFormat plfOddAndEven = new PluralFormat(oddAndEven);
plfOddAndEven.applyPattern("odd{# is odd.} other{# is even.}");
// Test fall back to other.
PluralFormat plfOddOrEven = new PluralFormat(oddAndEven);
plfOddOrEven.applyPattern("other{# is odd or even.}");
NumberFormat numberFormat =
NumberFormat.getInstance(ULocale.getDefault());
for (int i = 0; i < 22; ++i) {
@ -84,7 +86,7 @@ public class PluralFormatUnitTest extends TestFmwk {
: " is even."),
plfOddAndEven.format(i));
}
// Check that double definition results in an exception.
try {
PluralFormat plFmt = new PluralFormat(oddAndEven);
@ -103,26 +105,26 @@ public class PluralFormatUnitTest extends TestFmwk {
try {
PluralFormat plFmt = new PluralFormat(oddAndEven);
plFmt.applyPattern("odd{foo}");
errln("Not defining plural case other should result in an " +
errln("Not defining plural case other should result in an " +
"exception but did not.");
}catch (IllegalArgumentException e){}
// Test unknown keyword.
try {
PluralFormat plFmt = new PluralFormat(oddAndEven);
plFmt.applyPattern("otto{foo} other{bar}");
errln("Defining a message for an unknown keyword should result in" +
errln("Defining a message for an unknown keyword should result in" +
"an exception but did not.");
}catch (IllegalArgumentException e){}
// Test invalid keyword.
try {
PluralFormat plFmt = new PluralFormat(oddAndEven);
plFmt.applyPattern("1odd{foo} other{bar}");
errln("Defining a message for an invalid keyword should result in" +
errln("Defining a message for an invalid keyword should result in" +
"an exception but did not.");
}catch (IllegalArgumentException e){}
// Test invalid syntax
// -- comma between keyword{message} clauses
// -- space in keywords
@ -130,7 +132,7 @@ public class PluralFormatUnitTest extends TestFmwk {
try {
PluralFormat plFmt = new PluralFormat(oddAndEven);
plFmt.applyPattern("odd{foo},other{bar}");
errln("Separating keyword{message} items with other characters " +
errln("Separating keyword{message} items with other characters " +
"than space should provoke an exception but did not.");
}catch (IllegalArgumentException e){}
try {
@ -145,7 +147,7 @@ public class PluralFormatUnitTest extends TestFmwk {
errln("Defining multiple messages after a keyword should provoke " +
"an exception but did not.");
}catch (IllegalArgumentException e){}
// Check that nested format is preserved.
{
PluralFormat plFmt = new PluralFormat(oddAndEven);
@ -153,8 +155,8 @@ public class PluralFormatUnitTest extends TestFmwk {
"other{The number {0, number, #.#0} is even.}");
for (int i = 1; i < 3; ++i) {
assertEquals("format did not preserve a nested format string.",
((i % 2 == 1) ?
"The number {0, number, #.#0} is odd."
((i % 2 == 1) ?
"The number {0, number, #.#0} is odd."
: "The number {0, number, #.#0} is even."),
plFmt.format(i));
}
@ -167,18 +169,18 @@ public class PluralFormatUnitTest extends TestFmwk {
"other{The number {#} is even.}");
for (int i = 1; i < 3; ++i) {
assertEquals("format did not preserve # inside curly braces.",
((i % 2 == 1) ? "The number {#} is odd."
((i % 2 == 1) ? "The number {#} is odd."
: "The number {#} is even."),
plFmt.format(i));
}
}
}
public void TestSetLocale() {
// Create rules for testing.
PluralRules oddAndEven = PluralRules.createRules("odd__: n mod 2 is 1");
PluralFormat plFmt = new PluralFormat(oddAndEven);
plFmt.applyPattern("odd__{odd} other{even}");
plFmt.setLocale(ULocale.ENGLISH);
@ -188,7 +190,7 @@ public class PluralFormatUnitTest extends TestFmwk {
assertEquals("pattern was not resetted by setLocale() call.",
nrFmt.format(5),
plFmt.format(5));
// Check that rules got updated.
try {
plFmt.applyPattern("odd__{odd} other{even}");
@ -204,9 +206,8 @@ public class PluralFormatUnitTest extends TestFmwk {
((i==1) ? "one" : "not one"),
plFmt.format(i));
}
}
public void TestParse() {
PluralFormat plFmt = new PluralFormat("other{test}");
try {
@ -215,7 +216,7 @@ public class PluralFormatUnitTest extends TestFmwk {
"did not");
} catch (UnsupportedOperationException e) {
}
plFmt = new PluralFormat("other{test}");
try {
plFmt.parseObject("test", new ParsePosition(0));
@ -224,4 +225,29 @@ public class PluralFormatUnitTest extends TestFmwk {
} catch (UnsupportedOperationException e) {
}
}
public void TestPattern() {
Object[] args = { "acme", null };
{
PluralFormat pf = new PluralFormat(" one {one ''widget} other {# widgets} ");
String pat = pf.toPattern();
logln("pf pattern: '" + pat + "'");
assertEquals("no leading spaces", "o", pat.substring(0, 1));
assertEquals("no trailing spaces", "}", pat.substring(pat.length() - 1));
}
MessageFormat pfmt = new MessageFormat("The disk ''{0}'' contains {1, plural, one {one ''''{1, number, #.0}'''' widget} other {# widgets}}.");
System.out.println();
for (int i = 0; i < 3; ++i) {
args[1] = new Integer(i);
logln(pfmt.format(args));
}
PluralFormat pf = (PluralFormat)pfmt.getFormatsByArgumentIndex()[1];
logln(pf.toPattern());
logln(pfmt.toPattern());
MessageFormat pfmt2 = new MessageFormat(pfmt.toPattern());
assertEquals("message formats are equal", pfmt, pfmt2);
}
}

View File

@ -1293,6 +1293,25 @@ public class TestMessageFormat extends com.ibm.icu.dev.test.TestFmwk {
}
}
// Test toPattern when there is a PluralFormat
public void testPluralFormatToPattern() {
String[] patterns = {
"Beware of vicious {0, plural, one {hamster} other {hamsters}}.",
"{0, plural, one {{0, number,C''''est #,##0.0# fichier}} other {Ce sont # fichiers}} dans la liste.",
"{0, plural, one {C''est # fichier} other {Ce sont # fichiers}} dans la liste.",
};
for (int i = 0; i < patterns.length; ++i) {
String pattern = patterns[i];
MessageFormat mf = new MessageFormat(pattern);
MessageFormat mf2 = new MessageFormat(mf.toPattern());
if (!mf.equals(mf2)) {
errln("message formats not equal for pattern:\n*** '" + pattern + "'\n*** '" +
mf.toPattern() + "'");
}
}
}
//#if defined(FOUNDATION10) || defined(J2SE13)
//#else
// Test case for formatToCharacterIterator

View File

@ -59,28 +59,28 @@ import com.ibm.icu.util.ULocale;
* <p>
* <strong>Note:</strong>
* In ICU 3.8 MessageFormat supports named arguments. If a named argument
* is used, all arguments must be named. Names start with a character in
* <code>:ID_START:</code> and continue with characters in <code>:ID_CONTINUE:</code>,
* is used, all arguments must be named. Names start with a character in
* <code>:ID_START:</code> and continue with characters in <code>:ID_CONTINUE:</code>,
* in particular they do not start with a digit. If named arguments
* are used, {@link #usesNamedArguments()} will return true.
* <p>
* The other new APIs supporting named arguments are
* The other new APIs supporting named arguments are
* {@link #setFormatsByArgumentName(Map)},
* {@link #setFormatByArgumentName(String, Format)},
* {@link #format(Map, StringBuffer, FieldPosition)},
* {@link #format(String, Map)}, {@link #parseToMap(String, ParsePosition)},
* and {@link #parseToMap(String)}. These APIs are all compatible
* and {@link #parseToMap(String)}. These APIs are all compatible
* with patterns that do not used named arguments-- in these cases
* the keys in the input or output <code>Map</code>s use
* <code>String</code>s that name the argument indices, e.g. "0",
* the keys in the input or output <code>Map</code>s use
* <code>String</code>s that name the argument indices, e.g. "0",
* "1", "2"... etc.
* <p>
* When named arguments are used, certain APIs on Message that take or
* return arrays will throw an exception, since it is not possible to
* identify positions in an array using a name. These APIs are {@link
* #setFormatsByArgumentIndex(Format[])}, {@link #getFormatsByArgumentIndex()},
* {@link #format(Object[], StringBuffer, FieldPosition)},
* {@link #format(String, Object[])},{@link #parse(String, ParsePosition)},
* #setFormatsByArgumentIndex(Format[])}, {@link #getFormatsByArgumentIndex()},
* {@link #format(Object[], StringBuffer, FieldPosition)},
* {@link #format(String, Object[])},{@link #parse(String, ParsePosition)},
* and {@link #parse(String)}.
* These APIs all have corresponding new versions as listed above.
* <p>
@ -593,7 +593,7 @@ public class MessageFormat extends UFormat {
/**
* Returns a pattern representing the current state of the message format.
* The string is constructed from internal information and therefore
* does not necessarily equal the previously applied pattern.
* does not necessarily equal the previously applied pattern.
*
* @return a pattern representing the current state of the message format
* @stable ICU 3.0
@ -652,9 +652,20 @@ public class MessageFormat extends UFormat {
result.append(",choice,"
+ ((ChoiceFormat) formats[i]).toPattern());
} else if (formats[i] instanceof PluralFormat) {
// TODO: Implement PluralFormat.toPattern().
result.append(", plural, support for converting PluralFormat "
+ "to pattern not yet available.");
String pattern = ((PluralFormat)formats[i]).toPattern();
// TODO: PluralFormat doesn't do the single quote thing, just reapply
if (pattern.indexOf('\'') != 0) {
StringBuffer buf = new StringBuffer();
for (int j = 0; j < pattern.length(); ++j) {
char ch = pattern.charAt(j);
if (ch == '\'') {
buf.append(ch); // double it
}
buf.append(ch);
}
pattern = buf.toString();
}
result.append(",plural," + pattern);
} else {
//result.append(", unknown");
}
@ -682,10 +693,10 @@ public class MessageFormat extends UFormat {
* corresponding new format is ignored. If fewer formats are provided
* than needed, then only the formats for argument indices less
* than <code>newFormats.length</code> are replaced.
*
*
* This method is only supported if the format does not use
* named arguments, otherwise an IllegalArgumentException is thrown.
*
*
* @param newFormats
* the new formats to use
* @throws NullPointerException
@ -693,7 +704,7 @@ public class MessageFormat extends UFormat {
* @throws IllegalArgumentException
* if this formatter uses named arguments
* @stable ICU 3.0
*/
*/
public void setFormatsByArgumentIndex(Format[] newFormats) {
if (!argumentNamesAreNumeric) {
throw new IllegalArgumentException(
@ -707,7 +718,7 @@ public class MessageFormat extends UFormat {
}
}
}
/**
* Sets the formats to use for the values passed into
* <code>format</code> methods or returned from <code>parse</code>
@ -784,10 +795,10 @@ public class MessageFormat extends UFormat {
* in the pattern string, then the new format is used for all such
* format elements. If the argument index is not used for any format
* element in the pattern string, then the new format is ignored.
*
*
* This method is only supported when exclusively numbers are used for
* argument names. Otherwise an IllegalArgumentException is thrown.
*
*
* @param argumentIndex
* the argument index for which to use the new format
* @param newFormat
@ -874,10 +885,10 @@ public class MessageFormat extends UFormat {
* format element is returned in the array. If an argument index
* is not used for any format element in the pattern string, then
* null is returned in the array.
*
*
* This method is only supported when exclusively numbers are used for
* argument names. Otherwise an IllegalArgumentException is thrown.
*
*
* @return the formats used for the arguments within the pattern
* @throws IllegalArgumentException
* if this format uses named arguments
@ -886,7 +897,7 @@ public class MessageFormat extends UFormat {
public Format[] getFormatsByArgumentIndex() {
if (!argumentNamesAreNumeric) {
throw new IllegalArgumentException(
"This method is not available in MessageFormat objects " +
"This method is not available in MessageFormat objects " +
"that use alphanumeric argument names.");
}
int maximumArgumentNumber = -1;
@ -904,7 +915,7 @@ public class MessageFormat extends UFormat {
}
// TODO: provide method public Map getFormatsByArgumentName().
// Where Map is: String argumentName --> Format format.
/**
* Gets the formats used for the format elements in the
* previously set pattern string.
@ -921,7 +932,7 @@ public class MessageFormat extends UFormat {
*
* This method is only supported when exclusively numbers are used for
* argument names. Otherwise an IllegalArgumentException is thrown.
*
*
* @return the formats used for the format elements in the pattern
* @stable ICU 3.0
*/
@ -991,7 +1002,7 @@ public class MessageFormat extends UFormat {
*
* This method is only supported when the format does not use named
* arguments, otherwise an IllegalArgumentException is thrown.
*
*
* @param arguments an array of objects to be formatted and substituted.
* @param result where text is appended.
* @param pos On input: an alignment field, if desired.
@ -1005,7 +1016,7 @@ public class MessageFormat extends UFormat {
*/
public final StringBuffer format(Object[] arguments, StringBuffer result,
FieldPosition pos)
{
{
if (!argumentNamesAreNumeric) {
throw new IllegalArgumentException(
"This method is not available in MessageFormat objects " +
@ -1021,7 +1032,7 @@ public class MessageFormat extends UFormat {
* <p>
* The text substituted for the individual format elements is derived from
* the current subformat of the format element and the
* <code>arguments</code> value corresopnding to the format element's
* <code>arguments</code> value corresopnding to the format element's
* argument name.
* <p>
* This API may be called on formats that do not use named arguments.
@ -1047,7 +1058,7 @@ public class MessageFormat extends UFormat {
FieldPosition pos) {
return subformat(arguments, result, pos, null);
}
/**
* Creates a MessageFormat with the given pattern and uses it
* to format the given arguments. This is equivalent to
@ -1102,7 +1113,7 @@ public class MessageFormat extends UFormat {
* Formats a map or array of objects and appends the <code>MessageFormat</code>'s
* pattern, with format elements replaced by the formatted objects, to the
* provided <code>StringBuffer</code>.
* This is equivalent to either of
* This is equivalent to either of
* <blockquote>
* <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}((Object[]) arguments, result, pos)</code>
* <code>{@link #format(java.util.Map, java.lang.StringBuffer, java.text.FieldPosition) format}((Map) arguments, result, pos)</code>
@ -1128,7 +1139,7 @@ public class MessageFormat extends UFormat {
} else {
if (!argumentNamesAreNumeric) {
throw new IllegalArgumentException(
"This method is not available in MessageFormat objects " +
"This method is not available in MessageFormat objects " +
"that use alphanumeric argument names.");
}
return subformat((Object[]) arguments, result, pos, null);
@ -1224,7 +1235,7 @@ public class MessageFormat extends UFormat {
* This method is only supported with numbered arguments. If
* the format pattern used named argument an
* IllegalArgumentException is thrown.
*
*
* @throws IllegalArgumentException if this format uses named arguments
* @stable ICU 3.0
*/
@ -1242,21 +1253,21 @@ public class MessageFormat extends UFormat {
maximumArgumentNumber = argumentNumber;
}
}
if (objectMap == null) {
return null;
}
Object[] resultArray = new Object[maximumArgumentNumber + 1];
Iterator keyIter = objectMap.keySet().iterator();
while (keyIter.hasNext()) {
String key = (String) keyIter.next();
resultArray[Integer.parseInt(key)] = objectMap.get(key);
}
return resultArray;
}
/**
* Parses the string, returning the results in a Map.
* This is similar to the version that returns an array
@ -1286,7 +1297,7 @@ public class MessageFormat extends UFormat {
// Object[] resultArray = new Object[maximumArgumentNumber + 1];
Map resultMap = new HashMap();
int patternOffset = 0;
int sourceOffset = pos.getIndex();
ParsePosition tempStatus = new ParsePosition(0);
@ -1323,14 +1334,14 @@ public class MessageFormat extends UFormat {
String strValue = source.substring(sourceOffset, next);
if (!strValue.equals("{" + argumentNames[i] + "}"))
resultMap.put(argumentNames[i], source.substring(sourceOffset, next));
// resultArray[Integer.parseInt(argumentNames[i])] =
// resultArray[Integer.parseInt(argumentNames[i])] =
// source.substring(sourceOffset, next);
sourceOffset = next;
}
} else {
tempStatus.setIndex(sourceOffset);
resultMap.put(argumentNames[i], formats[i].parseObject(source, tempStatus));
// resultArray[Integer.parseInt(argumentNames[i])] =
// resultArray[Integer.parseInt(argumentNames[i])] =
// formats[i].parseObject(source, tempStatus);
if (tempStatus.getIndex() == sourceOffset) {
pos.setErrorIndex(sourceOffset);
@ -1375,7 +1386,7 @@ public class MessageFormat extends UFormat {
return result;
}
/**
* Parses text from the beginning of the given string to produce a map from
* argument to values. The method may not use the entire text of the given string.
@ -1385,13 +1396,13 @@ public class MessageFormat extends UFormat {
*
* @param source A <code>String</code> whose beginning should be parsed.
* @return A <code>Map</code> parsed from the string.
* @throws ParseException if the beginning of the specified string cannot
* @throws ParseException if the beginning of the specified string cannot
* be parsed.
* @see #parseToMap(String, ParsePosition)
* @stable ICU 3.8
*/
public Map parseToMap(String source) throws ParseException {
ParsePosition pos = new ParsePosition(0);
Map result = parseToMap(source, pos);
if (pos.getIndex() == 0) // unchanged, returned object is null
@ -1400,7 +1411,7 @@ public class MessageFormat extends UFormat {
return result;
}
/**
* Parses text from a string to produce an object array or Map.
* <p>
@ -1432,7 +1443,7 @@ public class MessageFormat extends UFormat {
if (argumentNamesAreNumeric) {
return parse(source, pos);
} else {
return parseToMap(source, pos);
return parseToMap(source, pos);
}
}
@ -1492,7 +1503,7 @@ public class MessageFormat extends UFormat {
* Defines constants that are used as attribute keys in the
* <code>AttributedCharacterIterator</code> returned
* from <code>MessageFormat.formatToCharacterIterator</code>.
*
*
* @stable ICU 3.8
*/
public static class Field extends Format.Field {
@ -1501,9 +1512,9 @@ public class MessageFormat extends UFormat {
/**
* Create a <code>Field</code> with the specified name.
*
*
* @param name The name of the attribute
*
*
* @stable ICU 3.8
*/
protected Field(String name) {
@ -1512,10 +1523,10 @@ public class MessageFormat extends UFormat {
/**
* Resolves instances being deserialized to the predefined constants.
*
*
* @return resolved MessageFormat.Field constant
* @throws InvalidObjectException if the constant could not be resolved.
*
*
* @stable ICU 3.8
*/
protected Object readResolve() throws InvalidObjectException {
@ -1535,7 +1546,7 @@ public class MessageFormat extends UFormat {
* The value associated with the key will be an <code>Integer</code>
* indicating the index in the <code>arguments</code> array of the
* argument from which the text was generated.
*
*
* @stable ICU 3.8
*/
public static final Field ARGUMENT = new Field("message argument field");
@ -1577,7 +1588,7 @@ public class MessageFormat extends UFormat {
/**
* The positions where the results of formatting each argument are to be
* inserted into the pattern.
*
*
* @serial
*/
private int[] offsets = new int[INITIAL_FORMATS];
@ -1595,14 +1606,14 @@ public class MessageFormat extends UFormat {
* The argument names corresponding to each formatter. (The formatters are
* stored in the order they occur in the pattern, not in the order in which
* the arguments are specified.)
*
*
* @serial
*/
private String[] argumentNames = new String[INITIAL_FORMATS];
/**
* Is true iff all argument names are non-negative numbers.
*
*
* @serial
*/
private boolean argumentNamesAreNumeric = true;
@ -1784,7 +1795,7 @@ public class MessageFormat extends UFormat {
private static final String[] typeList =
{"", "number", "date", "time", "choice", "spellout", "ordinal",
"duration", "plural"};
private static final int
private static final int
TYPE_EMPTY = 0,
TYPE_NUMBER = 1,
TYPE_DATE = 2,
@ -1797,23 +1808,23 @@ public class MessageFormat extends UFormat {
private static final String[] modifierList =
{"", "currency", "percent", "integer"};
private static final int
MODIFIER_EMPTY = 0,
MODIFIER_CURRENCY = 1,
MODIFIER_PERCENT = 2,
MODIFIER_INTEGER = 3;
private static final String[] dateModifierList =
{"", "short", "medium", "long", "full"};
private static final int
DATE_MODIFIER_EMPTY = 0,
DATE_MODIFIER_SHORT = 1,
DATE_MODIFIER_MEDIUM = 2,
DATE_MODIFIER_LONG = 3,
DATE_MODIFIER_FULL = 4;
private void makeFormat(int position, int offsetNumber,
StringBuffer[] segments)
{
@ -1852,7 +1863,7 @@ public class MessageFormat extends UFormat {
int argumentNumber;
try {
// always unlocalized!
argumentNumber = Integer.parseInt(segments[1].toString());
argumentNumber = Integer.parseInt(segments[1].toString());
} catch (NumberFormatException e) {
argumentNumber = -1;
}
@ -1861,9 +1872,9 @@ public class MessageFormat extends UFormat {
// to be numbers or (IDStartChars IDContChars*) strings.
argumentNamesAreNumeric = argumentNumber >= 0;
}
if (argumentNamesAreNumeric && argumentNumber < 0 ||
!argumentNamesAreNumeric &&
!argumentNamesAreNumeric &&
!isAlphaIdentifier(argumentNames[offsetNumber])) {
throw new IllegalArgumentException(
"All argument identifiers have to be either non-negative " +
@ -1949,7 +1960,7 @@ public class MessageFormat extends UFormat {
throw new IllegalArgumentException("Choice Pattern incorrect");
}
break;
case TYPE_SPELLOUT:
case TYPE_SPELLOUT:
{
RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(ulocale, RuleBasedNumberFormat.SPELLOUT);
String ruleset = segments[3].toString().trim();
@ -1962,7 +1973,7 @@ public class MessageFormat extends UFormat {
}
}
newFormat = rbnf;
}
}
break;
case TYPE_ORDINAL:
{
@ -1977,7 +1988,7 @@ public class MessageFormat extends UFormat {
}
}
newFormat = rbnf;
}
}
break;
case TYPE_DURATION:
{
@ -2105,7 +2116,7 @@ public class MessageFormat extends UFormat {
* This is a helper method for converting an object array into a map. The
* key set of the map is [0, ..., array.length]. The value associated with
* each key is the ith entry of the passed object array.
*
*
* @throws InvalidObjectException
* if the objects read from the stream is invalid.
*/
@ -2118,14 +2129,14 @@ public class MessageFormat extends UFormat {
}
return map;
}
private boolean isAlphaIdentifier(String argument) {
if (argument.length() == 0) {
return false;
}
for (int i = 0; i < argument.length(); ++i ) {
if (i == 0 && !IDStartChars.contains(argument.charAt(i)) ||
i > 0 && !IDContChars.contains(argument.charAt(i))){
i > 0 && !IDContChars.contains(argument.charAt(i))){
return false;
}
}
@ -2140,14 +2151,14 @@ public class MessageFormat extends UFormat {
private static final int STATE_SINGLE_QUOTE = 1;
private static final int STATE_IN_QUOTE = 2;
private static final int STATE_MSG_ELEMENT = 3;
private static UnicodeSet IDStartChars = new UnicodeSet("[:ID_Start:]");
private static UnicodeSet IDContChars = new UnicodeSet("[:ID_Continue:]");
/**
* Convert an 'apostrophe-friendly' pattern into a standard
* pattern. Standard patterns treat all apostrophes as
* quotes, which is problematic in some languages, e.g.
* quotes, which is problematic in some languages, e.g.
* French, where apostrophe is commonly used. This utility
* assumes that only an unpaired apostrophe immediately before
* a brace is a true quote. Other unpaired apostrophes are paired,

View File

@ -21,7 +21,7 @@ import java.util.Set;
* <p>
* <code>PluralFormat</code> supports the creation of internationalized
* messages with plural inflection. It is based on <i>plural
* selection</i>, i.e. the caller specifies messages for each
* selection</i>, i.e. the caller specifies messages for each
* plural case that can appear in the users language and the
* <code>PluralFormat</code> selects the appropriate message based on
* the number.
@ -68,7 +68,7 @@ import java.util.Set;
* <h5>Patterns and Their Interpretation</h5>
* <p>
* The pattern text defines the message output for each plural case of the
* used locale. The pattern is a sequence of
* used locale. The pattern is a sequence of
* <code><i>caseKeyword</i>{<i>message</i>}</code> clauses, separated by white
* space characters. Each clause assigns the message <code><i>message</i></code>
* to the plural case identified by <code><i>caseKeyword</i></code>.
@ -84,9 +84,9 @@ import java.util.Set;
* an <code>IllegalArgumentException</code> is thrown.
* <br/>
* Spaces between <code><i>caseKeyword</i></code> and
* <code><i>message</i></code> will be ignored; spaces within
* <code><i>message</i></code> will be ignored; spaces within
* <code><i>message</i></code> will be preserved.
* </p><p>
* </p><p>
* The message text for a particular plural case may contain other message
* format patterns. <code>PluralFormat</code> preserves these so that you
* can use the strings produced by <code>PluralFormat</code> with other
@ -143,7 +143,7 @@ import java.util.Set;
* For more information about <code>PluralRules</code>, see
* {@link PluralRules}.
* </p>
*
*
* @author tschumann (Tim Schumann)
* @draft ICU 3.8
* @provisional This API might change or be removed in a future release.
@ -169,8 +169,8 @@ public class PluralFormat extends UFormat {
/**
* The format messages for each plural case. It is a mapping:
* <code>String</code>(plural case keyword) --&gt; <code>String</code>
* (message for this plural case).
* <code>String</code>(plural case keyword) --&gt; <code>String</code>
* (message for this plural case).
*/
private Map parsedValues = null;
@ -202,10 +202,10 @@ public class PluralFormat extends UFormat {
public PluralFormat(ULocale ulocale) {
init(null, ulocale);
}
/**
* Creates a new <code>PluralFormat</code> for a given set of rules.
* The standard number formatting will be done using the default locale.
* The standard number formatting will be done using the default locale.
* @param rules defines the behavior of the <code>PluralFormat</code>
* object.
* @draft ICU 3.8
@ -244,7 +244,7 @@ public class PluralFormat extends UFormat {
}
/**
* Creates a new <code>PluralFormat</code> for a given pattern string and
* Creates a new <code>PluralFormat</code> for a given pattern string and
* locale.
* The locale will be used to get the set of plural rules and for
* standard number formatting.
@ -262,23 +262,23 @@ public class PluralFormat extends UFormat {
}
/**
* Creates a new <code>PluralFormat</code> for a given set of rules and a
* Creates a new <code>PluralFormat</code> for a given set of rules and a
* pattern.
* The standard number formatting will be done using the default locale.
* The standard number formatting will be done using the default locale.
* @param rules defines the behavior of the <code>PluralFormat</code>
* object.
* @param pattern the pattern for this <code>PluralFormat</code>.
* @throws IllegalArgumentException if the pattern is invalid.
* @draft ICU 3.8
* @provisional This API might change or be removed in a future release.
*/
*/
public PluralFormat(PluralRules rules, String pattern) {
init(rules, ULocale.getDefault());
applyPattern(pattern);
}
/**
* Creates a new <code>PluralFormat</code> for a given set of rules, a
* Creates a new <code>PluralFormat</code> for a given set of rules, a
* pattern and a locale.
* @param ulocale the <code>PluralFormat</code> will be configured with
* rules for this locale. This locale will also be used for standard
@ -299,10 +299,10 @@ public class PluralFormat extends UFormat {
* Initializes the <code>PluralRules</code> object.
* Postcondition:<br/>
* <code>ulocale</code> : is <code>locale</code><br/>
* <code>pluralRules</code>: if <code>rules</code> != <code>null</code>
* it's set to rules, otherwise it is the
* <code>pluralRules</code>: if <code>rules</code> != <code>null</code>
* it's set to rules, otherwise it is the
* predefined plural rule set for the locale
* <code>ulocale</code>.<br/>
* <code>ulocale</code>.<br/>
* <code>parsedValues</code>: is <code>null</code><br/>
* <code>pattern</code>: is <code>null</code><br/>
* <code>numberFormat</code>: a <code>NumberFormat</code> for the locale
@ -322,13 +322,15 @@ public class PluralFormat extends UFormat {
* The method parses the pattern and creates a map of format strings
* for the plural rules.
* Patterns and their interpretation are specified in the class description.
*
*
* @param pttrn the pattern for this plural format.
* @throws IllegalArgumentException if the pattern is invalid.
* @draft ICU 3.8
* @provisional This API might change or be removed in a future release.
*/
public void applyPattern(String pttrn) {
pttrn = pttrn.trim();
this.pattern = pttrn;
int braceStack = 0;
Set ruleNames = pluralRules.getKeywords();
@ -413,9 +415,20 @@ public class PluralFormat extends UFormat {
checkSufficientDefinition();
}
/**
* Returns the pattern for this PluralFormat.
*
* @return the pattern string
* @draft ICU 4.2
* @provisional This API might change or be removed in a future release.
*/
public String toPattern() {
return pattern;
}
/**
* Formats a plural message for a given number.
*
*
* @param number a number for which the plural message should be formatted.
* If no pattern has been applied to this
* <code>PluralFormat</code> object yet, the formatted number will
@ -434,14 +447,13 @@ public class PluralFormat extends UFormat {
String selectedRule = pluralRules.select(number);
String selectedPattern = (String) parsedValues.get(selectedRule);
if (selectedPattern == null) { // Fallback to others.
selectedPattern =
selectedPattern =
(String) parsedValues.get(PluralRules.KEYWORD_OTHER);
}
// Get formatted number and insert it into String.
// Will replace all '#' which are not inside curly braces by the
// formatted number.
return insertFormattedNumber(number, selectedPattern);
}
/**
@ -452,10 +464,10 @@ public class PluralFormat extends UFormat {
* applied to this <code>PluralFormat</code> object yet, the
* formatted number will be returned.
* Note: If this object is not an instance of <code>Number</code>,
* the <code>toAppendTo</code> will not be modified.
* the <code>toAppendTo</code> will not be modified.
* @param toAppendTo the formatted message will be appended to this
* <code>StringBuffer</code>.
* @param pos will be ignored by this method.
* @param pos will be ignored by this method.
* @return the string buffer passed in as toAppendTo, with formatted text
* appended.
* @throws IllegalArgumentException if number is not an instance of Number
@ -468,7 +480,7 @@ public class PluralFormat extends UFormat {
toAppendTo.append(format(((Number) number).doubleValue()));
return toAppendTo;
}
throw new IllegalArgumentException("'" + number +
throw new IllegalArgumentException("'" + number +
"' is not a Number");
}
@ -487,7 +499,7 @@ public class PluralFormat extends UFormat {
public Number parse(String text, ParsePosition parsePosition) {
throw new UnsupportedOperationException();
}
/**
* This method is not yet supported by <code>PluralFormat</code>.
* @param source the string to be parsed.
@ -564,7 +576,7 @@ public class PluralFormat extends UFormat {
init(null, ULocale.getDefault());
throw new IllegalArgumentException(errorText);
}
/**
* Helper method that is called during formatting.
* It replaces the character '#' by the number used for plural selection in
@ -586,10 +598,10 @@ public class PluralFormat extends UFormat {
int startIndex = 0;
for (int i = 0; i < message.length(); ++i) {
switch (message.charAt(i)) {
case '{':
case '{':
++braceStack;
break;
case '}':
case '}':
--braceStack;
break;
case '#':
@ -628,7 +640,7 @@ public class PluralFormat extends UFormat {
parsedValues.equals(rhs.parsedValues) &&
numberFormat.equals(rhs.numberFormat);
}
/**
* {@inheritDoc}
* @draft ICU 3.8