2 *******************************************************************************
\r
3 * Copyright (C) 2008, International Business Machines Corporation and *
\r
4 * others. All Rights Reserved. *
\r
5 *******************************************************************************
\r
7 package com.ibm.icu.impl;
\r
9 import com.ibm.icu.text.PluralRules;
\r
10 import com.ibm.icu.util.ULocale;
\r
11 import com.ibm.icu.util.UResourceBundle;
\r
13 import java.text.ParseException;
\r
14 import java.util.HashMap;
\r
15 import java.util.Iterator;
\r
16 import java.util.Map;
\r
17 import java.util.MissingResourceException;
\r
18 import java.util.Set;
\r
19 import java.util.TreeMap;
\r
22 * Loader for plural rules data.
\r
24 public class PluralRulesLoader {
\r
25 private final Map rulesIdToRules;
\r
26 private Map localeIdToRulesId; // lazy init, use getLocaleIdToRulesIdMap to access
\r
27 private Map rulesIdToEquivalentULocale; // lazy init, use getRulesIdToEquivalentULocaleMap to access
\r
30 * Access through singleton.
\r
32 private PluralRulesLoader() {
\r
33 rulesIdToRules = new HashMap();
\r
37 * Returns the locales for which we have plurals data.
\r
38 * Utility for testing.
\r
40 public ULocale[] getAvailableULocales() {
\r
41 Set keys = getLocaleIdToRulesIdMap().keySet();
\r
42 ULocale[] locales = new ULocale[keys.size()];
\r
44 for (Iterator iter = keys.iterator(); iter.hasNext();) {
\r
45 locales[n++] = ULocale.createCanonical((String) iter.next());
\r
51 * Returns the functionally equivalent locale.
\r
53 public ULocale getFunctionalEquivalent(ULocale locale, boolean[] isAvailable) {
\r
54 if (isAvailable != null && isAvailable.length > 0) {
\r
55 String localeId = ULocale.canonicalize(locale.getBaseName());
\r
56 Map idMap = getLocaleIdToRulesIdMap();
\r
57 isAvailable[0] = idMap.containsKey(localeId);
\r
60 String rulesId = getRulesIdForLocale(locale);
\r
61 if (rulesId == null || rulesId.trim().length() == 0) {
\r
62 return ULocale.ROOT; // ultimate fallback
\r
65 ULocale result = (ULocale) getRulesIdToEquivalentULocaleMap().get(rulesId);
\r
66 if (result == null) {
\r
67 return ULocale.ROOT; // ultimate fallback
\r
74 * Returns the lazily-constructed map.
\r
76 private Map getLocaleIdToRulesIdMap() {
\r
77 checkBuildRulesIdMaps();
\r
78 return localeIdToRulesId;
\r
82 * Returns the lazily-constructed map.
\r
84 private Map getRulesIdToEquivalentULocaleMap() {
\r
85 checkBuildRulesIdMaps();
\r
86 return rulesIdToEquivalentULocale;
\r
90 * Lazily constructs the localeIdToRulesId and rulesIdToEquivalentULocale
\r
91 * maps if necessary. These exactly reflect the contents of the locales resource
\r
94 private void checkBuildRulesIdMaps() {
\r
95 if (localeIdToRulesId == null) {
\r
97 UResourceBundle pluralb = getPluralBundle();
\r
98 UResourceBundle localeb = pluralb.get("locales");
\r
99 localeIdToRulesId = new TreeMap(); // sort for convenience of getAvailableULocales
\r
100 rulesIdToEquivalentULocale = new HashMap(); // not visible
\r
101 for (int i = 0; i < localeb.getSize(); ++i) {
\r
102 UResourceBundle b = localeb.get(i);
\r
103 String id = b.getKey();
\r
104 String value = b.getString().intern();
\r
105 localeIdToRulesId.put(id, value);
\r
107 if (!rulesIdToEquivalentULocale.containsKey(value)) {
\r
108 rulesIdToEquivalentULocale.put(value, new ULocale(id));
\r
112 catch (MissingResourceException e) {
\r
113 localeIdToRulesId = new HashMap(); // dummy so we don't try again, can read
\r
114 rulesIdToEquivalentULocale = new HashMap();
\r
120 * Gets the rulesId from the locale,with locale fallback. If there is no
\r
121 * rulesId, return null. The rulesId might be the empty string if the
\r
122 * rule is the default rule.
\r
124 public String getRulesIdForLocale(ULocale locale) {
\r
125 Map idMap = getLocaleIdToRulesIdMap();
\r
126 String localeId = ULocale.canonicalize(locale.getBaseName());
\r
127 String rulesId = null;
\r
128 while (null == (rulesId = (String) idMap.get(localeId))) {
\r
129 int ix = localeId.lastIndexOf("_");
\r
133 localeId = localeId.substring(0, ix);
\r
139 * Gets the rule from the rulesId. If there is no rule for this rulesId,
\r
142 public PluralRules getRulesForRulesId(String rulesId) {
\r
143 PluralRules rules = (PluralRules) rulesIdToRules.get(rulesId);
\r
144 if (rules == null) {
\r
146 UResourceBundle pluralb = getPluralBundle();
\r
147 UResourceBundle rulesb = pluralb.get("rules");
\r
148 UResourceBundle setb = rulesb.get(rulesId);
\r
150 StringBuffer sb = new StringBuffer();
\r
151 for (int i = 0; i < setb.getSize(); ++i) {
\r
152 UResourceBundle b = setb.get(i);
\r
156 sb.append(b.getKey());
\r
158 sb.append(b.getString());
\r
160 rules = PluralRules.parseDescription(sb.toString());
\r
161 } catch (ParseException e) {
\r
162 } catch (MissingResourceException e) {
\r
164 rulesIdToRules.put(rulesId, rules); // put even if null
\r
170 * Return the plurals resource.
\r
171 * Note MissingResourceException is unchecked, listed here for clarity.
\r
172 * Callers should handle this exception.
\r
174 public UResourceBundle getPluralBundle() throws MissingResourceException {
\r
175 return ICUResourceBundle.getBundleInstance(
\r
176 ICUResourceBundle.ICU_BASE_NAME,
\r
178 ICUResourceBundle.ICU_DATA_CLASS_LOADER,
\r
183 * Returns the plural rules for the the locale.
\r
184 * If we don't have data,
\r
185 * com.ibm.icu.text.PluralRules.DEFAULT is returned.
\r
187 public PluralRules forLocale(ULocale locale) {
\r
188 String rulesId = getRulesIdForLocale(locale);
\r
189 if (rulesId == null || rulesId.trim().length() == 0) {
\r
190 return PluralRules.DEFAULT;
\r
192 PluralRules rules = getRulesForRulesId(rulesId);
\r
193 if (rules == null) {
\r
194 rules = PluralRules.DEFAULT;
\r
200 * The only instance of the loader.
\r
202 public static final PluralRulesLoader loader = new PluralRulesLoader();
\r