]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_2_1-src/src/com/ibm/icu/impl/PluralRulesLoader.java
icu4jsrc
[Dictionary.git] / jars / icu4j-4_2_1-src / src / com / ibm / icu / impl / PluralRulesLoader.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 2008, International Business Machines Corporation and         *\r
4  * others. All Rights Reserved.                                                *\r
5  *******************************************************************************\r
6  */\r
7 package com.ibm.icu.impl;\r
8 \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
12 \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
20 \r
21 /**\r
22  * Loader for plural rules data.\r
23  */\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
28 \r
29   /**\r
30    * Access through singleton.\r
31    */\r
32   private PluralRulesLoader() {\r
33     rulesIdToRules = new HashMap();\r
34   }\r
35 \r
36   /**\r
37    * Returns the locales for which we have plurals data.\r
38    * Utility for testing.\r
39    */\r
40   public ULocale[] getAvailableULocales() {\r
41     Set keys = getLocaleIdToRulesIdMap().keySet();\r
42     ULocale[] locales = new ULocale[keys.size()];\r
43     int n = 0;\r
44     for (Iterator iter = keys.iterator(); iter.hasNext();) {\r
45       locales[n++] = ULocale.createCanonical((String) iter.next());\r
46     }\r
47     return locales;\r
48   }\r
49 \r
50   /**\r
51    * Returns the functionally equivalent locale.\r
52    */\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
58     }\r
59 \r
60     String rulesId = getRulesIdForLocale(locale);\r
61     if (rulesId == null || rulesId.trim().length() == 0) {\r
62       return ULocale.ROOT; // ultimate fallback\r
63     }\r
64 \r
65     ULocale result = (ULocale) getRulesIdToEquivalentULocaleMap().get(rulesId);\r
66     if (result == null) {\r
67       return ULocale.ROOT; // ultimate fallback\r
68     }\r
69 \r
70     return result;\r
71   }\r
72 \r
73   /**\r
74    * Returns the lazily-constructed map.\r
75    */\r
76   private Map getLocaleIdToRulesIdMap() {\r
77     checkBuildRulesIdMaps();\r
78     return localeIdToRulesId;\r
79   }\r
80 \r
81   /**\r
82    * Returns the lazily-constructed map.\r
83    */\r
84   private Map getRulesIdToEquivalentULocaleMap() {\r
85     checkBuildRulesIdMaps();\r
86     return rulesIdToEquivalentULocale;\r
87   }\r
88 \r
89   /**\r
90    * Lazily constructs the localeIdToRulesId and rulesIdToEquivalentULocale\r
91    * maps if necessary. These exactly reflect the contents of the locales resource\r
92    * in plurals.res.\r
93    */\r
94   private void checkBuildRulesIdMaps() {\r
95     if (localeIdToRulesId == null) {\r
96       try {\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
106 \r
107           if (!rulesIdToEquivalentULocale.containsKey(value)) {\r
108             rulesIdToEquivalentULocale.put(value, new ULocale(id));\r
109           }\r
110         }\r
111       }\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
115       }\r
116     }\r
117   }\r
118 \r
119   /**\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
123    */\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
130       if (ix == -1) {\r
131         break;\r
132       }\r
133       localeId = localeId.substring(0, ix);\r
134     }\r
135     return rulesId;\r
136   }\r
137 \r
138   /**\r
139    * Gets the rule from the rulesId.  If there is no rule for this rulesId,\r
140    * return null.\r
141    */\r
142   public PluralRules getRulesForRulesId(String rulesId) {\r
143     PluralRules rules = (PluralRules) rulesIdToRules.get(rulesId);\r
144     if (rules == null) {\r
145       try {\r
146         UResourceBundle pluralb = getPluralBundle();\r
147         UResourceBundle rulesb = pluralb.get("rules");\r
148         UResourceBundle setb = rulesb.get(rulesId);\r
149 \r
150         StringBuffer sb = new StringBuffer();\r
151         for (int i = 0; i < setb.getSize(); ++i) {\r
152           UResourceBundle b = setb.get(i);\r
153           if (i > 0) {\r
154             sb.append("; ");\r
155           }\r
156           sb.append(b.getKey());\r
157           sb.append(": ");\r
158           sb.append(b.getString());\r
159         }\r
160         rules = PluralRules.parseDescription(sb.toString());\r
161       } catch (ParseException e) {\r
162       } catch (MissingResourceException e) {\r
163       }\r
164       rulesIdToRules.put(rulesId, rules); // put even if null\r
165     }\r
166     return rules;\r
167   }\r
168 \r
169   /**\r
170    * Return the plurals resource.\r
171    * Note MissingResourceException is unchecked, listed here for clarity.\r
172    * Callers should handle this exception.\r
173    */\r
174   public UResourceBundle getPluralBundle() throws MissingResourceException {\r
175       return ICUResourceBundle.getBundleInstance(\r
176           ICUResourceBundle.ICU_BASE_NAME,\r
177           "plurals",\r
178           ICUResourceBundle.ICU_DATA_CLASS_LOADER,\r
179           true);\r
180   }\r
181 \r
182   /**\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
186    */\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
191     }\r
192     PluralRules rules = getRulesForRulesId(rulesId);\r
193     if (rules == null) {\r
194       rules = PluralRules.DEFAULT;\r
195     }\r
196     return rules;\r
197   }\r
198 \r
199   /**\r
200    * The only instance of the loader.\r
201    */\r
202   public static final PluralRulesLoader loader = new PluralRulesLoader();\r
203 }\r