/* ************************************************************************************** * Copyright (C) 2009-2014, Google, Inc.; International Business Machines Corporation * * and others. All Rights Reserved. * ************************************************************************************** */ package com.ibm.icu.util; import java.util.MissingResourceException; import com.ibm.icu.impl.ICUResourceBundle; import com.ibm.icu.text.UnicodeSet; import com.ibm.icu.util.ULocale.Category; /** * A class for accessing miscellaneous data in the locale bundles * @author ram * @stable ICU 2.8 */ public final class LocaleData { // private static final String EXEMPLAR_CHARS = "ExemplarCharacters"; private static final String MEASUREMENT_SYSTEM = "MeasurementSystem"; private static final String PAPER_SIZE = "PaperSize"; private static final String LOCALE_DISPLAY_PATTERN = "localeDisplayPattern"; private static final String PATTERN = "pattern"; private static final String SEPARATOR = "separator"; private boolean noSubstitute; private ICUResourceBundle bundle; private ICUResourceBundle langBundle; /** * EXType for {@link #getExemplarSet(int, int)}. * Corresponds to the 'main' (aka 'standard') CLDR exemplars in * {@link "http://www.unicode.org/reports/tr35/tr35-general.html#Character_Elements"}. * @stable ICU 3.4 */ public static final int ES_STANDARD = 0; /** * EXType for {@link #getExemplarSet(int, int)}. * Corresponds to the 'auxiliary' CLDR exemplars in * {@link "http://www.unicode.org/reports/tr35/tr35-general.html#Character_Elements"}. * @stable ICU 3.4 */ public static final int ES_AUXILIARY = 1; /** * EXType for {@link #getExemplarSet(int, int)}. * Corresponds to the 'index' CLDR exemplars in * {@link "http://www.unicode.org/reports/tr35/tr35-general.html#Character_Elements"}. * @stable ICU 4.4 */ public static final int ES_INDEX = 2; /** * EXType for {@link #getExemplarSet(int, int)}. * Corresponds to the 'currencySymbol' CLDR exemplars in * {@link "http://www.unicode.org/reports/tr35/tr35-general.html#Character_Elements"}. * Note: This type is no longer supported. * @deprecated ICU 51 */ @Deprecated public static final int ES_CURRENCY = 3; /** * Corresponds to the 'punctuation' CLDR exemplars in * {@link "http://www.unicode.org/reports/tr35/tr35-general.html#Character_Elements"}. * EXType for {@link #getExemplarSet(int, int)}. * @stable ICU 49 */ public static final int ES_PUNCTUATION = 4; /** * Count of EXTypes for {@link #getExemplarSet(int, int)}. * @stable ICU 3.4 */ public static final int ES_COUNT = 5; /** * Delimiter type for {@link #getDelimiter(int)}. * @stable ICU 3.4 */ public static final int QUOTATION_START = 0; /** * Delimiter type for {@link #getDelimiter(int)}. * @stable ICU 3.4 */ public static final int QUOTATION_END = 1; /** * Delimiter type for {@link #getDelimiter(int)}. * @stable ICU 3.4 */ public static final int ALT_QUOTATION_START = 2; /** * Delimiter type for {@link #getDelimiter(int)}. * @stable ICU 3.4 */ public static final int ALT_QUOTATION_END = 3; /** * Count of delimiter types for {@link #getDelimiter(int)}. * @stable ICU 3.4 */ public static final int DELIMITER_COUNT = 4; // private constructor to prevent default construction ///CLOVER:OFF private LocaleData(){} ///CLOVER:ON /** * Returns the set of exemplar characters for a locale. Equivalent to calling {@link #getExemplarSet(ULocale, int, int)} with * the extype == {@link #ES_STANDARD}. * * @param locale Locale for which the exemplar character set * is to be retrieved. * @param options Bitmask for options to apply to the exemplar pattern. * Specify zero to retrieve the exemplar set as it is * defined in the locale data. Specify * UnicodeSet.CASE to retrieve a case-folded exemplar * set. See {@link UnicodeSet#applyPattern(String, * int)} for a complete list of valid options. The * IGNORE_SPACE bit is always set, regardless of the * value of 'options'. * @return The set of exemplar characters for the given locale. * @stable ICU 3.0 */ public static UnicodeSet getExemplarSet(ULocale locale, int options) { return LocaleData.getInstance(locale).getExemplarSet(options, ES_STANDARD); } /** * Returns the set of exemplar characters for a locale. * Equivalent to calling new LocaleData(locale).{@link #getExemplarSet(int, int)}. * * @param locale Locale for which the exemplar character set * is to be retrieved. * @param options Bitmask for options to apply to the exemplar pattern. * Specify zero to retrieve the exemplar set as it is * defined in the locale data. Specify * UnicodeSet.CASE to retrieve a case-folded exemplar * set. See {@link UnicodeSet#applyPattern(String, * int)} for a complete list of valid options. The * IGNORE_SPACE bit is always set, regardless of the * value of 'options'. * @param extype The type of exemplar character set to retrieve. * @return The set of exemplar characters for the given locale. * @stable ICU 3.0 */ public static UnicodeSet getExemplarSet(ULocale locale, int options, int extype) { return LocaleData.getInstance(locale).getExemplarSet(options, extype); } /** * Returns the set of exemplar characters for a locale. * * @param options Bitmask for options to apply to the exemplar pattern. * Specify zero to retrieve the exemplar set as it is * defined in the locale data. Specify * UnicodeSet.CASE to retrieve a case-folded exemplar * set. See {@link UnicodeSet#applyPattern(String, * int)} for a complete list of valid options. The * IGNORE_SPACE bit is always set, regardless of the * value of 'options'. * @param extype The type of exemplar set to be retrieved, * ES_STANDARD, ES_INDEX, ES_AUXILIARY, or ES_PUNCTUATION * @return The set of exemplar characters for the given locale. * If there is nothing available for the locale, * then null is returned if {@link #getNoSubstitute()} is true, otherwise the * root value is returned (which may be UnicodeSet.EMPTY). * @exception RuntimeException if the extype is invalid. * @stable ICU 3.4 */ public UnicodeSet getExemplarSet(int options, int extype) { String [] exemplarSetTypes = { "ExemplarCharacters", "AuxExemplarCharacters", "ExemplarCharactersIndex", "ExemplarCharactersCurrency", "ExemplarCharactersPunctuation" }; if (extype == ES_CURRENCY) { // currency symbol exemplar is no longer available return noSubstitute ? null : UnicodeSet.EMPTY; } try{ final String aKey = exemplarSetTypes[extype]; // will throw an out-of-bounds exception ICUResourceBundle stringBundle = (ICUResourceBundle) bundle.get(aKey); if ( noSubstitute && (stringBundle.getLoadingStatus() == ICUResourceBundle.FROM_ROOT) ) { return null; } String unicodeSetPattern = stringBundle.getString(); return new UnicodeSet(unicodeSetPattern, UnicodeSet.IGNORE_SPACE | options); } catch (ArrayIndexOutOfBoundsException aiooe) { throw new IllegalArgumentException(aiooe); } catch (Exception ex){ return noSubstitute ? null : UnicodeSet.EMPTY; } } /** * Gets the LocaleData object associated with the ULocale specified in locale * * @param locale Locale with thich the locale data object is associated. * @return A locale data object. * @stable ICU 3.4 */ public static final LocaleData getInstance(ULocale locale) { LocaleData ld = new LocaleData(); ld.bundle = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, locale); ld.langBundle = (ICUResourceBundle)UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_LANG_BASE_NAME, locale); ld.noSubstitute = false; return ld; } /** * Gets the LocaleData object associated with the default FORMAT locale * * @return A locale data object. * @see Category#FORMAT * @stable ICU 3.4 */ public static final LocaleData getInstance() { return LocaleData.getInstance(ULocale.getDefault(Category.FORMAT)); } /** * Sets the "no substitute" behavior of this locale data object. * * @param setting Value for the no substitute behavior. If TRUE, * methods of this locale data object will return * an error when no data is available for that method, * given the locale ID supplied to the constructor. * @stable ICU 3.4 */ public void setNoSubstitute(boolean setting) { noSubstitute = setting; } /** * Gets the "no substitute" behavior of this locale data object. * * @return Value for the no substitute behavior. If TRUE, * methods of this locale data object will return * an error when no data is available for that method, * given the locale ID supplied to the constructor. * @stable ICU 3.4 */ public boolean getNoSubstitute() { return noSubstitute; } private static final String [] DELIMITER_TYPES = { "quotationStart", "quotationEnd", "alternateQuotationStart", "alternateQuotationEnd" }; /** * Retrieves a delimiter string from the locale data. * * @param type The type of delimiter string desired. Currently, * the valid choices are QUOTATION_START, QUOTATION_END, * ALT_QUOTATION_START, or ALT_QUOTATION_END. * @return The desired delimiter string. * @stable ICU 3.4 */ public String getDelimiter(int type) { ICUResourceBundle delimitersBundle = (ICUResourceBundle) bundle.get("delimiters"); // Only some of the quotation marks may be here. So we make sure that we do a multilevel fallback. ICUResourceBundle stringBundle = delimitersBundle.getWithFallback(DELIMITER_TYPES[type]); if ( noSubstitute && (stringBundle.getLoadingStatus() == ICUResourceBundle.FROM_ROOT) ) return null; return stringBundle.getString(); } /** * Utility for getMeasurementSystem and getPaperSize */ private static UResourceBundle measurementTypeBundleForLocale(ULocale locale, String measurementType){ // Much of this is taken from getCalendarType in impl/CalendarUtil.java UResourceBundle measTypeBundle = null; ULocale fullLoc = ULocale.addLikelySubtags(locale); String region = fullLoc.getCountry(); try { UResourceBundle rb = UResourceBundle.getBundleInstance( ICUResourceBundle.ICU_BASE_NAME, "supplementalData", ICUResourceBundle.ICU_DATA_CLASS_LOADER); UResourceBundle measurementData = rb.get("measurementData"); UResourceBundle measDataBundle = null; try { measDataBundle = measurementData.get(region); measTypeBundle = measDataBundle.get(measurementType); } catch (MissingResourceException mre) { // use "001" as fallback measDataBundle = measurementData.get("001"); measTypeBundle = measDataBundle.get(measurementType); } } catch (MissingResourceException mre) { // fall through } return measTypeBundle; } /** * Enumeration for representing the measurement systems. * @stable ICU 2.8 */ public static final class MeasurementSystem{ /** * Measurement system specified by Le Système International d'Unités (SI) * otherwise known as Metric system. * @stable ICU 2.8 */ public static final MeasurementSystem SI = new MeasurementSystem(0); /** * Measurement system followed in the United States of America. * @stable ICU 2.8 */ public static final MeasurementSystem US = new MeasurementSystem(1); /** * Mix of metric and imperial units used in Great Britain. * @stable ICU 55 */ public static final MeasurementSystem UK = new MeasurementSystem(2); private int systemID; private MeasurementSystem(int id){ systemID = id; } private boolean equals(int id){ return systemID == id; } } /** * Returns the measurement system used in the locale specified by the locale. * * @param locale The locale for which the measurement system to be retrieved. * @return MeasurementSystem the measurement system used in the locale. * @stable ICU 3.0 */ public static final MeasurementSystem getMeasurementSystem(ULocale locale){ UResourceBundle sysBundle = measurementTypeBundleForLocale(locale, MEASUREMENT_SYSTEM); int system = sysBundle.getInt(); if(MeasurementSystem.US.equals(system)){ return MeasurementSystem.US; } if(MeasurementSystem.UK.equals(system)){ return MeasurementSystem.UK; } if(MeasurementSystem.SI.equals(system)){ return MeasurementSystem.SI; } // return null if the object is null or is not an instance // of integer indicating an error return null; } /** * A class that represents the size of letter head * used in the country * @stable ICU 2.8 */ public static final class PaperSize{ private int height; private int width; private PaperSize(int h, int w){ height = h; width = w; } /** * Retruns the height of the paper * @return the height * @stable ICU 2.8 */ public int getHeight(){ return height; } /** * Returns the width of the paper * @return the width * @stable ICU 2.8 */ public int getWidth(){ return width; } } /** * Returns the size of paper used in the locale. The paper sizes returned are always in * milli-meters. * @param locale The locale for which the measurement system to be retrieved. * @return The paper size used in the locale * @stable ICU 3.0 */ public static final PaperSize getPaperSize(ULocale locale){ UResourceBundle obj = measurementTypeBundleForLocale(locale, PAPER_SIZE); int[] size = obj.getIntVector(); return new PaperSize(size[0], size[1]); } /** * Returns LocaleDisplayPattern for this locale, e.g., {0}({1}) * @return locale display pattern as a String. * @stable ICU 4.2 */ public String getLocaleDisplayPattern() { ICUResourceBundle locDispBundle = (ICUResourceBundle) langBundle.get(LOCALE_DISPLAY_PATTERN); String localeDisplayPattern = locDispBundle.getStringWithFallback(PATTERN); return localeDisplayPattern; } /** * Returns LocaleDisplaySeparator for this locale. * @return locale display separator as a char. * @stable ICU 4.2 */ public String getLocaleSeparator() { String sub0 = "{0}"; String sub1 = "{1}"; ICUResourceBundle locDispBundle = (ICUResourceBundle) langBundle.get(LOCALE_DISPLAY_PATTERN); String localeSeparator = locDispBundle.getStringWithFallback(SEPARATOR); int index0 = localeSeparator.indexOf(sub0); int index1 = localeSeparator.indexOf(sub1); if (index0 >= 0 && index1 >= 0 && index0 <= index1) { return localeSeparator.substring(index0 + sub0.length(), index1); } return localeSeparator; } private static VersionInfo gCLDRVersion = null; /** * Returns the current CLDR version * @stable ICU 4.2 */ public static VersionInfo getCLDRVersion() { // fetching this data should be idempotent. if(gCLDRVersion == null) { // from ZoneMeta.java UResourceBundle supplementalDataBundle = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, "supplementalData", ICUResourceBundle.ICU_DATA_CLASS_LOADER); UResourceBundle cldrVersionBundle = supplementalDataBundle.get("cldrVersion"); gCLDRVersion = VersionInfo.getInstance(cldrVersionBundle.getString()); } return gCLDRVersion; } }