]> gitweb.fperrin.net Git - Dictionary.git/blob - jars/icu4j-4_4_2-src/main/classes/core/src/com/ibm/icu/impl/PluralRulesLoader.java
go
[Dictionary.git] / jars / icu4j-4_4_2-src / main / classes / core / src / com / ibm / icu / impl / PluralRulesLoader.java
1 /*\r
2  *******************************************************************************\r
3  * Copyright (C) 2008-2010, 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 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
17 \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
21 \r
22 /**\r
23  * Loader for plural rules data.\r
24  */\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
29                                                    // access\r
30     private Map<String, ULocale> rulesIdToEquivalentULocale; // lazy init, use\r
31                                                              // getRulesIdToEquivalentULocaleMap\r
32                                                              // to access\r
33 \r
34     /**\r
35      * Access through singleton.\r
36      */\r
37     private PluralRulesLoader() {\r
38         rulesIdToRules = new HashMap<String, PluralRules>();\r
39     }\r
40 \r
41     /**\r
42      * Returns the locales for which we have plurals data. Utility for testing.\r
43      */\r
44     public ULocale[] getAvailableULocales() {\r
45         Set<String> keys = getLocaleIdToRulesIdMap().keySet();\r
46         ULocale[] locales = new ULocale[keys.size()];\r
47         int n = 0;\r
48         for (Iterator<String> iter = keys.iterator(); iter.hasNext();) {\r
49             locales[n++] = ULocale.createCanonical(iter.next());\r
50         }\r
51         return locales;\r
52     }\r
53 \r
54     /**\r
55      * Returns the functionally equivalent locale.\r
56      */\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
62         }\r
63 \r
64         String rulesId = getRulesIdForLocale(locale);\r
65         if (rulesId == null || rulesId.trim().length() == 0) {\r
66             return ULocale.ROOT; // ultimate fallback\r
67         }\r
68 \r
69         ULocale result = getRulesIdToEquivalentULocaleMap().get(\r
70                 rulesId);\r
71         if (result == null) {\r
72             return ULocale.ROOT; // ultimate fallback\r
73         }\r
74 \r
75         return result;\r
76     }\r
77 \r
78     /**\r
79      * Returns the lazily-constructed map.\r
80      */\r
81     private Map<String, String> getLocaleIdToRulesIdMap() {\r
82         checkBuildRulesIdMaps();\r
83         return localeIdToRulesId;\r
84     }\r
85 \r
86     /**\r
87      * Returns the lazily-constructed map.\r
88      */\r
89     private Map<String, ULocale> getRulesIdToEquivalentULocaleMap() {\r
90         checkBuildRulesIdMaps();\r
91         return rulesIdToEquivalentULocale;\r
92     }\r
93 \r
94     /**\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
98      */\r
99     private void checkBuildRulesIdMaps() {\r
100         if (localeIdToRulesId == null) {\r
101             try {\r
102                 UResourceBundle pluralb = getPluralBundle();\r
103                 UResourceBundle localeb = pluralb.get("locales");\r
104                 localeIdToRulesId = new TreeMap<String, String>(); // sort for\r
105                                                                    // convenience\r
106                                                                    // of\r
107                                                                    // getAvailableULocales\r
108                 rulesIdToEquivalentULocale = new HashMap<String, ULocale>(); // not\r
109                                                                              // visible\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
115 \r
116                     if (!rulesIdToEquivalentULocale.containsKey(value)) {\r
117                         rulesIdToEquivalentULocale.put(value, new ULocale(id));\r
118                     }\r
119                 }\r
120             } catch (MissingResourceException e) {\r
121                 localeIdToRulesId = Collections.emptyMap(); // dummy so we don't\r
122                                                             // try again, can\r
123                                                             // read\r
124                 rulesIdToEquivalentULocale = Collections.emptyMap();\r
125             }\r
126         }\r
127     }\r
128 \r
129     /**\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
133      */\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
140             if (ix == -1) {\r
141                 break;\r
142             }\r
143             localeId = localeId.substring(0, ix);\r
144         }\r
145         return rulesId;\r
146     }\r
147 \r
148     /**\r
149      * Gets the rule from the rulesId. If there is no rule for this rulesId,\r
150      * return null.\r
151      */\r
152     public PluralRules getRulesForRulesId(String rulesId) {\r
153         PluralRules rules = rulesIdToRules.get(rulesId);\r
154         if (rules == null) {\r
155             try {\r
156                 UResourceBundle pluralb = getPluralBundle();\r
157                 UResourceBundle rulesb = pluralb.get("rules");\r
158                 UResourceBundle setb = rulesb.get(rulesId);\r
159 \r
160                 StringBuilder sb = new StringBuilder();\r
161                 for (int i = 0; i < setb.getSize(); ++i) {\r
162                     UResourceBundle b = setb.get(i);\r
163                     if (i > 0) {\r
164                         sb.append("; ");\r
165                     }\r
166                     sb.append(b.getKey());\r
167                     sb.append(": ");\r
168                     sb.append(b.getString());\r
169                 }\r
170                 rules = PluralRules.parseDescription(sb.toString());\r
171             } catch (ParseException e) {\r
172             } catch (MissingResourceException e) {\r
173             }\r
174             rulesIdToRules.put(rulesId, rules); // put even if null\r
175         }\r
176         return rules;\r
177     }\r
178 \r
179     /**\r
180      * Return the plurals resource. Note MissingResourceException is unchecked,\r
181      * listed here for clarity. Callers should handle this exception.\r
182      */\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
187     }\r
188 \r
189     /**\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
192      */\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
197         }\r
198         PluralRules rules = getRulesForRulesId(rulesId);\r
199         if (rules == null) {\r
200             rules = PluralRules.DEFAULT;\r
201         }\r
202         return rules;\r
203     }\r
204 \r
205     /**\r
206      * The only instance of the loader.\r
207      */\r
208     public static final PluralRulesLoader loader = new PluralRulesLoader();\r
209 }\r