ICU-6390 support for available locales and functional equivalent

X-SVN-Rev: 24381
This commit is contained in:
Doug Felt 2008-07-15 02:05:19 +00:00
parent 30e587a108
commit 7c47091e1c
3 changed files with 102 additions and 6 deletions

View File

@ -17,7 +17,6 @@ import java.util.List;
/**
* @author dougfelt (Doug Felt)
*
*/
public class PluralRulesTest extends TestFmwk {
public static void main(String[] args) throws Exception {
@ -150,4 +149,25 @@ public class PluralRulesTest extends TestFmwk {
assertEquals("ru 1", PluralRules.KEYWORD_ONE, rules.select(1));
assertEquals("ru 2", PluralRules.KEYWORD_FEW, rules.select(2));
}
public void testFunctionalEquivalent() {
// spot check
ULocale unknown = ULocale.createCanonical("zz_ZZ");
ULocale un_equiv = PluralRules.getFunctionalEquivalent(unknown, null);
assertEquals("unknown locales have root", ULocale.ROOT, un_equiv);
ULocale jp_equiv = PluralRules.getFunctionalEquivalent(ULocale.JAPAN, null);
ULocale cn_equiv = PluralRules.getFunctionalEquivalent(ULocale.CHINA, null);
assertEquals("japan and china equivalent locales", jp_equiv, cn_equiv);
boolean[] available = new boolean[1];
ULocale russia = ULocale.createCanonical("ru_RU");
ULocale ru_ru_equiv = PluralRules.getFunctionalEquivalent(russia, available);
assertFalse("ru_RU not listed", available[0]);
ULocale russian = ULocale.createCanonical("ru");
ULocale ru_equiv = PluralRules.getFunctionalEquivalent(russian, available);
assertTrue("ru listed", available[0]);
assertEquals("ru and ru_RU equivalent locales", ru_ru_equiv, ru_equiv);
}
}

View File

@ -24,6 +24,7 @@ import java.util.TreeMap;
public class PluralRulesLoader {
private final Map rulesIdToRules;
private Map localeIdToRulesId; // lazy init, use getLocaleIdToRulesIdMap to access
private Map rulesIdToEquivalentULocale; // lazy init, use getRulesIdToEquivalentULocaleMap to access
/**
* Access through singleton.
@ -47,28 +48,72 @@ public class PluralRulesLoader {
}
/**
* Lazily construct the map from localeIds to rulesIds. This
* map exactly reflects the contents of the locales resource
* in plurals.res.
* Returns the functionally equivalent locale.
*/
public ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable) {
if (isAvailable != null && isAvailable.length > 0) {
String localeId = ULocale.canonicalize(locale.getBaseName());
Map idMap = getLocaleIdToRulesIdMap();
isAvailable[0] = idMap.containsKey(localeId);
}
String rulesId = getRulesIdForLocale(locale);
if (rulesId == null || rulesId.trim().length() == 0) {
return ULocale.ROOT; // ultimate fallback
}
ULocale result = (ULocale) getRulesIdToEquivalentULocaleMap().get(rulesId);
if (result == null) {
return ULocale.ROOT; // ultimate fallback
}
return result;
}
/**
* Returns the lazily-constructed map.
*/
private Map getLocaleIdToRulesIdMap() {
checkBuildRulesIdMaps();
return localeIdToRulesId;
}
/**
* Returns the lazily-constructed map.
*/
private Map getRulesIdToEquivalentULocaleMap() {
checkBuildRulesIdMaps();
return rulesIdToEquivalentULocale;
}
/**
* Lazily constructs the localeIdToRulesId and rulesIdToEquivalentULocale
* maps if necessary. These exactly reflect the contents of the locales resource
* in plurals.res.
*/
private void checkBuildRulesIdMaps() {
if (localeIdToRulesId == null) {
try {
UResourceBundle pluralb = getPluralBundle();
UResourceBundle localeb = pluralb.get("locales");
localeIdToRulesId = new TreeMap(); // sort for convenience of getAvailableULocales
rulesIdToEquivalentULocale = new HashMap(); // not visible
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);
if (!rulesIdToEquivalentULocale.containsKey(value)) {
rulesIdToEquivalentULocale.put(value, new ULocale(id));
}
}
}
catch (MissingResourceException e) {
localeIdToRulesId = new HashMap(); // dummy so we don't try again
localeIdToRulesId = new HashMap(); // dummy so we don't try again, can read
rulesIdToEquivalentULocale = new HashMap();
}
}
return localeIdToRulesId;
}
/**

View File

@ -735,6 +735,37 @@ public class PluralRules implements Serializable {
return keywords;
}
/**
* Returns the set of locales for which PluralRules are known.
* @return the set of locales for which PluralRules are known, as a list
* @draft ICU 4.2
* @provisional This API might change or be removed in a future release.
*/
public static ULocale[] getAvailableULocales() {
return PluralRulesLoader.loader.getAvailableULocales();
}
/**
* Returns the 'functionally equivalent' locale with respect to
* plural rules. Calling PluralRules.forLocale with the functionally equivalent
* locale, and with the provided locale, returns rules that behave the same.
* <br/>
* All locales with the same functionally equivalent locale have
* plural rules that behave the same. This is not exaustive;
* there may be other locales whose plural rules behave the same
* that do not have the same equivalent locale.
*
* @param locale the locale to check
* @param isAvailable if not null and of length > 0, this will hold 'true' at
* index 0 if locale is directly defined (without fallback) as having plural rules
* @return the functionally-equivalent locale
* @draft ICU 4.2
* @provisional This API might change or be removed in a future release.
*/
public static ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable) {
return PluralRulesLoader.loader.getFunctionalEquivalent(locale, isAvailable);
}
/**
* {@inheritDoc}
* @draft ICU 3.8