import java.util.TreeMap;
import com.ibm.icu.text.PluralRules;
+import com.ibm.icu.text.PluralRules.PluralType;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.UResourceBundle;
*/
public class PluralRulesLoader {
private final Map<String, PluralRules> rulesIdToRules;
- private Map<String, String> localeIdToRulesId; // lazy init, use
- // getLocaleIdToRulesIdMap to
- // access
- private Map<String, ULocale> rulesIdToEquivalentULocale; // lazy init, use
- // getRulesIdToEquivalentULocaleMap
- // to access
+ // lazy init, use getLocaleIdToRulesIdMap to access
+ private Map<String, String> localeIdToCardinalRulesId;
+ private Map<String, String> localeIdToOrdinalRulesId;
+ private Map<String, ULocale> rulesIdToEquivalentULocale;
/**
* Access through singleton.
* Returns the locales for which we have plurals data. Utility for testing.
*/
public ULocale[] getAvailableULocales() {
- Set<String> keys = getLocaleIdToRulesIdMap().keySet();
+ Set<String> keys = getLocaleIdToRulesIdMap(PluralType.CARDINAL).keySet();
ULocale[] locales = new ULocale[keys.size()];
int n = 0;
for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
public ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable) {
if (isAvailable != null && isAvailable.length > 0) {
String localeId = ULocale.canonicalize(locale.getBaseName());
- Map<String, String> idMap = getLocaleIdToRulesIdMap();
+ Map<String, String> idMap = getLocaleIdToRulesIdMap(PluralType.CARDINAL);
isAvailable[0] = idMap.containsKey(localeId);
}
- String rulesId = getRulesIdForLocale(locale);
+ String rulesId = getRulesIdForLocale(locale, PluralType.CARDINAL);
if (rulesId == null || rulesId.trim().length() == 0) {
return ULocale.ROOT; // ultimate fallback
}
/**
* Returns the lazily-constructed map.
*/
- private Map<String, String> getLocaleIdToRulesIdMap() {
+ private Map<String, String> getLocaleIdToRulesIdMap(PluralType type) {
checkBuildRulesIdMaps();
- return localeIdToRulesId;
+ return (type == PluralType.CARDINAL) ? localeIdToCardinalRulesId : localeIdToOrdinalRulesId;
}
/**
private void checkBuildRulesIdMaps() {
boolean haveMap;
synchronized (this) {
- haveMap = localeIdToRulesId != null;
+ haveMap = localeIdToCardinalRulesId != null;
}
if (!haveMap) {
- Map<String, String> tempLocaleIdToRulesId;
+ Map<String, String> tempLocaleIdToCardinalRulesId;
+ Map<String, String> tempLocaleIdToOrdinalRulesId;
Map<String, ULocale> tempRulesIdToEquivalentULocale;
try {
UResourceBundle pluralb = getPluralBundle();
+ // Read cardinal-number rules.
UResourceBundle localeb = pluralb.get("locales");
-
+
// sort for convenience of getAvailableULocales
- tempLocaleIdToRulesId = new TreeMap<String, String>();
+ tempLocaleIdToCardinalRulesId = new TreeMap<String, String>();
// not visible
tempRulesIdToEquivalentULocale = new HashMap<String, ULocale>();
-
+
for (int i = 0; i < localeb.getSize(); ++i) {
UResourceBundle b = localeb.get(i);
String id = b.getKey();
String value = b.getString().intern();
- tempLocaleIdToRulesId.put(id, value);
+ tempLocaleIdToCardinalRulesId.put(id, value);
if (!tempRulesIdToEquivalentULocale.containsKey(value)) {
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) {
// dummy so we don't try again
- tempLocaleIdToRulesId = Collections.emptyMap();
+ tempLocaleIdToCardinalRulesId = Collections.emptyMap();
+ tempLocaleIdToOrdinalRulesId = Collections.emptyMap();
tempRulesIdToEquivalentULocale = Collections.emptyMap();
}
synchronized(this) {
- if (localeIdToRulesId == null) {
- localeIdToRulesId = tempLocaleIdToRulesId;
+ if (localeIdToCardinalRulesId == null) {
+ localeIdToCardinalRulesId = tempLocaleIdToCardinalRulesId;
+ localeIdToOrdinalRulesId = tempLocaleIdToOrdinalRulesId;
rulesIdToEquivalentULocale = tempRulesIdToEquivalentULocale;
}
}
* rulesId, return null. The rulesId might be the empty string if the rule
* is the default rule.
*/
- public String getRulesIdForLocale(ULocale locale) {
- Map<String, String> idMap = getLocaleIdToRulesIdMap();
+ public String getRulesIdForLocale(ULocale locale, PluralType type) {
+ Map<String, String> idMap = getLocaleIdToRulesIdMap(type);
String localeId = ULocale.canonicalize(locale.getBaseName());
String rulesId = null;
while (null == (rulesId = idMap.get(localeId))) {
* Returns the plural rules for the the locale. If we don't have data,
* com.ibm.icu.text.PluralRules.DEFAULT is returned.
*/
- public PluralRules forLocale(ULocale locale) {
- String rulesId = getRulesIdForLocale(locale);
+ public PluralRules forLocale(ULocale locale, PluralRules.PluralType type) {
+ String rulesId = getRulesIdForLocale(locale, type);
if (rulesId == null || rulesId.trim().length() == 0) {
return PluralRules.DEFAULT;
}
import com.ibm.icu.impl.Utility;
import com.ibm.icu.text.MessagePattern.ArgType;
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.Category;
* <blockquote><pre>
* message = messageText (argument messageText)*
* argument = noneArg | simpleArg | complexArg
- * complexArg = choiceArg | pluralArg | selectArg
+ * complexArg = choiceArg | pluralArg | selectArg | selectordinalArg
*
* noneArg = '{' argNameOrNumber '}'
* simpleArg = '{' argNameOrNumber ',' argType [',' argStyle] '}'
* choiceArg = '{' argNameOrNumber ',' "choice" ',' choiceStyle '}'
* pluralArg = '{' argNameOrNumber ',' "plural" ',' pluralStyle '}'
* selectArg = '{' argNameOrNumber ',' "select" ',' selectStyle '}'
+ * selectordinalArg = '{' argNameOrNumber ',' "selectordinal" ',' pluralStyle '}'
*
* choiceStyle: see {@link ChoiceFormat}
* pluralStyle: see {@link PluralFormat}
// the locale has changed.
stockNumberFormatter = stockDateFormatter = null;
pluralProvider = null;
+ ordinalProvider = null;
applyPattern(existingPattern); /*ibm.3550*/
}
argResult = choiceResult;
haveArgResult = true;
sourceOffset = tempStatus.getIndex();
- } else if(argType==ArgType.PLURAL || argType==ArgType.SELECT) {
+ } else if(argType.hasPluralStyle() || argType==ArgType.SELECT) {
// No can do!
- throw new UnsupportedOperationException(argType==ArgType.PLURAL ?
- "Parsing of PluralFormat is not supported." :
- "Parsing of SelectFormat is not supported.");
+ throw new UnsupportedOperationException(
+ "Parsing of plural/select/selectordinal argument is not supported.");
} else {
// This should never happen.
throw new IllegalStateException("unexpected argType "+argType);
other.stockNumberFormatter = stockNumberFormatter == null ? null : (Format) stockNumberFormatter.clone();
other.pluralProvider = null;
+ other.ordinalProvider = null;
return other;
}
private transient Format stockNumberFormatter;
private transient PluralSelectorProvider pluralProvider;
+ private transient PluralSelectorProvider ordinalProvider;
// *Important*: All fields must be declared *transient*.
// See the longer comment above ulocale.
double number = ((Number)arg).doubleValue();
int subMsgStart=findChoiceSubMessage(msgPattern, i, number);
formatComplexSubMessage(subMsgStart, 0, args, argsMap, dest);
- } else if(argType==ArgType.PLURAL) {
+ } else if(argType.hasPluralStyle()) {
if (!(arg instanceof Number)) {
throw new IllegalArgumentException("'" + arg + "' is not a Number");
}
double number = ((Number)arg).doubleValue();
- if (pluralProvider == null) {
- pluralProvider = new PluralSelectorProvider(ulocale);
+ PluralSelector selector;
+ if(argType == ArgType.PLURAL) {
+ if (pluralProvider == null) {
+ pluralProvider = new PluralSelectorProvider(ulocale, PluralType.CARDINAL);
+ }
+ selector = pluralProvider;
+ } else {
+ if (ordinalProvider == null) {
+ ordinalProvider = new PluralSelectorProvider(ulocale, PluralType.ORDINAL);
+ }
+ selector = ordinalProvider;
}
- int subMsgStart=PluralFormat.findSubMessage(msgPattern, i, pluralProvider, number);
+ int subMsgStart=PluralFormat.findSubMessage(msgPattern, i, selector, number);
double offset=msgPattern.getPluralOffset(i);
formatComplexSubMessage(subMsgStart, number-offset, args, argsMap, dest);
} else if(argType==ArgType.SELECT) {
* we do not need any PluralRules.
*/
private static final class PluralSelectorProvider implements PluralFormat.PluralSelector {
- public PluralSelectorProvider(ULocale loc) {
+ public PluralSelectorProvider(ULocale loc, PluralType type) {
locale=loc;
+ this.type=type;
}
public String select(double number) {
if(rules == null) {
- rules = PluralRules.forLocale(locale);
+ rules = PluralRules.forLocale(locale, type);
}
return rules.select(number);
}
private ULocale locale;
private PluralRules rules;
+ private PluralType type;
}
@SuppressWarnings("unchecked")
package com.ibm.icu.text;
import java.util.ArrayList;
+import java.util.Locale;
import com.ibm.icu.impl.ICUConfig;
import com.ibm.icu.impl.PatternProps;
*/
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)
* and one or more (ARG_SELECTOR [explicit-value] message) tuples.
* If the selector has an explicit value (e.g., =2), then
* The argument is a SelectFormat with one or more (ARG_SELECTOR, message) pairs.
* @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;
+ }
}
/**
aposMode==ApostropheMode.DOUBLE_REQUIRED ||
c=='{' || c=='}' ||
(parentType==ArgType.CHOICE && c=='|') ||
- (parentType==ArgType.PLURAL && c=='#')
+ (parentType.hasPluralStyle() && c=='#')
) {
// skip the quote-starting apostrophe
addPart(Part.Type.SKIP_SYNTAX, index-1, 1, 0);
needsAutoQuoting=true;
}
}
- } else if(parentType==ArgType.PLURAL && c=='#') {
+ } else if(parentType.hasPluralStyle() && c=='#') {
// The unquoted # in a plural message fragment will be replaced
// with the (number-offset).
addPart(Part.Type.REPLACE_NUMBER, index-1, 1, 0);
} else if(isSelect(typeIndex)) {
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
parts.get(argStart).value=(short)argType.ordinal();
if(eos==inMessageFormatPattern(nestingLevel)) {
throw new IllegalArgumentException(
"Bad "+
- (argType==ArgType.PLURAL ? "plural" : "select")+
+ argType.toString().toLowerCase(Locale.ROOT)+
" pattern syntax: "+prefix(start));
}
if(!hasOther) {
throw new IllegalArgumentException(
"Missing 'other' keyword in "+
- (argType==ArgType.PLURAL ? "plural" : "select")+
+ argType.toString().toLowerCase(Locale.ROOT)+
" pattern in \""+prefix()+"\"");
}
return index;
}
int selectorIndex=index;
- if(argType==ArgType.PLURAL && msg.charAt(selectorIndex)=='=') {
+ if(argType.hasPluralStyle() && msg.charAt(selectorIndex)=='=') {
// explicit-value plural selector: =double
index=skipDouble(index+1);
int length=index-selectorIndex;
if(length==1) {
throw new IllegalArgumentException(
"Bad "+
- (argType==ArgType.PLURAL ? "plural" : "select")+
+ argType.toString().toLowerCase(Locale.ROOT)+
" pattern syntax: "+prefix(start));
}
if(length>Part.MAX_LENGTH) {
if(length==0) {
throw new IllegalArgumentException(
"Bad "+
- (argType==ArgType.PLURAL ? "plural" : "select")+
+ argType.toString().toLowerCase(Locale.ROOT)+
" pattern syntax: "+prefix(start));
}
// 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)
) {
// plural offset, not a selector
if(index==msg.length() || msg.charAt(index)!='{') {
throw new IllegalArgumentException(
"No message fragment after "+
- (argType==ArgType.PLURAL ? "plural" : "select")+
+ argType.toString().toLowerCase(Locale.ROOT)+
" selector: "+prefix(selectorIndex));
}
index=parseMessage(index, 1, nestingLevel+1, argType);
((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,
* as opposed to inside a top-level choice/plural/select pattern.
/*
*******************************************************************************
-* Copyright (C) 2011, International Business Machines
+* Copyright (C) 2011-2012, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
* created on: 2011jul14
break;
case PLURAL:
node.typeName = "plural";
- node.complexStyle = buildPluralStyleNode(pattern, start, limit);
+ node.complexStyle = buildPluralStyleNode(pattern, start, limit, argType);
break;
case SELECT:
node.typeName = "select";
node.complexStyle = buildSelectStyleNode(pattern, start, limit);
break;
+ case SELECTORDINAL:
+ node.typeName = "selectordinal";
+ node.complexStyle = buildPluralStyleNode(pattern, start, limit, argType);
+ break;
default:
// NONE type, nothing else to do
break;
}
private static ComplexArgStyleNode buildPluralStyleNode(MessagePattern pattern,
- int start, int limit) {
- ComplexArgStyleNode node = new ComplexArgStyleNode(MessagePattern.ArgType.PLURAL);
+ int start, int limit,
+ MessagePattern.ArgType argType) {
+ ComplexArgStyleNode node = new ComplexArgStyleNode(argType);
MessagePattern.Part offset = pattern.getPart(start);
if (offset.getType().hasNumericValue()) {
node.explicitOffset = true;
/*
*******************************************************************************
- * Copyright (C) 2007-2011, International Business Machines Corporation and *
- * others. All Rights Reserved. *
+ * Copyright (C) 2007-2012, International Business Machines Corporation and
+ * others. All Rights Reserved.
*******************************************************************************
*/
import java.util.Map;
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.Category;
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
* number formatting.
* @see Category#FORMAT
* @stable ICU 3.8
*/
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
* rules for this locale. This locale will also be used for standard
* number formatting.
* @stable ICU 3.8
*/
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.
* @param rules defines the behavior of the <code>PluralFormat</code>
* object.
* @stable ICU 3.8
*/
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.
* @param ulocale the default number formatting will be done using this
* locale.
* @stable ICU 3.8
*/
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
* standard number formatting.
* @param pattern the pattern for this <code>PluralFormat</code>.
* @stable ICU 3.8
*/
public PluralFormat(String pattern) {
- init(null, ULocale.getDefault(Category.FORMAT));
+ init(null, PluralType.CARDINAL, ULocale.getDefault(Category.FORMAT));
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.
* The locale will be used to get the set of plural rules and for
* standard number formatting.
* @stable ICU 3.8
*/
public PluralFormat(ULocale ulocale, String pattern) {
- init(null, ulocale);
+ init(null, PluralType.CARDINAL, ulocale);
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.
* The standard number formatting will be done using the default <code>FORMAT</code> locale.
* @param rules defines the behavior of the <code>PluralFormat</code>
* @stable ICU 3.8
*/
public PluralFormat(PluralRules rules, String pattern) {
- init(rules, ULocale.getDefault(Category.FORMAT));
+ init(rules, PluralType.CARDINAL, ULocale.getDefault(Category.FORMAT));
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.
* @param ulocale the <code>PluralFormat</code> will be configured with
* rules for this locale. This locale will also be used for standard
* @stable ICU 3.8
*/
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);
}
* <code>numberFormat</code>: a <code>NumberFormat</code> for the locale
* <code>ulocale</code>.
*/
- private void init(PluralRules rules, ULocale locale) {
+ private void init(PluralRules rules, PluralType type, ULocale locale) {
ulocale = locale;
- pluralRules = (rules == null) ? PluralRules.forLocale(ulocale)
+ pluralRules = (rules == null) ? PluralRules.forLocale(ulocale, type)
: rules;
resetPattern();
numberFormat = NumberFormat.getInstance(ulocale);
* i.e., a pattern that was applied previously will be removed,
* and the NumberFormat is set to the default number format for
* 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
* formatter. If <code>ulocale</code> is <code>null</code>, the
* default <code>FORMAT</code> locale will be used.
if (ulocale == null) {
ulocale = ULocale.getDefault(Category.FORMAT);
}
- init(null, ulocale);
+ init(null, PluralType.CARDINAL, ulocale);
}
/**
*/
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.
*/
// -------------------------------------------------------------------------
/**
- * 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.
- * 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
* http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
*
* @stable ICU 3.8
*/
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);
}
/*
version https://git-lfs.github.com/spec/v1
-oid sha256:aa91eade60c4302ef379eab96b02b98f08781bcc728c6059616545c63b83ba2a
+oid sha256:d933870a3235e23ce8bc66928d928bc0a0fb28d510b17f52eb74d7a99949bc92
size 7927279
/*
*******************************************************************************
-* Copyright (C) 2011, International Business Machines
+* Copyright (C) 2011-2012, International Business Machines
* Corporation and others. All Rights Reserved.
*******************************************************************************
* created on: 2011aug12
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Locale;
import com.ibm.icu.text.MessagePattern;
import com.ibm.icu.text.MessagePatternUtil;
private ExpectComplexArgNode expectSelectArg(Object name) {
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) {
ExpectComplexArgNode complexArg = new ExpectComplexArgNode(this, name, argType);
contents.add(complexArg);
private class ExpectComplexArgNode extends ExpectArgNode {
private ExpectComplexArgNode(ExpectMessageNode parent,
Object name, MessagePattern.ArgType argType) {
- super(name,
- argType == MessagePattern.ArgType.CHOICE ? "choice" :
- argType == MessagePattern.ArgType.PLURAL ? "plural" : "select");
+ super(name, argType.toString().toLowerCase(Locale.ROOT));
this.argType = argType;
this.parent = parent;
}
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() {
MessageNode msg = MessagePatternUtil.buildMessageNode(
"a_{0,choice,-∞ #-inf| 5≤ five | 99 # ninety'|'nine }_z");
/*
*******************************************************************************
- * Copyright (C) 2007-2011, International Business Machines Corporation and *
- * others. All Rights Reserved. *
+ * Copyright (C) 2007-2012, International Business Machines Corporation and
+ * others. All Rights Reserved.
*******************************************************************************
*/
import com.ibm.icu.text.NumberFormat;
import com.ibm.icu.text.PluralFormat;
import com.ibm.icu.text.PluralRules;
+import com.ibm.icu.text.PluralRules.PluralType;
import com.ibm.icu.util.ULocale;
/**
}
}
}
+
+ 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));
+ }
}
/*
*******************************************************************************
- * Copyright (C) 2007-2011, International Business Machines Corporation and *
- * others. All Rights Reserved. *
+ * Copyright (C) 2007-2012, International Business Machines Corporation and
+ * others. All Rights Reserved.
*******************************************************************************
*/
package com.ibm.icu.dev.test.format;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.impl.Utility;
import com.ibm.icu.text.PluralRules;
+import com.ibm.icu.text.PluralRules.PluralType;
import com.ibm.icu.util.ULocale;
/**
}
}
}
+
+ public void TestOrdinal() {
+ PluralRules pr = PluralRules.forLocale(ULocale.ENGLISH, PluralType.ORDINAL);
+ assertEquals("PluralRules(en-ordinal).select(2)", "two", pr.select(2));
+ }
}
/*
**********************************************************************
-* Copyright (c) 2004-2011, International Business Machines
+* Copyright (c) 2004-2012, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
* Author: Alan Liu
assertEquals("trim-named-arg format() failed", "x 3 y",
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());
+ }
}