1/* 2 ******************************************************************************* 3 * Copyright (C) 2009-2014, International Business Machines Corporation and * 4 * others. All Rights Reserved. * 5 ******************************************************************************* 6 */ 7package com.ibm.icu.text; 8 9import java.io.Serializable; 10import java.util.HashMap; 11import java.util.Iterator; 12import java.util.Locale; 13import java.util.Map; 14 15import com.ibm.icu.impl.CurrencyData; 16import com.ibm.icu.util.ICUCloneNotSupportedException; 17import com.ibm.icu.util.ULocale; 18import com.ibm.icu.util.ULocale.Category; 19 20/** 21 * This class represents the information needed by 22 * DecimalFormat to format currency plural, 23 * such as "3.00 US dollars" or "1.00 US dollar". 24 * DecimalFormat creates for itself an instance of 25 * CurrencyPluralInfo from its locale data. 26 * If you need to change any of these symbols, you can get the 27 * CurrencyPluralInfo object from your 28 * DecimalFormat and modify it. 29 * 30 * Following are the information needed for currency plural format and parse: 31 * locale information, 32 * plural rule of the locale, 33 * currency plural pattern of the locale. 34 * 35 * @stable ICU 4.2 36 */ 37 38public class CurrencyPluralInfo implements Cloneable, Serializable { 39 private static final long serialVersionUID = 1; 40 41 /** 42 * Create a CurrencyPluralInfo object for the default <code>FORMAT</code> locale. 43 * @see Category#FORMAT 44 * @stable ICU 4.2 45 */ 46 public CurrencyPluralInfo() { 47 initialize(ULocale.getDefault(Category.FORMAT)); 48 } 49 50 /** 51 * Create a CurrencyPluralInfo object for the given locale. 52 * @param locale the locale 53 * @stable ICU 4.2 54 */ 55 public CurrencyPluralInfo(Locale locale) { 56 initialize(ULocale.forLocale(locale)); 57 } 58 59 /** 60 * Create a CurrencyPluralInfo object for the given locale. 61 * @param locale the locale 62 * @stable ICU 4.2 63 */ 64 public CurrencyPluralInfo(ULocale locale) { 65 initialize(locale); 66 } 67 68 /** 69 * Gets a CurrencyPluralInfo instance for the default locale. 70 * 71 * @return A CurrencyPluralInfo instance. 72 * @stable ICU 4.2 73 */ 74 public static CurrencyPluralInfo getInstance() { 75 return new CurrencyPluralInfo(); 76 } 77 78 /** 79 * Gets a CurrencyPluralInfo instance for the given locale. 80 * 81 * @param locale the locale. 82 * @return A CurrencyPluralInfo instance. 83 * @stable ICU 4.2 84 */ 85 public static CurrencyPluralInfo getInstance(Locale locale) { 86 return new CurrencyPluralInfo(locale); 87 } 88 89 /** 90 * Gets a CurrencyPluralInfo instance for the given locale. 91 * 92 * @param locale the locale. 93 * @return A CurrencyPluralInfo instance. 94 * @stable ICU 4.2 95 */ 96 public static CurrencyPluralInfo getInstance(ULocale locale) { 97 return new CurrencyPluralInfo(locale); 98 } 99 100 /** 101 * Gets plural rules of this locale, used for currency plural format 102 * 103 * @return plural rule 104 * @stable ICU 4.2 105 */ 106 public PluralRules getPluralRules() { 107 return pluralRules; 108 } 109 110 /** 111 * Given a plural count, gets currency plural pattern of this locale, 112 * used for currency plural format 113 * 114 * @param pluralCount currency plural count 115 * @return a currency plural pattern based on plural count 116 * @stable ICU 4.2 117 */ 118 public String getCurrencyPluralPattern(String pluralCount) { 119 String currencyPluralPattern = pluralCountToCurrencyUnitPattern.get(pluralCount); 120 if (currencyPluralPattern == null) { 121 // fall back to "other" 122 if (!pluralCount.equals("other")) { 123 currencyPluralPattern = pluralCountToCurrencyUnitPattern.get("other"); 124 } 125 if (currencyPluralPattern == null) { 126 // no currencyUnitPatterns defined, 127 // fallback to predefined default. 128 // This should never happen when ICU resource files are 129 // available, since currencyUnitPattern of "other" is always 130 // defined in root. 131 currencyPluralPattern = defaultCurrencyPluralPattern; 132 } 133 } 134 return currencyPluralPattern; 135 } 136 137 /** 138 * Get locale 139 * 140 * @return locale 141 * 142 * @stable ICU 4.2 143 */ 144 public ULocale getLocale() { 145 return ulocale; 146 } 147 148 /** 149 * Set plural rules. These are initially set in the constructor based on the locale, 150 * and usually do not need to be changed. 151 * 152 * @param ruleDescription new plural rule description 153 * @stable ICU 4.2 154 */ 155 public void setPluralRules(String ruleDescription) { 156 pluralRules = PluralRules.createRules(ruleDescription); 157 } 158 159 /** 160 * Set currency plural patterns. These are initially set in the constructor based on the 161 * locale, and usually do not need to be changed. 162 * 163 * @param pluralCount the plural count for which the currency pattern will 164 * be overridden. 165 * @param pattern the new currency plural pattern 166 * @stable ICU 4.2 167 */ 168 public void setCurrencyPluralPattern(String pluralCount, String pattern) { 169 pluralCountToCurrencyUnitPattern.put(pluralCount, pattern); 170 } 171 172 /** 173 * Set locale. This also sets both the plural rules and the currency plural patterns to be 174 * the defaults for the locale. 175 * 176 * @param loc the new locale to set 177 * @stable ICU 4.2 178 */ 179 public void setLocale(ULocale loc) { 180 ulocale = loc; 181 initialize(loc); 182 } 183 184 /** 185 * Standard override 186 * 187 * @stable ICU 4.2 188 */ 189 public Object clone() { 190 try { 191 CurrencyPluralInfo other = (CurrencyPluralInfo) super.clone(); 192 // locale is immutable 193 other.ulocale = (ULocale)ulocale.clone(); 194 // plural rule is immutable 195 //other.pluralRules = pluralRules; 196 // clone content 197 //other.pluralCountToCurrencyUnitPattern = pluralCountToCurrencyUnitPattern; 198 other.pluralCountToCurrencyUnitPattern = new HashMap<String, String>(); 199 for (String pluralCount : pluralCountToCurrencyUnitPattern.keySet()) { 200 String currencyPattern = pluralCountToCurrencyUnitPattern.get(pluralCount); 201 other.pluralCountToCurrencyUnitPattern.put(pluralCount, currencyPattern); 202 } 203 return other; 204 } catch (CloneNotSupportedException e) { 205 throw new ICUCloneNotSupportedException(e); 206 } 207 } 208 209 /** 210 * Override equals 211 * 212 * @stable ICU 4.2 213 */ 214 public boolean equals(Object a) { 215 if (a instanceof CurrencyPluralInfo) { 216 CurrencyPluralInfo other = (CurrencyPluralInfo)a; 217 return pluralRules.equals(other.pluralRules) && 218 pluralCountToCurrencyUnitPattern.equals(other.pluralCountToCurrencyUnitPattern); 219 } 220 return false; 221 } 222 223 /** 224 * Mock implementation of hashCode(). This implementation always returns a constant 225 * value. When Java assertion is enabled, this method triggers an assertion failure. 226 * @internal 227 * @deprecated This API is ICU internal only. 228 */ 229 @Deprecated 230 public int hashCode() { 231 assert false : "hashCode not designed"; 232 return 42; 233 } 234 235 /** 236 * Given a number, returns the keyword of the first rule that applies 237 * to the number. 238 * @internal 239 * @deprecated This API is ICU internal only. 240 */ 241 @Deprecated 242 String select(double number) { 243 return pluralRules.select(number); 244 } 245 246 /** 247 * Given a number, returns the keyword of the first rule that applies 248 * to the number. 249 * @internal 250 * @deprecated This API is ICU internal only. 251 */ 252 @Deprecated 253 String select(PluralRules.FixedDecimal numberInfo) { 254 return pluralRules.select(numberInfo); 255 } 256 257 /** 258 * Currency plural pattern iterator. 259 * 260 * @return a iterator on the currency plural pattern key set. 261 */ 262 Iterator<String> pluralPatternIterator() { 263 return pluralCountToCurrencyUnitPattern.keySet().iterator(); 264 } 265 266 private void initialize(ULocale uloc) { 267 ulocale = uloc; 268 pluralRules = PluralRules.forLocale(uloc); 269 setupCurrencyPluralPattern(uloc); 270 } 271 272 private void setupCurrencyPluralPattern(ULocale uloc) { 273 pluralCountToCurrencyUnitPattern = new HashMap<String, String>(); 274 275 String numberStylePattern = NumberFormat.getPattern(uloc, NumberFormat.NUMBERSTYLE); 276 // Split the number style pattern into pos and neg if applicable 277 int separatorIndex = numberStylePattern.indexOf(";"); 278 String negNumberPattern = null; 279 if (separatorIndex != -1) { 280 negNumberPattern = numberStylePattern.substring(separatorIndex + 1); 281 numberStylePattern = numberStylePattern.substring(0, separatorIndex); 282 } 283 Map<String, String> map = CurrencyData.provider.getInstance(uloc, true).getUnitPatterns(); 284 for (Map.Entry<String, String> e : map.entrySet()) { 285 String pluralCount = e.getKey(); 286 String pattern = e.getValue(); 287 288 // replace {0} with numberStylePattern 289 // and {1} with triple currency sign 290 String patternWithNumber = pattern.replace("{0}", numberStylePattern); 291 String patternWithCurrencySign = patternWithNumber.replace("{1}", tripleCurrencyStr); 292 if (separatorIndex != -1) { 293 String negPattern = pattern; 294 String negWithNumber = negPattern.replace("{0}", negNumberPattern); 295 String negWithCurrSign = negWithNumber.replace("{1}", tripleCurrencyStr); 296 StringBuilder posNegPatterns = new StringBuilder(patternWithCurrencySign); 297 posNegPatterns.append(";"); 298 posNegPatterns.append(negWithCurrSign); 299 patternWithCurrencySign = posNegPatterns.toString(); 300 } 301 pluralCountToCurrencyUnitPattern.put(pluralCount, patternWithCurrencySign); 302 } 303 } 304 305 306 //-------------------- private data member --------------------- 307 // 308 // triple currency sign char array 309 private static final char[] tripleCurrencySign = {0xA4, 0xA4, 0xA4}; 310 // triple currency sign string 311 private static final String tripleCurrencyStr = new String(tripleCurrencySign); 312 313 // default currency plural pattern char array 314 private static final char[] defaultCurrencyPluralPatternChar = {0, '.', '#', '#', ' ', 0xA4, 0xA4, 0xA4}; 315 // default currency plural pattern string 316 private static final String defaultCurrencyPluralPattern = new String(defaultCurrencyPluralPatternChar); 317 318 // map from plural count to currency plural pattern, for example 319 // one (plural count) --> {0} {1} (currency plural pattern, 320 // in which {0} is the amount number, and {1} is the currency plural name). 321 private Map<String, String> pluralCountToCurrencyUnitPattern = null; 322 323 /* 324 * The plural rule is used to format currency plural name, 325 * for example: "3.00 US Dollars". 326 * If there are 3 currency signs in the currency pattern, 327 * the 3 currency signs will be replaced by the currency plural name. 328 */ 329 private PluralRules pluralRules = null; 330 331 // locale 332 private ULocale ulocale = null; 333} 334