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