mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-21 12:40:02 +00:00
ICU-6373 use plural rules data from resource, update tests to match new data
X-SVN-Rev: 24266
This commit is contained in:
parent
9993b72bc3
commit
942954d066
4 changed files with 203 additions and 69 deletions
|
@ -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. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
|
@ -48,15 +48,19 @@ public class PluralFormatTest extends TestFmwk {
|
|||
*/
|
||||
log("test pattern: '" + testPattern + "'");
|
||||
for (int i = 0; i < locales.length; ++i) {
|
||||
PluralFormat plf = new PluralFormat(new ULocale(locales[i]), testPattern);
|
||||
log("plf: " + plf);
|
||||
String expected = (String) changes.get(new Integer(0));
|
||||
for (int n = 0; n < 200; ++n) {
|
||||
if (changes.get(new Integer(n)) != null) {
|
||||
expected = (String) changes.get(new Integer(n));
|
||||
try {
|
||||
PluralFormat plf = new PluralFormat(new ULocale(locales[i]), testPattern);
|
||||
log("plf: " + plf);
|
||||
String expected = (String) changes.get(new Integer(0));
|
||||
for (int n = 0; n < 200; ++n) {
|
||||
if (changes.get(new Integer(n)) != null) {
|
||||
expected = (String) changes.get(new Integer(n));
|
||||
}
|
||||
assertEquals("Locale: " + locales[i] + ", number: " + n,
|
||||
expected, plf.format(n));
|
||||
}
|
||||
assertEquals("Locale: " + locales[i] + ", number: " + n,
|
||||
expected, plf.format(n));
|
||||
} catch (IllegalArgumentException e) {
|
||||
errln(e.getMessage() + " locale: " + locales[i] + " pattern: '" + testPattern + "' " + System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +74,7 @@ public class PluralFormatTest extends TestFmwk {
|
|||
}
|
||||
|
||||
public void TestSingular1Locales() {
|
||||
String localeIDs = "da,de,el,en,eo,es,et,fi,fo,he,hu,it,nb,nl,nn,no,pt,sv";
|
||||
String localeIDs = "da,de,el,en,eo,es,et,fi,fo,he,it,nb,nl,nn,no,pt_PT,sv";
|
||||
String testPattern = "one{one} other{other}";
|
||||
Map changes = new HashMap();
|
||||
changes.put(new Integer(0), "other");
|
||||
|
@ -118,13 +122,13 @@ public class PluralFormatTest extends TestFmwk {
|
|||
|
||||
public void TestSingularZeroSome() {
|
||||
String localeIDs = "ro";
|
||||
String testPattern = "zero{zero} one{one} other{other}";
|
||||
String testPattern = "few{few} one{one} other{other}";
|
||||
Map changes = new HashMap();
|
||||
changes.put(new Integer(0), "zero");
|
||||
changes.put(new Integer(0), "few");
|
||||
changes.put(new Integer(1), "one");
|
||||
changes.put(new Integer(2), "zero");
|
||||
changes.put(new Integer(2), "few");
|
||||
changes.put(new Integer(20), "other");
|
||||
changes.put(new Integer(101), "zero");
|
||||
changes.put(new Integer(101), "few");
|
||||
changes.put(new Integer(120), "other");
|
||||
helperTestRules(localeIDs, testPattern, changes);
|
||||
}
|
||||
|
@ -187,7 +191,7 @@ public class PluralFormatTest extends TestFmwk {
|
|||
changes.put(new Integer(2), "few");
|
||||
changes.put(new Integer(5), "other");
|
||||
for (int i = 2; i < 20; ++i) {
|
||||
if (i == 11) {
|
||||
if (i == 2 || i == 11 || i == 12) {
|
||||
continue;
|
||||
}
|
||||
changes.put(new Integer(i*10 + 2), "few");
|
||||
|
|
|
@ -9,6 +9,7 @@ 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.util.ULocale;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -131,4 +132,22 @@ public class PluralRulesTest extends TestFmwk {
|
|||
compareEquality(rules);
|
||||
}
|
||||
}
|
||||
|
||||
public void testBuiltInRules() {
|
||||
// spot check
|
||||
PluralRules rules = PluralRules.forLocale(ULocale.US);
|
||||
assertEquals("us 0", PluralRules.KEYWORD_OTHER, rules.select(0));
|
||||
assertEquals("us 1", PluralRules.KEYWORD_ONE, rules.select(1));
|
||||
assertEquals("us 2", PluralRules.KEYWORD_OTHER, rules.select(2));
|
||||
|
||||
rules = PluralRules.forLocale(ULocale.JAPAN);
|
||||
assertEquals("ja 0", PluralRules.KEYWORD_OTHER, rules.select(0));
|
||||
assertEquals("ja 1", PluralRules.KEYWORD_OTHER, rules.select(1));
|
||||
assertEquals("ja 2", PluralRules.KEYWORD_OTHER, rules.select(2));
|
||||
|
||||
rules = PluralRules.forLocale(ULocale.createCanonical("ru"));
|
||||
assertEquals("ru 0", PluralRules.KEYWORD_MANY, rules.select(0));
|
||||
assertEquals("ru 1", PluralRules.KEYWORD_ONE, rules.select(1));
|
||||
assertEquals("ru 2", PluralRules.KEYWORD_FEW, rules.select(2));
|
||||
}
|
||||
}
|
||||
|
|
161
icu4j/src/com/ibm/icu/impl/PluralRulesLoader.java
Normal file
161
icu4j/src/com/ibm/icu/impl/PluralRulesLoader.java
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
*******************************************************************************
|
||||
* Copyright (C) 2008, International Business Machines Corporation and *
|
||||
* others. All Rights Reserved. *
|
||||
*******************************************************************************
|
||||
*/
|
||||
package com.ibm.icu.impl;
|
||||
|
||||
import com.ibm.icu.text.PluralRules;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.util.UResourceBundle;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Loader for plural rules data.
|
||||
*/
|
||||
public class PluralRulesLoader {
|
||||
private final Map rulesIdToRules;
|
||||
private Map localeIdToRulesId; // lazy init, use getLocaleIdToRulesIdMap to access
|
||||
|
||||
/**
|
||||
* Access through singleton.
|
||||
*/
|
||||
private PluralRulesLoader() {
|
||||
rulesIdToRules = new HashMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the locales for which we have plurals data.
|
||||
* Utility for testing.
|
||||
*/
|
||||
public ULocale[] getAvailableULocales() {
|
||||
Set keys = getLocaleIdToRulesIdMap().keySet();
|
||||
ULocale[] locales = new ULocale[keys.size()];
|
||||
int n = 0;
|
||||
for (Iterator iter = keys.iterator(); iter.hasNext();) {
|
||||
locales[n++] = ULocale.createCanonical((String) iter.next());
|
||||
}
|
||||
return locales;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily construct the map from localeIds to rulesIds. This
|
||||
* map exactly reflects the contents of the locales resource
|
||||
* in plurals.res.
|
||||
*/
|
||||
private Map getLocaleIdToRulesIdMap() {
|
||||
if (localeIdToRulesId == null) {
|
||||
try {
|
||||
UResourceBundle pluralb = getPluralBundle();
|
||||
UResourceBundle localeb = pluralb.get("locales");
|
||||
localeIdToRulesId = new TreeMap(); // sort for convenience of getAvailableULocales
|
||||
for (int i = 0; i < localeb.getSize(); ++i) {
|
||||
UResourceBundle b = localeb.get(i);
|
||||
String id = b.getKey();
|
||||
String value = b.getString().intern();
|
||||
localeIdToRulesId.put(id, value);
|
||||
}
|
||||
}
|
||||
catch (MissingResourceException e) {
|
||||
localeIdToRulesId = new HashMap(); // dummy so we don't try again
|
||||
}
|
||||
}
|
||||
return localeIdToRulesId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rulesId from the locale,with locale fallback. If there is no
|
||||
* rulesId, return null. The rulesId might be the empty string if the
|
||||
* rule is the default rule.
|
||||
*/
|
||||
public String getRulesIdForLocale(ULocale locale) {
|
||||
Map idMap = getLocaleIdToRulesIdMap();
|
||||
String localeId = ULocale.canonicalize(locale.getBaseName());
|
||||
String rulesId = null;
|
||||
while (null == (rulesId = (String) idMap.get(localeId))) {
|
||||
int ix = localeId.lastIndexOf("_");
|
||||
if (ix == -1) {
|
||||
break;
|
||||
}
|
||||
localeId = localeId.substring(0, ix);
|
||||
}
|
||||
return rulesId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rule from the rulesId. If there is no rule for this rulesId,
|
||||
* return null.
|
||||
*/
|
||||
public PluralRules getRulesForRulesId(String rulesId) {
|
||||
PluralRules rules = (PluralRules) rulesIdToRules.get(rulesId);
|
||||
if (rules == null) {
|
||||
try {
|
||||
UResourceBundle pluralb = getPluralBundle();
|
||||
UResourceBundle rulesb = pluralb.get("rules");
|
||||
UResourceBundle setb = rulesb.get(rulesId);
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0; i < setb.getSize(); ++i) {
|
||||
UResourceBundle b = setb.get(i);
|
||||
if (i > 0) {
|
||||
sb.append("; ");
|
||||
}
|
||||
sb.append(b.getKey());
|
||||
sb.append(": ");
|
||||
sb.append(b.getString());
|
||||
}
|
||||
rules = PluralRules.parseDescription(sb.toString());
|
||||
} catch (ParseException e) {
|
||||
} catch (MissingResourceException e) {
|
||||
}
|
||||
rulesIdToRules.put(rulesId, rules); // put even if null
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the plurals resource.
|
||||
* Note MissingResourceException is unchecked, listed here for clarity.
|
||||
* Callers should handle this exception.
|
||||
*/
|
||||
public UResourceBundle getPluralBundle() throws MissingResourceException {
|
||||
return ICUResourceBundle.getBundleInstance(
|
||||
ICUResourceBundle.ICU_BASE_NAME,
|
||||
"plurals",
|
||||
ICUResourceBundle.ICU_DATA_CLASS_LOADER,
|
||||
true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
if (rulesId == null || rulesId.trim().length() == 0) {
|
||||
return PluralRules.DEFAULT;
|
||||
}
|
||||
PluralRules rules = getRulesForRulesId(rulesId);
|
||||
if (rules == null) {
|
||||
rules = PluralRules.DEFAULT;
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* The only instance of the loader.
|
||||
*/
|
||||
public static final PluralRulesLoader loader = new PluralRulesLoader();
|
||||
}
|
|
@ -7,17 +7,16 @@
|
|||
|
||||
package com.ibm.icu.text;
|
||||
|
||||
import com.ibm.icu.util.ULocale;
|
||||
import com.ibm.icu.impl.PluralRulesLoader;
|
||||
import com.ibm.icu.impl.Utility;
|
||||
import com.ibm.icu.util.ULocale;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -78,8 +77,6 @@ import java.util.Set;
|
|||
public class PluralRules implements Serializable {
|
||||
private static final long serialVersionUID = 1;
|
||||
|
||||
private static final Map ruleMap; // from locale string to PluralRules
|
||||
|
||||
private final RuleList rules;
|
||||
private final Set keywords;
|
||||
private int repeatLimit; // for equality test
|
||||
|
@ -276,46 +273,6 @@ public class PluralRules implements Serializable {
|
|||
int getRepeatLimit();
|
||||
}
|
||||
|
||||
// default data
|
||||
static {
|
||||
String[] ruledata = {
|
||||
"other: n/ja,ko,tr,vi", // not strictly necessary, default for all
|
||||
"zero: n is 0; one: n is 1; two: n is 2; few: n in 3..10; " +
|
||||
"many: n in 11..99/ar",
|
||||
"one: n is 1/da,de,el,en,eo,es,et,fi,fo,he,hu,it,nb,nl,nn,no,pt,sv",
|
||||
"one: n in 0..1/fr,pt_BR",
|
||||
"zero: n is 0; one: n mod 10 is 1 and n mod 100 is not 11/lv",
|
||||
"one: n is 1; two: n is 2/ga",
|
||||
"zero: n is 0; one: n is 1; zero: n mod 100 in 1..19/ro",
|
||||
"other: n mod 100 in 11..19; one: n mod 10 is 1; " +
|
||||
"few: n mod 10 in 2..9/lt",
|
||||
"one: n mod 10 is 1 and n mod 100 is not 11; " +
|
||||
"few: n mod 10 in 2..4 " +
|
||||
"and n mod 100 not in 12..14/hr,ru,sr,uk",
|
||||
"one: n is 1; few: n in 2..4/cs,sk",
|
||||
"one: n is 1; few: n mod 10 in 2..4 and n mod 100 not in 12..14/pl",
|
||||
"one: n mod 100 is 1; two: n mod 100 is 2; " +
|
||||
"few: n mod 100 in 3..4/sl",
|
||||
};
|
||||
|
||||
HashMap map = new HashMap();
|
||||
for (int i = 0; i < ruledata.length; ++i) {
|
||||
String[] data = Utility.split(ruledata[i], '/');
|
||||
try {
|
||||
PluralRules pluralRules = parseDescription(data[0]);
|
||||
String[] locales = Utility.split(data[1], ',');
|
||||
for (int j = 0; j < locales.length; ++j) {
|
||||
map.put(locales[j].trim(), pluralRules);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("PluralRules init failure, " +
|
||||
e.getMessage() + " at line " + i);
|
||||
}
|
||||
}
|
||||
|
||||
ruleMap = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* syntax:
|
||||
* condition : or_condition
|
||||
|
@ -724,14 +681,7 @@ public class PluralRules implements Serializable {
|
|||
* @provisional This API might change or be removed in a future release.
|
||||
*/
|
||||
public static PluralRules forLocale(ULocale locale) {
|
||||
PluralRules result = null;
|
||||
while (null == (result = (PluralRules) ruleMap.get(locale.getName()))) {
|
||||
locale = locale.getFallback();
|
||||
if (locale == null) {
|
||||
return DEFAULT;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return PluralRulesLoader.loader.forLocale(locale);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -846,4 +796,4 @@ public class PluralRules implements Serializable {
|
|||
}
|
||||
return repeatLimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue