ICU-9132 Java support for MessageFormat selectordinal and PluralRules.PluralType.ORDINAL
X-SVN-Rev: 31705
This commit is contained in:
parent
adcdc1c20e
commit
3e084c0f60
@ -16,6 +16,7 @@ import java.util.Set;
|
|||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
import com.ibm.icu.text.PluralRules;
|
import com.ibm.icu.text.PluralRules;
|
||||||
|
import com.ibm.icu.text.PluralRules.PluralType;
|
||||||
import com.ibm.icu.util.ULocale;
|
import com.ibm.icu.util.ULocale;
|
||||||
import com.ibm.icu.util.UResourceBundle;
|
import com.ibm.icu.util.UResourceBundle;
|
||||||
|
|
||||||
@ -24,12 +25,10 @@ import com.ibm.icu.util.UResourceBundle;
|
|||||||
*/
|
*/
|
||||||
public class PluralRulesLoader {
|
public class PluralRulesLoader {
|
||||||
private final Map<String, PluralRules> rulesIdToRules;
|
private final Map<String, PluralRules> rulesIdToRules;
|
||||||
private Map<String, String> localeIdToRulesId; // lazy init, use
|
// lazy init, use getLocaleIdToRulesIdMap to access
|
||||||
// getLocaleIdToRulesIdMap to
|
private Map<String, String> localeIdToCardinalRulesId;
|
||||||
// access
|
private Map<String, String> localeIdToOrdinalRulesId;
|
||||||
private Map<String, ULocale> rulesIdToEquivalentULocale; // lazy init, use
|
private Map<String, ULocale> rulesIdToEquivalentULocale;
|
||||||
// getRulesIdToEquivalentULocaleMap
|
|
||||||
// to access
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Access through singleton.
|
* Access through singleton.
|
||||||
@ -42,7 +41,7 @@ public class PluralRulesLoader {
|
|||||||
* Returns the locales for which we have plurals data. Utility for testing.
|
* Returns the locales for which we have plurals data. Utility for testing.
|
||||||
*/
|
*/
|
||||||
public ULocale[] getAvailableULocales() {
|
public ULocale[] getAvailableULocales() {
|
||||||
Set<String> keys = getLocaleIdToRulesIdMap().keySet();
|
Set<String> keys = getLocaleIdToRulesIdMap(PluralType.CARDINAL).keySet();
|
||||||
ULocale[] locales = new ULocale[keys.size()];
|
ULocale[] locales = new ULocale[keys.size()];
|
||||||
int n = 0;
|
int n = 0;
|
||||||
for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
|
for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
|
||||||
@ -57,11 +56,11 @@ public class PluralRulesLoader {
|
|||||||
public ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable) {
|
public ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable) {
|
||||||
if (isAvailable != null && isAvailable.length > 0) {
|
if (isAvailable != null && isAvailable.length > 0) {
|
||||||
String localeId = ULocale.canonicalize(locale.getBaseName());
|
String localeId = ULocale.canonicalize(locale.getBaseName());
|
||||||
Map<String, String> idMap = getLocaleIdToRulesIdMap();
|
Map<String, String> idMap = getLocaleIdToRulesIdMap(PluralType.CARDINAL);
|
||||||
isAvailable[0] = idMap.containsKey(localeId);
|
isAvailable[0] = idMap.containsKey(localeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
String rulesId = getRulesIdForLocale(locale);
|
String rulesId = getRulesIdForLocale(locale, PluralType.CARDINAL);
|
||||||
if (rulesId == null || rulesId.trim().length() == 0) {
|
if (rulesId == null || rulesId.trim().length() == 0) {
|
||||||
return ULocale.ROOT; // ultimate fallback
|
return ULocale.ROOT; // ultimate fallback
|
||||||
}
|
}
|
||||||
@ -78,9 +77,9 @@ public class PluralRulesLoader {
|
|||||||
/**
|
/**
|
||||||
* Returns the lazily-constructed map.
|
* Returns the lazily-constructed map.
|
||||||
*/
|
*/
|
||||||
private Map<String, String> getLocaleIdToRulesIdMap() {
|
private Map<String, String> getLocaleIdToRulesIdMap(PluralType type) {
|
||||||
checkBuildRulesIdMaps();
|
checkBuildRulesIdMaps();
|
||||||
return localeIdToRulesId;
|
return (type == PluralType.CARDINAL) ? localeIdToCardinalRulesId : localeIdToOrdinalRulesId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -99,17 +98,19 @@ public class PluralRulesLoader {
|
|||||||
private void checkBuildRulesIdMaps() {
|
private void checkBuildRulesIdMaps() {
|
||||||
boolean haveMap;
|
boolean haveMap;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
haveMap = localeIdToRulesId != null;
|
haveMap = localeIdToCardinalRulesId != null;
|
||||||
}
|
}
|
||||||
if (!haveMap) {
|
if (!haveMap) {
|
||||||
Map<String, String> tempLocaleIdToRulesId;
|
Map<String, String> tempLocaleIdToCardinalRulesId;
|
||||||
|
Map<String, String> tempLocaleIdToOrdinalRulesId;
|
||||||
Map<String, ULocale> tempRulesIdToEquivalentULocale;
|
Map<String, ULocale> tempRulesIdToEquivalentULocale;
|
||||||
try {
|
try {
|
||||||
UResourceBundle pluralb = getPluralBundle();
|
UResourceBundle pluralb = getPluralBundle();
|
||||||
|
// Read cardinal-number rules.
|
||||||
UResourceBundle localeb = pluralb.get("locales");
|
UResourceBundle localeb = pluralb.get("locales");
|
||||||
|
|
||||||
// sort for convenience of getAvailableULocales
|
// sort for convenience of getAvailableULocales
|
||||||
tempLocaleIdToRulesId = new TreeMap<String, String>();
|
tempLocaleIdToCardinalRulesId = new TreeMap<String, String>();
|
||||||
// not visible
|
// not visible
|
||||||
tempRulesIdToEquivalentULocale = new HashMap<String, ULocale>();
|
tempRulesIdToEquivalentULocale = new HashMap<String, ULocale>();
|
||||||
|
|
||||||
@ -117,21 +118,33 @@ public class PluralRulesLoader {
|
|||||||
UResourceBundle b = localeb.get(i);
|
UResourceBundle b = localeb.get(i);
|
||||||
String id = b.getKey();
|
String id = b.getKey();
|
||||||
String value = b.getString().intern();
|
String value = b.getString().intern();
|
||||||
tempLocaleIdToRulesId.put(id, value);
|
tempLocaleIdToCardinalRulesId.put(id, value);
|
||||||
|
|
||||||
if (!tempRulesIdToEquivalentULocale.containsKey(value)) {
|
if (!tempRulesIdToEquivalentULocale.containsKey(value)) {
|
||||||
tempRulesIdToEquivalentULocale.put(value, new ULocale(id));
|
tempRulesIdToEquivalentULocale.put(value, new ULocale(id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read ordinal-number rules.
|
||||||
|
localeb = pluralb.get("locales_ordinals");
|
||||||
|
tempLocaleIdToOrdinalRulesId = new TreeMap<String, String>();
|
||||||
|
for (int i = 0; i < localeb.getSize(); ++i) {
|
||||||
|
UResourceBundle b = localeb.get(i);
|
||||||
|
String id = b.getKey();
|
||||||
|
String value = b.getString().intern();
|
||||||
|
tempLocaleIdToOrdinalRulesId.put(id, value);
|
||||||
|
}
|
||||||
} catch (MissingResourceException e) {
|
} catch (MissingResourceException e) {
|
||||||
// dummy so we don't try again
|
// dummy so we don't try again
|
||||||
tempLocaleIdToRulesId = Collections.emptyMap();
|
tempLocaleIdToCardinalRulesId = Collections.emptyMap();
|
||||||
|
tempLocaleIdToOrdinalRulesId = Collections.emptyMap();
|
||||||
tempRulesIdToEquivalentULocale = Collections.emptyMap();
|
tempRulesIdToEquivalentULocale = Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
if (localeIdToRulesId == null) {
|
if (localeIdToCardinalRulesId == null) {
|
||||||
localeIdToRulesId = tempLocaleIdToRulesId;
|
localeIdToCardinalRulesId = tempLocaleIdToCardinalRulesId;
|
||||||
|
localeIdToOrdinalRulesId = tempLocaleIdToOrdinalRulesId;
|
||||||
rulesIdToEquivalentULocale = tempRulesIdToEquivalentULocale;
|
rulesIdToEquivalentULocale = tempRulesIdToEquivalentULocale;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,8 +156,8 @@ public class PluralRulesLoader {
|
|||||||
* rulesId, return null. The rulesId might be the empty string if the rule
|
* rulesId, return null. The rulesId might be the empty string if the rule
|
||||||
* is the default rule.
|
* is the default rule.
|
||||||
*/
|
*/
|
||||||
public String getRulesIdForLocale(ULocale locale) {
|
public String getRulesIdForLocale(ULocale locale, PluralType type) {
|
||||||
Map<String, String> idMap = getLocaleIdToRulesIdMap();
|
Map<String, String> idMap = getLocaleIdToRulesIdMap(type);
|
||||||
String localeId = ULocale.canonicalize(locale.getBaseName());
|
String localeId = ULocale.canonicalize(locale.getBaseName());
|
||||||
String rulesId = null;
|
String rulesId = null;
|
||||||
while (null == (rulesId = idMap.get(localeId))) {
|
while (null == (rulesId = idMap.get(localeId))) {
|
||||||
@ -216,8 +229,8 @@ public class PluralRulesLoader {
|
|||||||
* Returns the plural rules for the the locale. If we don't have data,
|
* Returns the plural rules for the the locale. If we don't have data,
|
||||||
* com.ibm.icu.text.PluralRules.DEFAULT is returned.
|
* com.ibm.icu.text.PluralRules.DEFAULT is returned.
|
||||||
*/
|
*/
|
||||||
public PluralRules forLocale(ULocale locale) {
|
public PluralRules forLocale(ULocale locale, PluralRules.PluralType type) {
|
||||||
String rulesId = getRulesIdForLocale(locale);
|
String rulesId = getRulesIdForLocale(locale, type);
|
||||||
if (rulesId == null || rulesId.trim().length() == 0) {
|
if (rulesId == null || rulesId.trim().length() == 0) {
|
||||||
return PluralRules.DEFAULT;
|
return PluralRules.DEFAULT;
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,8 @@ import com.ibm.icu.impl.PatternProps;
|
|||||||
import com.ibm.icu.impl.Utility;
|
import com.ibm.icu.impl.Utility;
|
||||||
import com.ibm.icu.text.MessagePattern.ArgType;
|
import com.ibm.icu.text.MessagePattern.ArgType;
|
||||||
import com.ibm.icu.text.MessagePattern.Part;
|
import com.ibm.icu.text.MessagePattern.Part;
|
||||||
|
import com.ibm.icu.text.PluralFormat.PluralSelector;
|
||||||
|
import com.ibm.icu.text.PluralRules.PluralType;
|
||||||
import com.ibm.icu.util.ULocale;
|
import com.ibm.icu.util.ULocale;
|
||||||
import com.ibm.icu.util.ULocale.Category;
|
import com.ibm.icu.util.ULocale.Category;
|
||||||
|
|
||||||
@ -99,13 +101,14 @@ import com.ibm.icu.util.ULocale.Category;
|
|||||||
* <blockquote><pre>
|
* <blockquote><pre>
|
||||||
* message = messageText (argument messageText)*
|
* message = messageText (argument messageText)*
|
||||||
* argument = noneArg | simpleArg | complexArg
|
* argument = noneArg | simpleArg | complexArg
|
||||||
* complexArg = choiceArg | pluralArg | selectArg
|
* complexArg = choiceArg | pluralArg | selectArg | selectordinalArg
|
||||||
*
|
*
|
||||||
* noneArg = '{' argNameOrNumber '}'
|
* noneArg = '{' argNameOrNumber '}'
|
||||||
* simpleArg = '{' argNameOrNumber ',' argType [',' argStyle] '}'
|
* simpleArg = '{' argNameOrNumber ',' argType [',' argStyle] '}'
|
||||||
* choiceArg = '{' argNameOrNumber ',' "choice" ',' choiceStyle '}'
|
* choiceArg = '{' argNameOrNumber ',' "choice" ',' choiceStyle '}'
|
||||||
* pluralArg = '{' argNameOrNumber ',' "plural" ',' pluralStyle '}'
|
* pluralArg = '{' argNameOrNumber ',' "plural" ',' pluralStyle '}'
|
||||||
* selectArg = '{' argNameOrNumber ',' "select" ',' selectStyle '}'
|
* selectArg = '{' argNameOrNumber ',' "select" ',' selectStyle '}'
|
||||||
|
* selectordinalArg = '{' argNameOrNumber ',' "selectordinal" ',' pluralStyle '}'
|
||||||
*
|
*
|
||||||
* choiceStyle: see {@link ChoiceFormat}
|
* choiceStyle: see {@link ChoiceFormat}
|
||||||
* pluralStyle: see {@link PluralFormat}
|
* pluralStyle: see {@link PluralFormat}
|
||||||
@ -408,6 +411,7 @@ public class MessageFormat extends UFormat {
|
|||||||
// the locale has changed.
|
// the locale has changed.
|
||||||
stockNumberFormatter = stockDateFormatter = null;
|
stockNumberFormatter = stockDateFormatter = null;
|
||||||
pluralProvider = null;
|
pluralProvider = null;
|
||||||
|
ordinalProvider = null;
|
||||||
applyPattern(existingPattern); /*ibm.3550*/
|
applyPattern(existingPattern); /*ibm.3550*/
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1327,11 +1331,10 @@ public class MessageFormat extends UFormat {
|
|||||||
argResult = choiceResult;
|
argResult = choiceResult;
|
||||||
haveArgResult = true;
|
haveArgResult = true;
|
||||||
sourceOffset = tempStatus.getIndex();
|
sourceOffset = tempStatus.getIndex();
|
||||||
} else if(argType==ArgType.PLURAL || argType==ArgType.SELECT) {
|
} else if(argType.hasPluralStyle() || argType==ArgType.SELECT) {
|
||||||
// No can do!
|
// No can do!
|
||||||
throw new UnsupportedOperationException(argType==ArgType.PLURAL ?
|
throw new UnsupportedOperationException(
|
||||||
"Parsing of PluralFormat is not supported." :
|
"Parsing of plural/select/selectordinal argument is not supported.");
|
||||||
"Parsing of SelectFormat is not supported.");
|
|
||||||
} else {
|
} else {
|
||||||
// This should never happen.
|
// This should never happen.
|
||||||
throw new IllegalStateException("unexpected argType "+argType);
|
throw new IllegalStateException("unexpected argType "+argType);
|
||||||
@ -1441,6 +1444,7 @@ public class MessageFormat extends UFormat {
|
|||||||
other.stockNumberFormatter = stockNumberFormatter == null ? null : (Format) stockNumberFormatter.clone();
|
other.stockNumberFormatter = stockNumberFormatter == null ? null : (Format) stockNumberFormatter.clone();
|
||||||
|
|
||||||
other.pluralProvider = null;
|
other.pluralProvider = null;
|
||||||
|
other.ordinalProvider = null;
|
||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1560,6 +1564,7 @@ public class MessageFormat extends UFormat {
|
|||||||
private transient Format stockNumberFormatter;
|
private transient Format stockNumberFormatter;
|
||||||
|
|
||||||
private transient PluralSelectorProvider pluralProvider;
|
private transient PluralSelectorProvider pluralProvider;
|
||||||
|
private transient PluralSelectorProvider ordinalProvider;
|
||||||
|
|
||||||
// *Important*: All fields must be declared *transient*.
|
// *Important*: All fields must be declared *transient*.
|
||||||
// See the longer comment above ulocale.
|
// See the longer comment above ulocale.
|
||||||
@ -1697,15 +1702,24 @@ public class MessageFormat extends UFormat {
|
|||||||
double number = ((Number)arg).doubleValue();
|
double number = ((Number)arg).doubleValue();
|
||||||
int subMsgStart=findChoiceSubMessage(msgPattern, i, number);
|
int subMsgStart=findChoiceSubMessage(msgPattern, i, number);
|
||||||
formatComplexSubMessage(subMsgStart, 0, args, argsMap, dest);
|
formatComplexSubMessage(subMsgStart, 0, args, argsMap, dest);
|
||||||
} else if(argType==ArgType.PLURAL) {
|
} else if(argType.hasPluralStyle()) {
|
||||||
if (!(arg instanceof Number)) {
|
if (!(arg instanceof Number)) {
|
||||||
throw new IllegalArgumentException("'" + arg + "' is not a Number");
|
throw new IllegalArgumentException("'" + arg + "' is not a Number");
|
||||||
}
|
}
|
||||||
double number = ((Number)arg).doubleValue();
|
double number = ((Number)arg).doubleValue();
|
||||||
|
PluralSelector selector;
|
||||||
|
if(argType == ArgType.PLURAL) {
|
||||||
if (pluralProvider == null) {
|
if (pluralProvider == null) {
|
||||||
pluralProvider = new PluralSelectorProvider(ulocale);
|
pluralProvider = new PluralSelectorProvider(ulocale, PluralType.CARDINAL);
|
||||||
}
|
}
|
||||||
int subMsgStart=PluralFormat.findSubMessage(msgPattern, i, pluralProvider, number);
|
selector = pluralProvider;
|
||||||
|
} else {
|
||||||
|
if (ordinalProvider == null) {
|
||||||
|
ordinalProvider = new PluralSelectorProvider(ulocale, PluralType.ORDINAL);
|
||||||
|
}
|
||||||
|
selector = ordinalProvider;
|
||||||
|
}
|
||||||
|
int subMsgStart=PluralFormat.findSubMessage(msgPattern, i, selector, number);
|
||||||
double offset=msgPattern.getPluralOffset(i);
|
double offset=msgPattern.getPluralOffset(i);
|
||||||
formatComplexSubMessage(subMsgStart, number-offset, args, argsMap, dest);
|
formatComplexSubMessage(subMsgStart, number-offset, args, argsMap, dest);
|
||||||
} else if(argType==ArgType.SELECT) {
|
} else if(argType==ArgType.SELECT) {
|
||||||
@ -1940,17 +1954,19 @@ public class MessageFormat extends UFormat {
|
|||||||
* we do not need any PluralRules.
|
* we do not need any PluralRules.
|
||||||
*/
|
*/
|
||||||
private static final class PluralSelectorProvider implements PluralFormat.PluralSelector {
|
private static final class PluralSelectorProvider implements PluralFormat.PluralSelector {
|
||||||
public PluralSelectorProvider(ULocale loc) {
|
public PluralSelectorProvider(ULocale loc, PluralType type) {
|
||||||
locale=loc;
|
locale=loc;
|
||||||
|
this.type=type;
|
||||||
}
|
}
|
||||||
public String select(double number) {
|
public String select(double number) {
|
||||||
if(rules == null) {
|
if(rules == null) {
|
||||||
rules = PluralRules.forLocale(locale);
|
rules = PluralRules.forLocale(locale, type);
|
||||||
}
|
}
|
||||||
return rules.select(number);
|
return rules.select(number);
|
||||||
}
|
}
|
||||||
private ULocale locale;
|
private ULocale locale;
|
||||||
private PluralRules rules;
|
private PluralRules rules;
|
||||||
|
private PluralType type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
package com.ibm.icu.text;
|
package com.ibm.icu.text;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import com.ibm.icu.impl.ICUConfig;
|
import com.ibm.icu.impl.ICUConfig;
|
||||||
import com.ibm.icu.impl.PatternProps;
|
import com.ibm.icu.impl.PatternProps;
|
||||||
@ -819,7 +820,7 @@ public final class MessagePattern implements Cloneable, Freezable<MessagePattern
|
|||||||
*/
|
*/
|
||||||
CHOICE,
|
CHOICE,
|
||||||
/**
|
/**
|
||||||
* The argument is a PluralFormat with an optional ARG_INT or ARG_DOUBLE offset
|
* The argument is a cardinal-number PluralFormat with an optional ARG_INT or ARG_DOUBLE offset
|
||||||
* (e.g., offset:1)
|
* (e.g., offset:1)
|
||||||
* and one or more (ARG_SELECTOR [explicit-value] message) tuples.
|
* and one or more (ARG_SELECTOR [explicit-value] message) tuples.
|
||||||
* If the selector has an explicit value (e.g., =2), then
|
* If the selector has an explicit value (e.g., =2), then
|
||||||
@ -832,7 +833,24 @@ public final class MessagePattern implements Cloneable, Freezable<MessagePattern
|
|||||||
* The argument is a SelectFormat with one or more (ARG_SELECTOR, message) pairs.
|
* The argument is a SelectFormat with one or more (ARG_SELECTOR, message) pairs.
|
||||||
* @stable ICU 4.8
|
* @stable ICU 4.8
|
||||||
*/
|
*/
|
||||||
SELECT
|
SELECT,
|
||||||
|
/**
|
||||||
|
* The argument is an ordinal-number PluralFormat
|
||||||
|
* with the same style parts sequence and semantics as {@link ArgType#PLURAL}.
|
||||||
|
* @draft ICU 50
|
||||||
|
* @provisional This API might change or be removed in a future release.
|
||||||
|
*/
|
||||||
|
SELECTORDINAL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the argument type has a plural style part sequence and semantics,
|
||||||
|
* for example {@link ArgType#PLURAL} and {@link ArgType#SELECTORDINAL}.
|
||||||
|
* @draft ICU 50
|
||||||
|
* @provisional This API might change or be removed in a future release.
|
||||||
|
*/
|
||||||
|
public boolean hasPluralStyle() {
|
||||||
|
return this == PLURAL || this == SELECTORDINAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -931,7 +949,7 @@ public final class MessagePattern implements Cloneable, Freezable<MessagePattern
|
|||||||
aposMode==ApostropheMode.DOUBLE_REQUIRED ||
|
aposMode==ApostropheMode.DOUBLE_REQUIRED ||
|
||||||
c=='{' || c=='}' ||
|
c=='{' || c=='}' ||
|
||||||
(parentType==ArgType.CHOICE && c=='|') ||
|
(parentType==ArgType.CHOICE && c=='|') ||
|
||||||
(parentType==ArgType.PLURAL && c=='#')
|
(parentType.hasPluralStyle() && c=='#')
|
||||||
) {
|
) {
|
||||||
// skip the quote-starting apostrophe
|
// skip the quote-starting apostrophe
|
||||||
addPart(Part.Type.SKIP_SYNTAX, index-1, 1, 0);
|
addPart(Part.Type.SKIP_SYNTAX, index-1, 1, 0);
|
||||||
@ -964,7 +982,7 @@ public final class MessagePattern implements Cloneable, Freezable<MessagePattern
|
|||||||
needsAutoQuoting=true;
|
needsAutoQuoting=true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(parentType==ArgType.PLURAL && c=='#') {
|
} else if(parentType.hasPluralStyle() && c=='#') {
|
||||||
// The unquoted # in a plural message fragment will be replaced
|
// The unquoted # in a plural message fragment will be replaced
|
||||||
// with the (number-offset).
|
// with the (number-offset).
|
||||||
addPart(Part.Type.REPLACE_NUMBER, index-1, 1, 0);
|
addPart(Part.Type.REPLACE_NUMBER, index-1, 1, 0);
|
||||||
@ -1063,6 +1081,10 @@ public final class MessagePattern implements Cloneable, Freezable<MessagePattern
|
|||||||
} else if(isSelect(typeIndex)) {
|
} else if(isSelect(typeIndex)) {
|
||||||
argType=ArgType.SELECT;
|
argType=ArgType.SELECT;
|
||||||
}
|
}
|
||||||
|
} else if(length==13) {
|
||||||
|
if(isSelect(typeIndex) && isOrdinal(typeIndex+6)) {
|
||||||
|
argType=ArgType.SELECTORDINAL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// change the ARG_START type from NONE to argType
|
// change the ARG_START type from NONE to argType
|
||||||
parts.get(argStart).value=(short)argType.ordinal();
|
parts.get(argStart).value=(short)argType.ordinal();
|
||||||
@ -1191,26 +1213,26 @@ public final class MessagePattern implements Cloneable, Freezable<MessagePattern
|
|||||||
if(eos==inMessageFormatPattern(nestingLevel)) {
|
if(eos==inMessageFormatPattern(nestingLevel)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Bad "+
|
"Bad "+
|
||||||
(argType==ArgType.PLURAL ? "plural" : "select")+
|
argType.toString().toLowerCase(Locale.ROOT)+
|
||||||
" pattern syntax: "+prefix(start));
|
" pattern syntax: "+prefix(start));
|
||||||
}
|
}
|
||||||
if(!hasOther) {
|
if(!hasOther) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Missing 'other' keyword in "+
|
"Missing 'other' keyword in "+
|
||||||
(argType==ArgType.PLURAL ? "plural" : "select")+
|
argType.toString().toLowerCase(Locale.ROOT)+
|
||||||
" pattern in \""+prefix()+"\"");
|
" pattern in \""+prefix()+"\"");
|
||||||
}
|
}
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
int selectorIndex=index;
|
int selectorIndex=index;
|
||||||
if(argType==ArgType.PLURAL && msg.charAt(selectorIndex)=='=') {
|
if(argType.hasPluralStyle() && msg.charAt(selectorIndex)=='=') {
|
||||||
// explicit-value plural selector: =double
|
// explicit-value plural selector: =double
|
||||||
index=skipDouble(index+1);
|
index=skipDouble(index+1);
|
||||||
int length=index-selectorIndex;
|
int length=index-selectorIndex;
|
||||||
if(length==1) {
|
if(length==1) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Bad "+
|
"Bad "+
|
||||||
(argType==ArgType.PLURAL ? "plural" : "select")+
|
argType.toString().toLowerCase(Locale.ROOT)+
|
||||||
" pattern syntax: "+prefix(start));
|
" pattern syntax: "+prefix(start));
|
||||||
}
|
}
|
||||||
if(length>Part.MAX_LENGTH) {
|
if(length>Part.MAX_LENGTH) {
|
||||||
@ -1225,11 +1247,11 @@ public final class MessagePattern implements Cloneable, Freezable<MessagePattern
|
|||||||
if(length==0) {
|
if(length==0) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Bad "+
|
"Bad "+
|
||||||
(argType==ArgType.PLURAL ? "plural" : "select")+
|
argType.toString().toLowerCase(Locale.ROOT)+
|
||||||
" pattern syntax: "+prefix(start));
|
" pattern syntax: "+prefix(start));
|
||||||
}
|
}
|
||||||
// Note: The ':' in "offset:" is just beyond the skipIdentifier() range.
|
// Note: The ':' in "offset:" is just beyond the skipIdentifier() range.
|
||||||
if( argType==ArgType.PLURAL && length==6 && index<msg.length() &&
|
if( argType.hasPluralStyle() && length==6 && index<msg.length() &&
|
||||||
msg.regionMatches(selectorIndex, "offset:", 0, 7)
|
msg.regionMatches(selectorIndex, "offset:", 0, 7)
|
||||||
) {
|
) {
|
||||||
// plural offset, not a selector
|
// plural offset, not a selector
|
||||||
@ -1270,7 +1292,7 @@ public final class MessagePattern implements Cloneable, Freezable<MessagePattern
|
|||||||
if(index==msg.length() || msg.charAt(index)!='{') {
|
if(index==msg.length() || msg.charAt(index)!='{') {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"No message fragment after "+
|
"No message fragment after "+
|
||||||
(argType==ArgType.PLURAL ? "plural" : "select")+
|
argType.toString().toLowerCase(Locale.ROOT)+
|
||||||
" selector: "+prefix(selectorIndex));
|
" selector: "+prefix(selectorIndex));
|
||||||
}
|
}
|
||||||
index=parseMessage(index, 1, nestingLevel+1, argType);
|
index=parseMessage(index, 1, nestingLevel+1, argType);
|
||||||
@ -1479,6 +1501,18 @@ public final class MessagePattern implements Cloneable, Freezable<MessagePattern
|
|||||||
((c=msg.charAt(index))=='t' || c=='T');
|
((c=msg.charAt(index))=='t' || c=='T');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isOrdinal(int index) {
|
||||||
|
char c;
|
||||||
|
return
|
||||||
|
((c=msg.charAt(index++))=='o' || c=='O') &&
|
||||||
|
((c=msg.charAt(index++))=='r' || c=='R') &&
|
||||||
|
((c=msg.charAt(index++))=='d' || c=='D') &&
|
||||||
|
((c=msg.charAt(index++))=='i' || c=='I') &&
|
||||||
|
((c=msg.charAt(index++))=='n' || c=='N') &&
|
||||||
|
((c=msg.charAt(index++))=='a' || c=='A') &&
|
||||||
|
((c=msg.charAt(index))=='l' || c=='L');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if we are inside a MessageFormat (sub-)pattern,
|
* @return true if we are inside a MessageFormat (sub-)pattern,
|
||||||
* as opposed to inside a top-level choice/plural/select pattern.
|
* as opposed to inside a top-level choice/plural/select pattern.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* Copyright (C) 2011, International Business Machines
|
* Copyright (C) 2011-2012, International Business Machines
|
||||||
* Corporation and others. All Rights Reserved.
|
* Corporation and others. All Rights Reserved.
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* created on: 2011jul14
|
* created on: 2011jul14
|
||||||
@ -547,12 +547,16 @@ public final class MessagePatternUtil {
|
|||||||
break;
|
break;
|
||||||
case PLURAL:
|
case PLURAL:
|
||||||
node.typeName = "plural";
|
node.typeName = "plural";
|
||||||
node.complexStyle = buildPluralStyleNode(pattern, start, limit);
|
node.complexStyle = buildPluralStyleNode(pattern, start, limit, argType);
|
||||||
break;
|
break;
|
||||||
case SELECT:
|
case SELECT:
|
||||||
node.typeName = "select";
|
node.typeName = "select";
|
||||||
node.complexStyle = buildSelectStyleNode(pattern, start, limit);
|
node.complexStyle = buildSelectStyleNode(pattern, start, limit);
|
||||||
break;
|
break;
|
||||||
|
case SELECTORDINAL:
|
||||||
|
node.typeName = "selectordinal";
|
||||||
|
node.complexStyle = buildPluralStyleNode(pattern, start, limit, argType);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// NONE type, nothing else to do
|
// NONE type, nothing else to do
|
||||||
break;
|
break;
|
||||||
@ -580,8 +584,9 @@ public final class MessagePatternUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static ComplexArgStyleNode buildPluralStyleNode(MessagePattern pattern,
|
private static ComplexArgStyleNode buildPluralStyleNode(MessagePattern pattern,
|
||||||
int start, int limit) {
|
int start, int limit,
|
||||||
ComplexArgStyleNode node = new ComplexArgStyleNode(MessagePattern.ArgType.PLURAL);
|
MessagePattern.ArgType argType) {
|
||||||
|
ComplexArgStyleNode node = new ComplexArgStyleNode(argType);
|
||||||
MessagePattern.Part offset = pattern.getPart(start);
|
MessagePattern.Part offset = pattern.getPart(start);
|
||||||
if (offset.getType().hasNumericValue()) {
|
if (offset.getType().hasNumericValue()) {
|
||||||
node.explicitOffset = true;
|
node.explicitOffset = true;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* Copyright (C) 2007-2011, International Business Machines Corporation and *
|
* Copyright (C) 2007-2012, International Business Machines Corporation and
|
||||||
* others. All Rights Reserved. *
|
* others. All Rights Reserved.
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -14,6 +14,7 @@ import java.text.ParsePosition;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.ibm.icu.impl.Utility;
|
import com.ibm.icu.impl.Utility;
|
||||||
|
import com.ibm.icu.text.PluralRules.PluralType;
|
||||||
import com.ibm.icu.util.ULocale;
|
import com.ibm.icu.util.ULocale;
|
||||||
import com.ibm.icu.util.ULocale.Category;
|
import com.ibm.icu.util.ULocale.Category;
|
||||||
|
|
||||||
@ -176,29 +177,29 @@ public class PluralFormat extends UFormat {
|
|||||||
transient private double offset = 0;
|
transient private double offset = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new <code>PluralFormat</code> for the default <code>FORMAT</code> locale.
|
* Creates a new cardinal-number <code>PluralFormat</code> for the default <code>FORMAT</code> locale.
|
||||||
* This locale will be used to get the set of plural rules and for standard
|
* This locale will be used to get the set of plural rules and for standard
|
||||||
* number formatting.
|
* number formatting.
|
||||||
* @see Category#FORMAT
|
* @see Category#FORMAT
|
||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
public PluralFormat() {
|
public PluralFormat() {
|
||||||
init(null, ULocale.getDefault(Category.FORMAT));
|
init(null, PluralType.CARDINAL, ULocale.getDefault(Category.FORMAT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new <code>PluralFormat</code> for a given locale.
|
* Creates a new cardinal-number <code>PluralFormat</code> for a given locale.
|
||||||
* @param ulocale the <code>PluralFormat</code> will be configured with
|
* @param ulocale the <code>PluralFormat</code> will be configured with
|
||||||
* rules for this locale. This locale will also be used for standard
|
* rules for this locale. This locale will also be used for standard
|
||||||
* number formatting.
|
* number formatting.
|
||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
public PluralFormat(ULocale ulocale) {
|
public PluralFormat(ULocale ulocale) {
|
||||||
init(null, ulocale);
|
init(null, PluralType.CARDINAL, ulocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new <code>PluralFormat</code> for a given set of rules.
|
* Creates a new cardinal-number <code>PluralFormat</code> for a given set of rules.
|
||||||
* The standard number formatting will be done using the default <code>FORMAT</code> locale.
|
* The standard number formatting will be done using the default <code>FORMAT</code> locale.
|
||||||
* @param rules defines the behavior of the <code>PluralFormat</code>
|
* @param rules defines the behavior of the <code>PluralFormat</code>
|
||||||
* object.
|
* object.
|
||||||
@ -206,11 +207,11 @@ public class PluralFormat extends UFormat {
|
|||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
public PluralFormat(PluralRules rules) {
|
public PluralFormat(PluralRules rules) {
|
||||||
init(rules, ULocale.getDefault(Category.FORMAT));
|
init(rules, PluralType.CARDINAL, ULocale.getDefault(Category.FORMAT));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new <code>PluralFormat</code> for a given set of rules.
|
* Creates a new cardinal-number <code>PluralFormat</code> for a given set of rules.
|
||||||
* The standard number formatting will be done using the given locale.
|
* The standard number formatting will be done using the given locale.
|
||||||
* @param ulocale the default number formatting will be done using this
|
* @param ulocale the default number formatting will be done using this
|
||||||
* locale.
|
* locale.
|
||||||
@ -219,11 +220,24 @@ public class PluralFormat extends UFormat {
|
|||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
public PluralFormat(ULocale ulocale, PluralRules rules) {
|
public PluralFormat(ULocale ulocale, PluralRules rules) {
|
||||||
init(rules, ulocale);
|
init(rules, PluralType.CARDINAL, ulocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new <code>PluralFormat</code> for a given pattern string.
|
* Creates a new <code>PluralFormat</code> for the plural type.
|
||||||
|
* The standard number formatting will be done using the given locale.
|
||||||
|
* @param ulocale the default number formatting will be done using this
|
||||||
|
* locale.
|
||||||
|
* @param type The plural type (e.g., cardinal or ordinal).
|
||||||
|
* @draft ICU 50
|
||||||
|
* @provisional This API might change or be removed in a future release.
|
||||||
|
*/
|
||||||
|
public PluralFormat(ULocale ulocale, PluralType type) {
|
||||||
|
init(null, type, ulocale);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new cardinal-number <code>PluralFormat</code> for a given pattern string.
|
||||||
* The default <code>FORMAT</code> locale will be used to get the set of plural rules and for
|
* The default <code>FORMAT</code> locale will be used to get the set of plural rules and for
|
||||||
* standard number formatting.
|
* standard number formatting.
|
||||||
* @param pattern the pattern for this <code>PluralFormat</code>.
|
* @param pattern the pattern for this <code>PluralFormat</code>.
|
||||||
@ -232,12 +246,12 @@ public class PluralFormat extends UFormat {
|
|||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
public PluralFormat(String pattern) {
|
public PluralFormat(String pattern) {
|
||||||
init(null, ULocale.getDefault(Category.FORMAT));
|
init(null, PluralType.CARDINAL, ULocale.getDefault(Category.FORMAT));
|
||||||
applyPattern(pattern);
|
applyPattern(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new <code>PluralFormat</code> for a given pattern string and
|
* Creates a new cardinal-number <code>PluralFormat</code> for a given pattern string and
|
||||||
* locale.
|
* locale.
|
||||||
* The locale will be used to get the set of plural rules and for
|
* The locale will be used to get the set of plural rules and for
|
||||||
* standard number formatting.
|
* standard number formatting.
|
||||||
@ -249,12 +263,12 @@ public class PluralFormat extends UFormat {
|
|||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
public PluralFormat(ULocale ulocale, String pattern) {
|
public PluralFormat(ULocale ulocale, String pattern) {
|
||||||
init(null, ulocale);
|
init(null, PluralType.CARDINAL, ulocale);
|
||||||
applyPattern(pattern);
|
applyPattern(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new <code>PluralFormat</code> for a given set of rules and a
|
* Creates a new cardinal-number <code>PluralFormat</code> for a given set of rules and a
|
||||||
* pattern.
|
* pattern.
|
||||||
* The standard number formatting will be done using the default <code>FORMAT</code> locale.
|
* The standard number formatting will be done using the default <code>FORMAT</code> locale.
|
||||||
* @param rules defines the behavior of the <code>PluralFormat</code>
|
* @param rules defines the behavior of the <code>PluralFormat</code>
|
||||||
@ -265,12 +279,12 @@ public class PluralFormat extends UFormat {
|
|||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
public PluralFormat(PluralRules rules, String pattern) {
|
public PluralFormat(PluralRules rules, String pattern) {
|
||||||
init(rules, ULocale.getDefault(Category.FORMAT));
|
init(rules, PluralType.CARDINAL, ULocale.getDefault(Category.FORMAT));
|
||||||
applyPattern(pattern);
|
applyPattern(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new <code>PluralFormat</code> for a given set of rules, a
|
* Creates a new cardinal-number <code>PluralFormat</code> for a given set of rules, a
|
||||||
* pattern and a locale.
|
* pattern and a locale.
|
||||||
* @param ulocale the <code>PluralFormat</code> will be configured with
|
* @param ulocale the <code>PluralFormat</code> will be configured with
|
||||||
* rules for this locale. This locale will also be used for standard
|
* rules for this locale. This locale will also be used for standard
|
||||||
@ -282,7 +296,24 @@ public class PluralFormat extends UFormat {
|
|||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
public PluralFormat(ULocale ulocale, PluralRules rules, String pattern) {
|
public PluralFormat(ULocale ulocale, PluralRules rules, String pattern) {
|
||||||
init(rules, ulocale);
|
init(rules, PluralType.CARDINAL, ulocale);
|
||||||
|
applyPattern(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new <code>PluralFormat</code> for a plural type, 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
|
||||||
|
* number formatting.
|
||||||
|
* @param type The plural type (e.g., cardinal or ordinal).
|
||||||
|
* @param pattern the pattern for this <code>PluralFormat</code>.
|
||||||
|
* @throws IllegalArgumentException if the pattern is invalid.
|
||||||
|
* @draft ICU 50
|
||||||
|
* @provisional This API might change or be removed in a future release.
|
||||||
|
*/
|
||||||
|
public PluralFormat(ULocale ulocale, PluralType type, String pattern) {
|
||||||
|
init(null, type, ulocale);
|
||||||
applyPattern(pattern);
|
applyPattern(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -299,9 +330,9 @@ public class PluralFormat extends UFormat {
|
|||||||
* <code>numberFormat</code>: a <code>NumberFormat</code> for the locale
|
* <code>numberFormat</code>: a <code>NumberFormat</code> for the locale
|
||||||
* <code>ulocale</code>.
|
* <code>ulocale</code>.
|
||||||
*/
|
*/
|
||||||
private void init(PluralRules rules, ULocale locale) {
|
private void init(PluralRules rules, PluralType type, ULocale locale) {
|
||||||
ulocale = locale;
|
ulocale = locale;
|
||||||
pluralRules = (rules == null) ? PluralRules.forLocale(ulocale)
|
pluralRules = (rules == null) ? PluralRules.forLocale(ulocale, type)
|
||||||
: rules;
|
: rules;
|
||||||
resetPattern();
|
resetPattern();
|
||||||
numberFormat = NumberFormat.getInstance(ulocale);
|
numberFormat = NumberFormat.getInstance(ulocale);
|
||||||
@ -590,7 +621,8 @@ public class PluralFormat extends UFormat {
|
|||||||
* i.e., a pattern that was applied previously will be removed,
|
* i.e., a pattern that was applied previously will be removed,
|
||||||
* and the NumberFormat is set to the default number format for
|
* and the NumberFormat is set to the default number format for
|
||||||
* the locale. The resulting format behaves the same as one
|
* the locale. The resulting format behaves the same as one
|
||||||
* constructed from {@link #PluralFormat(ULocale)}.
|
* constructed from {@link #PluralFormat(ULocale, PluralType)}
|
||||||
|
* with PluralType.CARDINAL.
|
||||||
* @param ulocale the <code>ULocale</code> used to configure the
|
* @param ulocale the <code>ULocale</code> used to configure the
|
||||||
* formatter. If <code>ulocale</code> is <code>null</code>, the
|
* formatter. If <code>ulocale</code> is <code>null</code>, the
|
||||||
* default <code>FORMAT</code> locale will be used.
|
* default <code>FORMAT</code> locale will be used.
|
||||||
@ -601,7 +633,7 @@ public class PluralFormat extends UFormat {
|
|||||||
if (ulocale == null) {
|
if (ulocale == null) {
|
||||||
ulocale = ULocale.getDefault(Category.FORMAT);
|
ulocale = ULocale.getDefault(Category.FORMAT);
|
||||||
}
|
}
|
||||||
init(null, ulocale);
|
init(null, PluralType.CARDINAL, ulocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,6 +148,26 @@ public class PluralRules implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public static final double NO_UNIQUE_VALUE = -0.00123456777;
|
public static final double NO_UNIQUE_VALUE = -0.00123456777;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of plurals and PluralRules.
|
||||||
|
* @draft ICU 50
|
||||||
|
* @provisional This API might change or be removed in a future release.
|
||||||
|
*/
|
||||||
|
public enum PluralType {
|
||||||
|
/**
|
||||||
|
* Plural rules for cardinal numbers: 1 file vs. 2 files.
|
||||||
|
* @draft ICU 50
|
||||||
|
* @provisional This API might change or be removed in a future release.
|
||||||
|
*/
|
||||||
|
CARDINAL,
|
||||||
|
/**
|
||||||
|
* Plural rules for ordinal numbers: 1st file, 2nd file, 3rd file, 4th file, etc.
|
||||||
|
* @draft ICU 50
|
||||||
|
* @provisional This API might change or be removed in a future release.
|
||||||
|
*/
|
||||||
|
ORDINAL
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The default constraint that is always satisfied.
|
* The default constraint that is always satisfied.
|
||||||
*/
|
*/
|
||||||
@ -798,9 +818,11 @@ public class PluralRules implements Serializable {
|
|||||||
// -------------------------------------------------------------------------
|
// -------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to the predefined <code>PluralRules</code> for a given
|
* Provides access to the predefined cardinal-number <code>PluralRules</code> for a given
|
||||||
* locale.
|
* locale.
|
||||||
* ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>.
|
* Same as forLocale(locale, PluralType.CARDINAL).
|
||||||
|
*
|
||||||
|
* <p>ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>.
|
||||||
* For these predefined rules, see CLDR page at
|
* For these predefined rules, see CLDR page at
|
||||||
* http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
|
* http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
|
||||||
*
|
*
|
||||||
@ -814,7 +836,30 @@ public class PluralRules implements Serializable {
|
|||||||
* @stable ICU 3.8
|
* @stable ICU 3.8
|
||||||
*/
|
*/
|
||||||
public static PluralRules forLocale(ULocale locale) {
|
public static PluralRules forLocale(ULocale locale) {
|
||||||
return PluralRulesLoader.loader.forLocale(locale);
|
return PluralRulesLoader.loader.forLocale(locale, PluralType.CARDINAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides access to the predefined <code>PluralRules</code> for a given
|
||||||
|
* locale and the plural type.
|
||||||
|
*
|
||||||
|
* <p>ICU defines plural rules for many locales based on CLDR <i>Language Plural Rules</i>.
|
||||||
|
* For these predefined rules, see CLDR page at
|
||||||
|
* http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
|
||||||
|
*
|
||||||
|
* @param locale The locale for which a <code>PluralRules</code> object is
|
||||||
|
* returned.
|
||||||
|
* @param type The plural type (e.g., cardinal or ordinal).
|
||||||
|
* @return The predefined <code>PluralRules</code> object for this locale.
|
||||||
|
* If there's no predefined rules for this locale, the rules
|
||||||
|
* for the closest parent in the locale hierarchy that has one will
|
||||||
|
* be returned. The final fallback always returns the default
|
||||||
|
* rules.
|
||||||
|
* @draft ICU 50
|
||||||
|
* @provisional This API might change or be removed in a future release.
|
||||||
|
*/
|
||||||
|
public static PluralRules forLocale(ULocale locale, PluralType type) {
|
||||||
|
return PluralRulesLoader.loader.forLocale(locale, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:aa91eade60c4302ef379eab96b02b98f08781bcc728c6059616545c63b83ba2a
|
oid sha256:d933870a3235e23ce8bc66928d928bc0a0fb28d510b17f52eb74d7a99949bc92
|
||||||
size 7927279
|
size 7927279
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* Copyright (C) 2011, International Business Machines
|
* Copyright (C) 2011-2012, International Business Machines
|
||||||
* Corporation and others. All Rights Reserved.
|
* Corporation and others. All Rights Reserved.
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* created on: 2011aug12
|
* created on: 2011aug12
|
||||||
@ -12,6 +12,7 @@ package com.ibm.icu.dev.test.format;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import com.ibm.icu.text.MessagePattern;
|
import com.ibm.icu.text.MessagePattern;
|
||||||
import com.ibm.icu.text.MessagePatternUtil;
|
import com.ibm.icu.text.MessagePatternUtil;
|
||||||
@ -65,6 +66,9 @@ public final class MessagePatternUtilTest extends com.ibm.icu.dev.test.TestFmwk
|
|||||||
private ExpectComplexArgNode expectSelectArg(Object name) {
|
private ExpectComplexArgNode expectSelectArg(Object name) {
|
||||||
return expectComplexArg(name, MessagePattern.ArgType.SELECT);
|
return expectComplexArg(name, MessagePattern.ArgType.SELECT);
|
||||||
}
|
}
|
||||||
|
private ExpectComplexArgNode expectSelectOrdinalArg(Object name) {
|
||||||
|
return expectComplexArg(name, MessagePattern.ArgType.SELECTORDINAL);
|
||||||
|
}
|
||||||
private ExpectComplexArgNode expectComplexArg(Object name, MessagePattern.ArgType argType) {
|
private ExpectComplexArgNode expectComplexArg(Object name, MessagePattern.ArgType argType) {
|
||||||
ExpectComplexArgNode complexArg = new ExpectComplexArgNode(this, name, argType);
|
ExpectComplexArgNode complexArg = new ExpectComplexArgNode(this, name, argType);
|
||||||
contents.add(complexArg);
|
contents.add(complexArg);
|
||||||
@ -180,9 +184,7 @@ public final class MessagePatternUtilTest extends com.ibm.icu.dev.test.TestFmwk
|
|||||||
private class ExpectComplexArgNode extends ExpectArgNode {
|
private class ExpectComplexArgNode extends ExpectArgNode {
|
||||||
private ExpectComplexArgNode(ExpectMessageNode parent,
|
private ExpectComplexArgNode(ExpectMessageNode parent,
|
||||||
Object name, MessagePattern.ArgType argType) {
|
Object name, MessagePattern.ArgType argType) {
|
||||||
super(name,
|
super(name, argType.toString().toLowerCase(Locale.ROOT));
|
||||||
argType == MessagePattern.ArgType.CHOICE ? "choice" :
|
|
||||||
argType == MessagePattern.ArgType.PLURAL ? "plural" : "select");
|
|
||||||
this.argType = argType;
|
this.argType = argType;
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
}
|
}
|
||||||
@ -394,6 +396,22 @@ public final class MessagePatternUtilTest extends com.ibm.icu.dev.test.TestFmwk
|
|||||||
expect.checkMatches(msg);
|
expect.checkMatches(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void TestSelectOrdinalArg() {
|
||||||
|
MessageNode msg = MessagePatternUtil.buildMessageNode(
|
||||||
|
"abc{num, selectordinal, offset:17 =0{null} few{fff} other {oooo}}xyz");
|
||||||
|
ExpectMessageNode expect = new ExpectMessageNode().
|
||||||
|
expectTextThatContains("abc").
|
||||||
|
expectSelectOrdinalArg("num").
|
||||||
|
expectOffset(17).
|
||||||
|
expectVariant("=0", 0).expectTextThatContains("null").finishVariant().
|
||||||
|
expectVariant("few").expectTextThatContains("fff").finishVariant().
|
||||||
|
expectVariant("other").expectTextThatContains("oooo").finishVariant().
|
||||||
|
finishComplexArg().
|
||||||
|
expectTextThatContains("xyz");
|
||||||
|
expect.checkMatches(msg);
|
||||||
|
}
|
||||||
|
|
||||||
public void TestChoiceArg() {
|
public void TestChoiceArg() {
|
||||||
MessageNode msg = MessagePatternUtil.buildMessageNode(
|
MessageNode msg = MessagePatternUtil.buildMessageNode(
|
||||||
"a_{0,choice,-∞ #-inf| 5≤ five | 99 # ninety'|'nine }_z");
|
"a_{0,choice,-∞ #-inf| 5≤ five | 99 # ninety'|'nine }_z");
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* Copyright (C) 2007-2011, International Business Machines Corporation and *
|
* Copyright (C) 2007-2012, International Business Machines Corporation and
|
||||||
* others. All Rights Reserved. *
|
* others. All Rights Reserved.
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -19,6 +19,7 @@ import com.ibm.icu.text.MessageFormat;
|
|||||||
import com.ibm.icu.text.NumberFormat;
|
import com.ibm.icu.text.NumberFormat;
|
||||||
import com.ibm.icu.text.PluralFormat;
|
import com.ibm.icu.text.PluralFormat;
|
||||||
import com.ibm.icu.text.PluralRules;
|
import com.ibm.icu.text.PluralRules;
|
||||||
|
import com.ibm.icu.text.PluralRules.PluralType;
|
||||||
import com.ibm.icu.util.ULocale;
|
import com.ibm.icu.util.ULocale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -324,4 +325,18 @@ public class PluralFormatUnitTest extends TestFmwk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TestOrdinalFormat() {
|
||||||
|
String pattern = "one{#st file}two{#nd file}few{#rd file}other{#th file}";
|
||||||
|
PluralFormat pf = new PluralFormat(ULocale.ENGLISH, PluralType.ORDINAL, pattern);
|
||||||
|
assertEquals("PluralFormat.format(321)", "321st file", pf.format(321));
|
||||||
|
assertEquals("PluralFormat.format(22)", "22nd file", pf.format(22));
|
||||||
|
assertEquals("PluralFormat.format(3)", "3rd file", pf.format(3));
|
||||||
|
|
||||||
|
// Code coverage: Use the other new-for-PluralType constructor as well.
|
||||||
|
pf = new PluralFormat(ULocale.ENGLISH, PluralType.ORDINAL);
|
||||||
|
pf.applyPattern(pattern);
|
||||||
|
assertEquals("PluralFormat.format(456)", "456th file", pf.format(456));
|
||||||
|
assertEquals("PluralFormat.format(111)", "111th file", pf.format(111));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
* Copyright (C) 2007-2011, International Business Machines Corporation and *
|
* Copyright (C) 2007-2012, International Business Machines Corporation and
|
||||||
* others. All Rights Reserved. *
|
* others. All Rights Reserved.
|
||||||
*******************************************************************************
|
*******************************************************************************
|
||||||
*/
|
*/
|
||||||
package com.ibm.icu.dev.test.format;
|
package com.ibm.icu.dev.test.format;
|
||||||
@ -18,6 +18,7 @@ import java.util.Set;
|
|||||||
import com.ibm.icu.dev.test.TestFmwk;
|
import com.ibm.icu.dev.test.TestFmwk;
|
||||||
import com.ibm.icu.impl.Utility;
|
import com.ibm.icu.impl.Utility;
|
||||||
import com.ibm.icu.text.PluralRules;
|
import com.ibm.icu.text.PluralRules;
|
||||||
|
import com.ibm.icu.text.PluralRules.PluralType;
|
||||||
import com.ibm.icu.util.ULocale;
|
import com.ibm.icu.util.ULocale;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -386,4 +387,9 @@ public class PluralRulesTest extends TestFmwk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TestOrdinal() {
|
||||||
|
PluralRules pr = PluralRules.forLocale(ULocale.ENGLISH, PluralType.ORDINAL);
|
||||||
|
assertEquals("PluralRules(en-ordinal).select(2)", "two", pr.select(2));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Copyright (c) 2004-2011, International Business Machines
|
* Copyright (c) 2004-2012, International Business Machines
|
||||||
* Corporation and others. All Rights Reserved.
|
* Corporation and others. All Rights Reserved.
|
||||||
**********************************************************************
|
**********************************************************************
|
||||||
* Author: Alan Liu
|
* Author: Alan Liu
|
||||||
@ -1832,4 +1832,33 @@ public class TestMessageFormat extends com.ibm.icu.dev.test.TestFmwk {
|
|||||||
assertEquals("trim-named-arg format() failed", "x 3 y",
|
assertEquals("trim-named-arg format() failed", "x 3 y",
|
||||||
m.format(map, result, new FieldPosition(0)).toString());
|
m.format(map, result, new FieldPosition(0)).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TestSelectOrdinal() {
|
||||||
|
// Test plural & ordinal together,
|
||||||
|
// to make sure that we get the correct cached PluralSelector for each.
|
||||||
|
MessageFormat m = new MessageFormat(
|
||||||
|
"{0,plural,one{1 file}other{# files}}, " +
|
||||||
|
"{0,selectordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}",
|
||||||
|
ULocale.ENGLISH);
|
||||||
|
Object[] args = new Object[] { 21 };
|
||||||
|
FieldPosition ignore = null;
|
||||||
|
StringBuffer result = new StringBuffer();
|
||||||
|
assertEquals("plural-and-ordinal format(21)", "21 files, 21st file",
|
||||||
|
m.format(args, result, ignore).toString());
|
||||||
|
|
||||||
|
args[0] = 2;
|
||||||
|
result.delete(0, result.length());
|
||||||
|
assertEquals("plural-and-ordinal format(2) failed", "2 files, 2nd file",
|
||||||
|
m.format(args, result, ignore).toString());
|
||||||
|
|
||||||
|
args[0] = 1;
|
||||||
|
result.delete(0, result.length());
|
||||||
|
assertEquals("plural-and-ordinal format(1) failed", "1 file, 1st file",
|
||||||
|
m.format(args, result, ignore).toString());
|
||||||
|
|
||||||
|
args[0] = 3;
|
||||||
|
result.delete(0, result.length());
|
||||||
|
assertEquals("plural-and-ordinal format(3) failed", "3 files, 3rd file",
|
||||||
|
m.format(args, result, ignore).toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user