2 *******************************************************************************
\r
3 * Copyright (C) 2008-2010, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.impl;
\r
9 import java.text.ParseException;
\r
10 import java.util.Collections;
\r
11 import java.util.HashMap;
\r
12 import java.util.Iterator;
\r
13 import java.util.Map;
\r
14 import java.util.MissingResourceException;
\r
15 import java.util.Set;
\r
16 import java.util.TreeMap;
\r
18 import com.ibm.icu.text.PluralRules;
\r
19 import com.ibm.icu.util.ULocale;
\r
20 import com.ibm.icu.util.UResourceBundle;
\r
23 * Loader for plural rules data.
\r
25 public class PluralRulesLoader {
\r
26 private final Map<String, PluralRules> rulesIdToRules;
\r
27 private Map<String, String> localeIdToRulesId; // lazy init, use
\r
28 // getLocaleIdToRulesIdMap to
\r
30 private Map<String, ULocale> rulesIdToEquivalentULocale; // lazy init, use
\r
31 // getRulesIdToEquivalentULocaleMap
\r
35 * Access through singleton.
\r
37 private PluralRulesLoader() {
\r
38 rulesIdToRules = new HashMap<String, PluralRules>();
\r
42 * Returns the locales for which we have plurals data. Utility for testing.
\r
44 public ULocale[] getAvailableULocales() {
\r
45 Set<String> keys = getLocaleIdToRulesIdMap().keySet();
\r
46 ULocale[] locales = new ULocale[keys.size()];
\r
48 for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {
\r
49 locales[n++] = ULocale.createCanonical(iter.next());
\r
55 * Returns the functionally equivalent locale.
\r
57 public ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable) {
\r
58 if (isAvailable != null && isAvailable.length > 0) {
\r
59 String localeId = ULocale.canonicalize(locale.getBaseName());
\r
60 Map<String, String> idMap = getLocaleIdToRulesIdMap();
\r
61 isAvailable[0] = idMap.containsKey(localeId);
\r
64 String rulesId = getRulesIdForLocale(locale);
\r
65 if (rulesId == null || rulesId.trim().length() == 0) {
\r
66 return ULocale.ROOT; // ultimate fallback
\r
69 ULocale result = getRulesIdToEquivalentULocaleMap().get(
\r
71 if (result == null) {
\r
72 return ULocale.ROOT; // ultimate fallback
\r
79 * Returns the lazily-constructed map.
\r
81 private Map<String, String> getLocaleIdToRulesIdMap() {
\r
82 checkBuildRulesIdMaps();
\r
83 return localeIdToRulesId;
\r
87 * Returns the lazily-constructed map.
\r
89 private Map<String, ULocale> getRulesIdToEquivalentULocaleMap() {
\r
90 checkBuildRulesIdMaps();
\r
91 return rulesIdToEquivalentULocale;
\r
95 * Lazily constructs the localeIdToRulesId and rulesIdToEquivalentULocale
\r
96 * maps if necessary. These exactly reflect the contents of the locales
\r
97 * resource in plurals.res.
\r
99 private void checkBuildRulesIdMaps() {
\r
100 if (localeIdToRulesId == null) {
\r
102 UResourceBundle pluralb = getPluralBundle();
\r
103 UResourceBundle localeb = pluralb.get("locales");
\r
104 localeIdToRulesId = new TreeMap<String, String>(); // sort for
\r
107 // getAvailableULocales
\r
108 rulesIdToEquivalentULocale = new HashMap<String, ULocale>(); // not
\r
110 for (int i = 0; i < localeb.getSize(); ++i) {
\r
111 UResourceBundle b = localeb.get(i);
\r
112 String id = b.getKey();
\r
113 String value = b.getString().intern();
\r
114 localeIdToRulesId.put(id, value);
\r
116 if (!rulesIdToEquivalentULocale.containsKey(value)) {
\r
117 rulesIdToEquivalentULocale.put(value, new ULocale(id));
\r
120 } catch (MissingResourceException e) {
\r
121 localeIdToRulesId = Collections.emptyMap(); // dummy so we don't
\r
124 rulesIdToEquivalentULocale = Collections.emptyMap();
\r
130 * Gets the rulesId from the locale,with locale fallback. If there is no
\r
131 * rulesId, return null. The rulesId might be the empty string if the rule
\r
132 * is the default rule.
\r
134 public String getRulesIdForLocale(ULocale locale) {
\r
135 Map<String, String> idMap = getLocaleIdToRulesIdMap();
\r
136 String localeId = ULocale.canonicalize(locale.getBaseName());
\r
137 String rulesId = null;
\r
138 while (null == (rulesId = idMap.get(localeId))) {
\r
139 int ix = localeId.lastIndexOf("_");
\r
143 localeId = localeId.substring(0, ix);
\r
149 * Gets the rule from the rulesId. If there is no rule for this rulesId,
\r
152 public PluralRules getRulesForRulesId(String rulesId) {
\r
153 PluralRules rules = rulesIdToRules.get(rulesId);
\r
154 if (rules == null) {
\r
156 UResourceBundle pluralb = getPluralBundle();
\r
157 UResourceBundle rulesb = pluralb.get("rules");
\r
158 UResourceBundle setb = rulesb.get(rulesId);
\r
160 StringBuilder sb = new StringBuilder();
\r
161 for (int i = 0; i < setb.getSize(); ++i) {
\r
162 UResourceBundle b = setb.get(i);
\r
166 sb.append(b.getKey());
\r
168 sb.append(b.getString());
\r
170 rules = PluralRules.parseDescription(sb.toString());
\r
171 } catch (ParseException e) {
\r
172 } catch (MissingResourceException e) {
\r
174 rulesIdToRules.put(rulesId, rules); // put even if null
\r
180 * Return the plurals resource. Note MissingResourceException is unchecked,
\r
181 * listed here for clarity. Callers should handle this exception.
\r
183 public UResourceBundle getPluralBundle() throws MissingResourceException {
\r
184 return ICUResourceBundle.getBundleInstance(
\r
185 ICUResourceBundle.ICU_BASE_NAME, "plurals",
\r
186 ICUResourceBundle.ICU_DATA_CLASS_LOADER, true);
\r
190 * Returns the plural rules for the the locale. If we don't have data,
\r
191 * com.ibm.icu.text.PluralRules.DEFAULT is returned.
\r
193 public PluralRules forLocale(ULocale locale) {
\r
194 String rulesId = getRulesIdForLocale(locale);
\r
195 if (rulesId == null || rulesId.trim().length() == 0) {
\r
196 return PluralRules.DEFAULT;
\r
198 PluralRules rules = getRulesForRulesId(rulesId);
\r
199 if (rules == null) {
\r
200 rules = PluralRules.DEFAULT;
\r
206 * The only instance of the loader.
\r
208 public static final PluralRulesLoader loader = new PluralRulesLoader();
\r