diff options
Diffstat (limited to 'src/com/ibm/icu/simple/PluralRulesLoader.java')
-rw-r--r-- | src/com/ibm/icu/simple/PluralRulesLoader.java | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/src/com/ibm/icu/simple/PluralRulesLoader.java b/src/com/ibm/icu/simple/PluralRulesLoader.java new file mode 100644 index 0000000..23383ea --- /dev/null +++ b/src/com/ibm/icu/simple/PluralRulesLoader.java @@ -0,0 +1,180 @@ +/* + ******************************************************************************* + * Copyright (C) 2008-2013, International Business Machines Corporation and * + * others. All Rights Reserved. * + ******************************************************************************* + */ +package com.ibm.icu.simple; + +import java.text.ParseException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.TreeMap; + +import com.ibm.icu.simple.PluralRules.PluralType; + +/** + * Loader for plural rules data. + */ +public class PluralRulesLoader extends PluralRules.Factory { + // Data created from ICU4C with the command + // ~/svn.icu/trunk/bld$ LD_LIBRARY_PATH=lib bin/genrb --write-java UTF-8 --java-package com.ibm.icu.simple -s ../src/source/data/misc/ plurals.txt -d /tmp/icu + private static final ResourceBundle DATA_RB = new LocaleElements_plurals(); + + private final Map<String, PluralRules> rulesIdToRules; + // lazy init, use getLocaleIdToRulesIdMap to access + private Map<String, String> localeIdToCardinalRulesId; + private Map<String, String> localeIdToOrdinalRulesId; + + /** + * Access through singleton. + */ + private PluralRulesLoader() { + rulesIdToRules = new HashMap<String, PluralRules>(); + } + + /** + * Returns the lazily-constructed map. + */ + private Map<String, String> getLocaleIdToRulesIdMap(PluralType type) { + checkBuildRulesIdMaps(); + return (type == PluralType.CARDINAL) ? localeIdToCardinalRulesId : localeIdToOrdinalRulesId; + } + + /** + * Lazily constructs the localeIdToRulesId and rulesIdToEquivalentULocale + * maps if necessary. These exactly reflect the contents of the locales + * resource in plurals.res. + */ + private void checkBuildRulesIdMaps() { + boolean haveMap; + synchronized (this) { + haveMap = localeIdToCardinalRulesId != null; + } + if (!haveMap) { + Map<String, String> tempLocaleIdToCardinalRulesId; + Map<String, String> tempLocaleIdToOrdinalRulesId; + try { + ResourceBundle pluralb = DATA_RB; + // Read cardinal-number rules. + Object[][] localeb = (Object[][]) pluralb.getObject("locales"); + + // sort for convenience of getAvailableULocales + tempLocaleIdToCardinalRulesId = new TreeMap<String, String>(); + + for (Object[] langAndId : localeb) { + String id = (String) langAndId[0]; + String value = (String) langAndId[1]; + tempLocaleIdToCardinalRulesId.put(id, value); + } + + // Read ordinal-number rules. + localeb = (Object[][]) pluralb.getObject("locales_ordinals"); + tempLocaleIdToOrdinalRulesId = new TreeMap<String, String>(); + for (Object[] langAndId : localeb) { + String id = (String) langAndId[0]; + String value = (String) langAndId[1]; + tempLocaleIdToOrdinalRulesId.put(id, value); + } + } catch (MissingResourceException e) { + // dummy so we don't try again + tempLocaleIdToCardinalRulesId = Collections.emptyMap(); + tempLocaleIdToOrdinalRulesId = Collections.emptyMap(); + } + + synchronized(this) { + if (localeIdToCardinalRulesId == null) { + localeIdToCardinalRulesId = tempLocaleIdToCardinalRulesId; + localeIdToOrdinalRulesId = tempLocaleIdToOrdinalRulesId; + } + } + } + } + + /** + * 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(Locale locale, PluralType type) { + Map<String, String> idMap = getLocaleIdToRulesIdMap(type); + String lang = locale.getLanguage(); + String rulesId = idMap.get(lang); + return rulesId; + } + + /** + * Gets the rule from the rulesId. If there is no rule for this rulesId, + * return null. + */ + public PluralRules getRulesForRulesId(String rulesId) { + // synchronize on the map. release the lock temporarily while we build the rules. + PluralRules rules = null; + boolean hasRules; // Separate boolean because stored rules can be null. + synchronized (rulesIdToRules) { + hasRules = rulesIdToRules.containsKey(rulesId); + if (hasRules) { + rules = rulesIdToRules.get(rulesId); // can be null + } + } + if (!hasRules) { + try { + ResourceBundle pluralb = DATA_RB; + Object[][] rulesb = (Object[][]) pluralb.getObject("rules"); + Object[][] setb = null; + for (Object[] idAndRule : rulesb) { // Unbounded loop: We must find the rulesId. + if (rulesId.equals(idAndRule[0])) { + setb = (Object[][]) idAndRule[1]; + break; + } + } + + StringBuilder sb = new StringBuilder(); + for (Object[] keywordAndRule : setb) { + if (sb.length() > 0) { + sb.append("; "); + } + sb.append((String) keywordAndRule[0]); + sb.append(": "); + sb.append((String) keywordAndRule[1]); + } + rules = PluralRules.parseDescription(sb.toString()); + } catch (ParseException e) { + } catch (MissingResourceException e) { + } + synchronized (rulesIdToRules) { + if (rulesIdToRules.containsKey(rulesId)) { + rules = rulesIdToRules.get(rulesId); + } else { + rulesIdToRules.put(rulesId, rules); // can be null + } + } + } + return rules; + } + + /** + * 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(Locale locale, PluralRules.PluralType type) { + String rulesId = getRulesIdForLocale(locale, type); + 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(); +} |