1 /* 2 ************************************************************************************** 3 * Copyright (C) 2009-2014, Google, Inc.; International Business Machines Corporation * 4 * and others. All Rights Reserved. * 5 ************************************************************************************** 6 */ 7 package com.ibm.icu.util; 8 9 import java.util.MissingResourceException; 10 11 import com.ibm.icu.impl.ICUResourceBundle; 12 import com.ibm.icu.text.UnicodeSet; 13 import com.ibm.icu.util.ULocale.Category; 14 15 /** 16 * A class for accessing miscellaneous data in the locale bundles 17 * @author ram 18 * @stable ICU 2.8 19 */ 20 public final class LocaleData { 21 22 // private static final String EXEMPLAR_CHARS = "ExemplarCharacters"; 23 private static final String MEASUREMENT_SYSTEM = "MeasurementSystem"; 24 private static final String PAPER_SIZE = "PaperSize"; 25 private static final String LOCALE_DISPLAY_PATTERN = "localeDisplayPattern"; 26 private static final String PATTERN = "pattern"; 27 private static final String SEPARATOR = "separator"; 28 private boolean noSubstitute; 29 private ICUResourceBundle bundle; 30 private ICUResourceBundle langBundle; 31 32 /** 33 * EXType for {@link #getExemplarSet(int, int)}. 34 * Corresponds to the 'main' (aka 'standard') CLDR exemplars in 35 * {@link "http://www.unicode.org/reports/tr35/tr35-general.html#Character_Elements"}. 36 * @stable ICU 3.4 37 */ 38 public static final int ES_STANDARD = 0; 39 40 /** 41 * EXType for {@link #getExemplarSet(int, int)}. 42 * Corresponds to the 'auxiliary' CLDR exemplars in 43 * {@link "http://www.unicode.org/reports/tr35/tr35-general.html#Character_Elements"}. 44 * @stable ICU 3.4 45 */ 46 public static final int ES_AUXILIARY = 1; 47 48 /** 49 * EXType for {@link #getExemplarSet(int, int)}. 50 * Corresponds to the 'index' CLDR exemplars in 51 * {@link "http://www.unicode.org/reports/tr35/tr35-general.html#Character_Elements"}. 52 * @stable ICU 4.4 53 */ 54 public static final int ES_INDEX = 2; 55 56 /** 57 * EXType for {@link #getExemplarSet(int, int)}. 58 * Corresponds to the 'currencySymbol' CLDR exemplars in 59 * {@link "http://www.unicode.org/reports/tr35/tr35-general.html#Character_Elements"}. 60 * Note: This type is no longer supported. 61 * @deprecated ICU 51 62 */ 63 @Deprecated 64 public static final int ES_CURRENCY = 3; 65 66 /** 67 * Corresponds to the 'punctuation' CLDR exemplars in 68 * {@link "http://www.unicode.org/reports/tr35/tr35-general.html#Character_Elements"}. 69 * EXType for {@link #getExemplarSet(int, int)}. 70 * @stable ICU 49 71 */ 72 public static final int ES_PUNCTUATION = 4; 73 74 /** 75 * Count of EXTypes for {@link #getExemplarSet(int, int)}. 76 * @stable ICU 3.4 77 */ 78 public static final int ES_COUNT = 5; 79 80 /** 81 * Delimiter type for {@link #getDelimiter(int)}. 82 * @stable ICU 3.4 83 */ 84 public static final int QUOTATION_START = 0; 85 86 /** 87 * Delimiter type for {@link #getDelimiter(int)}. 88 * @stable ICU 3.4 89 */ 90 public static final int QUOTATION_END = 1; 91 92 /** 93 * Delimiter type for {@link #getDelimiter(int)}. 94 * @stable ICU 3.4 95 */ 96 public static final int ALT_QUOTATION_START = 2; 97 98 /** 99 * Delimiter type for {@link #getDelimiter(int)}. 100 * @stable ICU 3.4 101 */ 102 public static final int ALT_QUOTATION_END = 3; 103 104 /** 105 * Count of delimiter types for {@link #getDelimiter(int)}. 106 * @stable ICU 3.4 107 */ 108 public static final int DELIMITER_COUNT = 4; 109 110 // private constructor to prevent default construction 111 ///CLOVER:OFF LocaleData()112 private LocaleData(){} 113 ///CLOVER:ON 114 115 /** 116 * Returns the set of exemplar characters for a locale. Equivalent to calling {@link #getExemplarSet(ULocale, int, int)} with 117 * the extype == {@link #ES_STANDARD}. 118 * 119 * @param locale Locale for which the exemplar character set 120 * is to be retrieved. 121 * @param options Bitmask for options to apply to the exemplar pattern. 122 * Specify zero to retrieve the exemplar set as it is 123 * defined in the locale data. Specify 124 * UnicodeSet.CASE to retrieve a case-folded exemplar 125 * set. See {@link UnicodeSet#applyPattern(String, 126 * int)} for a complete list of valid options. The 127 * IGNORE_SPACE bit is always set, regardless of the 128 * value of 'options'. 129 * @return The set of exemplar characters for the given locale. 130 * @stable ICU 3.0 131 */ getExemplarSet(ULocale locale, int options)132 public static UnicodeSet getExemplarSet(ULocale locale, int options) { 133 return LocaleData.getInstance(locale).getExemplarSet(options, ES_STANDARD); 134 } 135 136 /** 137 * Returns the set of exemplar characters for a locale. 138 * Equivalent to calling new LocaleData(locale).{@link #getExemplarSet(int, int)}. 139 * 140 * @param locale Locale for which the exemplar character set 141 * is to be retrieved. 142 * @param options Bitmask for options to apply to the exemplar pattern. 143 * Specify zero to retrieve the exemplar set as it is 144 * defined in the locale data. Specify 145 * UnicodeSet.CASE to retrieve a case-folded exemplar 146 * set. See {@link UnicodeSet#applyPattern(String, 147 * int)} for a complete list of valid options. The 148 * IGNORE_SPACE bit is always set, regardless of the 149 * value of 'options'. 150 * @param extype The type of exemplar character set to retrieve. 151 * @return The set of exemplar characters for the given locale. 152 * @stable ICU 3.0 153 */ getExemplarSet(ULocale locale, int options, int extype)154 public static UnicodeSet getExemplarSet(ULocale locale, int options, int extype) { 155 return LocaleData.getInstance(locale).getExemplarSet(options, extype); 156 } 157 158 /** 159 * Returns the set of exemplar characters for a locale. 160 * 161 * @param options Bitmask for options to apply to the exemplar pattern. 162 * Specify zero to retrieve the exemplar set as it is 163 * defined in the locale data. Specify 164 * UnicodeSet.CASE to retrieve a case-folded exemplar 165 * set. See {@link UnicodeSet#applyPattern(String, 166 * int)} for a complete list of valid options. The 167 * IGNORE_SPACE bit is always set, regardless of the 168 * value of 'options'. 169 * @param extype The type of exemplar set to be retrieved, 170 * ES_STANDARD, ES_INDEX, ES_AUXILIARY, or ES_PUNCTUATION 171 * @return The set of exemplar characters for the given locale. 172 * If there is nothing available for the locale, 173 * then null is returned if {@link #getNoSubstitute()} is true, otherwise the 174 * root value is returned (which may be UnicodeSet.EMPTY). 175 * @exception RuntimeException if the extype is invalid. 176 * @stable ICU 3.4 177 */ getExemplarSet(int options, int extype)178 public UnicodeSet getExemplarSet(int options, int extype) { 179 String [] exemplarSetTypes = { 180 "ExemplarCharacters", 181 "AuxExemplarCharacters", 182 "ExemplarCharactersIndex", 183 "ExemplarCharactersCurrency", 184 "ExemplarCharactersPunctuation" 185 }; 186 187 if (extype == ES_CURRENCY) { 188 // currency symbol exemplar is no longer available 189 return noSubstitute ? null : UnicodeSet.EMPTY; 190 } 191 192 try{ 193 final String aKey = exemplarSetTypes[extype]; // will throw an out-of-bounds exception 194 ICUResourceBundle stringBundle = (ICUResourceBundle) bundle.get(aKey); 195 196 if ( noSubstitute && (stringBundle.getLoadingStatus() == ICUResourceBundle.FROM_ROOT) ) { 197 return null; 198 } 199 String unicodeSetPattern = stringBundle.getString(); 200 return new UnicodeSet(unicodeSetPattern, UnicodeSet.IGNORE_SPACE | options); 201 } catch (ArrayIndexOutOfBoundsException aiooe) { 202 throw new IllegalArgumentException(aiooe); 203 } catch (Exception ex){ 204 return noSubstitute ? null : UnicodeSet.EMPTY; 205 } 206 } 207 208 /** 209 * Gets the LocaleData object associated with the ULocale specified in locale 210 * 211 * @param locale Locale with thich the locale data object is associated. 212 * @return A locale data object. 213 * @stable ICU 3.4 214 */ getInstance(ULocale locale)215 public static final LocaleData getInstance(ULocale locale) { 216 LocaleData ld = new LocaleData(); 217 ld.bundle = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale); 218 ld.langBundle = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_LANG_BASE_NAME, locale); 219 ld.noSubstitute = false; 220 return ld; 221 } 222 223 /** 224 * Gets the LocaleData object associated with the default <code>FORMAT</code> locale 225 * 226 * @return A locale data object. 227 * @see Category#FORMAT 228 * @stable ICU 3.4 229 */ getInstance()230 public static final LocaleData getInstance() { 231 return LocaleData.getInstance(ULocale.getDefault(Category.FORMAT)); 232 } 233 234 /** 235 * Sets the "no substitute" behavior of this locale data object. 236 * 237 * @param setting Value for the no substitute behavior. If TRUE, 238 * methods of this locale data object will return 239 * an error when no data is available for that method, 240 * given the locale ID supplied to the constructor. 241 * @stable ICU 3.4 242 */ setNoSubstitute(boolean setting)243 public void setNoSubstitute(boolean setting) { 244 noSubstitute = setting; 245 } 246 247 /** 248 * Gets the "no substitute" behavior of this locale data object. 249 * 250 * @return Value for the no substitute behavior. If TRUE, 251 * methods of this locale data object will return 252 * an error when no data is available for that method, 253 * given the locale ID supplied to the constructor. 254 * @stable ICU 3.4 255 */ getNoSubstitute()256 public boolean getNoSubstitute() { 257 return noSubstitute; 258 } 259 260 private static final String [] DELIMITER_TYPES = { 261 "quotationStart", 262 "quotationEnd", 263 "alternateQuotationStart", 264 "alternateQuotationEnd" 265 }; 266 267 /** 268 * Retrieves a delimiter string from the locale data. 269 * 270 * @param type The type of delimiter string desired. Currently, 271 * the valid choices are QUOTATION_START, QUOTATION_END, 272 * ALT_QUOTATION_START, or ALT_QUOTATION_END. 273 * @return The desired delimiter string. 274 * @stable ICU 3.4 275 */ getDelimiter(int type)276 public String getDelimiter(int type) { 277 ICUResourceBundle delimitersBundle = (ICUResourceBundle) bundle.get("delimiters"); 278 // Only some of the quotation marks may be here. So we make sure that we do a multilevel fallback. 279 ICUResourceBundle stringBundle = delimitersBundle.getWithFallback(DELIMITER_TYPES[type]); 280 281 if ( noSubstitute && (stringBundle.getLoadingStatus() == ICUResourceBundle.FROM_ROOT) ) 282 return null; 283 284 return stringBundle.getString(); 285 } 286 287 /** 288 * Utility for getMeasurementSystem and getPaperSize 289 */ measurementTypeBundleForLocale(ULocale locale, String measurementType)290 private static UResourceBundle measurementTypeBundleForLocale(ULocale locale, String measurementType){ 291 // Much of this is taken from getCalendarType in impl/CalendarUtil.java 292 UResourceBundle measTypeBundle = null; 293 ULocale fullLoc = ULocale.addLikelySubtags(locale); 294 String region = fullLoc.getCountry(); 295 try { 296 UResourceBundle rb = UResourceBundle.getBundleInstance( 297 ICUResourceBundle.ICU_BASE_NAME, 298 "supplementalData", 299 ICUResourceBundle.ICU_DATA_CLASS_LOADER); 300 UResourceBundle measurementData = rb.get("measurementData"); 301 UResourceBundle measDataBundle = null; 302 try { 303 measDataBundle = measurementData.get(region); 304 measTypeBundle = measDataBundle.get(measurementType); 305 } catch (MissingResourceException mre) { 306 // use "001" as fallback 307 measDataBundle = measurementData.get("001"); 308 measTypeBundle = measDataBundle.get(measurementType); 309 } 310 } catch (MissingResourceException mre) { 311 // fall through 312 } 313 return measTypeBundle; 314 } 315 316 317 /** 318 * Enumeration for representing the measurement systems. 319 * @stable ICU 2.8 320 */ 321 public static final class MeasurementSystem{ 322 /** 323 * Measurement system specified by Le Système International d'Unités (SI) 324 * otherwise known as Metric system. 325 * @stable ICU 2.8 326 */ 327 public static final MeasurementSystem SI = new MeasurementSystem(0); 328 329 /** 330 * Measurement system followed in the United States of America. 331 * @stable ICU 2.8 332 */ 333 public static final MeasurementSystem US = new MeasurementSystem(1); 334 335 /** 336 * Mix of metric and imperial units used in Great Britain. 337 * @stable ICU 55 338 */ 339 public static final MeasurementSystem UK = new MeasurementSystem(2); 340 341 private int systemID; MeasurementSystem(int id)342 private MeasurementSystem(int id){ 343 systemID = id; 344 } 345 equals(int id)346 private boolean equals(int id){ 347 return systemID == id; 348 } 349 } 350 351 /** 352 * Returns the measurement system used in the locale specified by the locale. 353 * 354 * @param locale The locale for which the measurement system to be retrieved. 355 * @return MeasurementSystem the measurement system used in the locale. 356 * @stable ICU 3.0 357 */ getMeasurementSystem(ULocale locale)358 public static final MeasurementSystem getMeasurementSystem(ULocale locale){ 359 UResourceBundle sysBundle = measurementTypeBundleForLocale(locale, MEASUREMENT_SYSTEM); 360 361 int system = sysBundle.getInt(); 362 if(MeasurementSystem.US.equals(system)){ 363 return MeasurementSystem.US; 364 } 365 if(MeasurementSystem.UK.equals(system)){ 366 return MeasurementSystem.UK; 367 } 368 if(MeasurementSystem.SI.equals(system)){ 369 return MeasurementSystem.SI; 370 } 371 // return null if the object is null or is not an instance 372 // of integer indicating an error 373 return null; 374 } 375 376 /** 377 * A class that represents the size of letter head 378 * used in the country 379 * @stable ICU 2.8 380 */ 381 public static final class PaperSize{ 382 private int height; 383 private int width; 384 PaperSize(int h, int w)385 private PaperSize(int h, int w){ 386 height = h; 387 width = w; 388 } 389 /** 390 * Retruns the height of the paper 391 * @return the height 392 * @stable ICU 2.8 393 */ getHeight()394 public int getHeight(){ 395 return height; 396 } 397 /** 398 * Returns the width of the paper 399 * @return the width 400 * @stable ICU 2.8 401 */ getWidth()402 public int getWidth(){ 403 return width; 404 } 405 } 406 407 /** 408 * Returns the size of paper used in the locale. The paper sizes returned are always in 409 * <em> milli-meters<em>. 410 * @param locale The locale for which the measurement system to be retrieved. 411 * @return The paper size used in the locale 412 * @stable ICU 3.0 413 */ getPaperSize(ULocale locale)414 public static final PaperSize getPaperSize(ULocale locale){ 415 UResourceBundle obj = measurementTypeBundleForLocale(locale, PAPER_SIZE); 416 int[] size = obj.getIntVector(); 417 return new PaperSize(size[0], size[1]); 418 } 419 420 /** 421 * Returns LocaleDisplayPattern for this locale, e.g., {0}({1}) 422 * @return locale display pattern as a String. 423 * @stable ICU 4.2 424 */ getLocaleDisplayPattern()425 public String getLocaleDisplayPattern() { 426 ICUResourceBundle locDispBundle = (ICUResourceBundle) langBundle.get(LOCALE_DISPLAY_PATTERN); 427 String localeDisplayPattern = locDispBundle.getStringWithFallback(PATTERN); 428 return localeDisplayPattern; 429 } 430 431 /** 432 * Returns LocaleDisplaySeparator for this locale. 433 * @return locale display separator as a char. 434 * @stable ICU 4.2 435 */ getLocaleSeparator()436 public String getLocaleSeparator() { 437 String sub0 = "{0}"; 438 String sub1 = "{1}"; 439 ICUResourceBundle locDispBundle = (ICUResourceBundle) langBundle.get(LOCALE_DISPLAY_PATTERN); 440 String localeSeparator = locDispBundle.getStringWithFallback(SEPARATOR); 441 int index0 = localeSeparator.indexOf(sub0); 442 int index1 = localeSeparator.indexOf(sub1); 443 if (index0 >= 0 && index1 >= 0 && index0 <= index1) { 444 return localeSeparator.substring(index0 + sub0.length(), index1); 445 } 446 return localeSeparator; 447 } 448 449 private static VersionInfo gCLDRVersion = null; 450 451 /** 452 * Returns the current CLDR version 453 * @stable ICU 4.2 454 */ getCLDRVersion()455 public static VersionInfo getCLDRVersion() { 456 // fetching this data should be idempotent. 457 if(gCLDRVersion == null) { 458 // from ZoneMeta.java 459 UResourceBundle supplementalDataBundle = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "supplementalData", ICUResourceBundle.ICU_DATA_CLASS_LOADER); 460 UResourceBundle cldrVersionBundle = supplementalDataBundle.get("cldrVersion"); 461 gCLDRVersion = VersionInfo.getInstance(cldrVersionBundle.getString()); 462 } 463 return gCLDRVersion; 464 } 465 } 466