Home | History | Annotate | Download | only in icu
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.icu;
     18 
     19 import java.text.DateFormat;
     20 import java.util.Arrays;
     21 import java.util.HashMap;
     22 import java.util.Locale;
     23 
     24 /**
     25  * Passes locale-specific from ICU native code to Java.
     26  * <p>
     27  * Note that you share these; you must not alter any of the fields, nor their array elements
     28  * in the case of arrays. If you ever expose any of these things to user code, you must give
     29  * them a clone rather than the original.
     30  */
     31 public final class LocaleData {
     32     // A cache for the locale-specific data.
     33     private static final HashMap<String, LocaleData> localeDataCache = new HashMap<String, LocaleData>();
     34     static {
     35         // Ensure that we pull in the locale data for the root locale, en_US, and the
     36         // user's default locale. (All devices must support the root locale and en_US,
     37         // and they're used for various system things like HTTP headers.) Pre-populating
     38         // the cache is especially useful on Android because we'll share this via the Zygote.
     39         get(Locale.ROOT);
     40         get(Locale.US);
     41         get(Locale.getDefault());
     42     }
     43 
     44     // Used by Calendar.
     45     public Integer firstDayOfWeek;
     46     public Integer minimalDaysInFirstWeek;
     47 
     48     // Used by DateFormatSymbols.
     49     public String[] amPm;
     50     public String[] eras;
     51 
     52     public String[] longMonthNames;
     53     public String[] shortMonthNames;
     54     public String[] longStandAloneMonthNames;
     55     public String[] shortStandAloneMonthNames;
     56 
     57     public String[] longWeekdayNames;
     58     public String[] shortWeekdayNames;
     59     public String[] longStandAloneWeekdayNames;
     60     public String[] shortStandAloneWeekdayNames;
     61 
     62     public String fullTimeFormat;
     63     public String longTimeFormat;
     64     public String mediumTimeFormat;
     65     public String shortTimeFormat;
     66 
     67     public String fullDateFormat;
     68     public String longDateFormat;
     69     public String mediumDateFormat;
     70     public String shortDateFormat;
     71 
     72     // Used by DecimalFormatSymbols.
     73     public char zeroDigit;
     74     public char decimalSeparator;
     75     public char groupingSeparator;
     76     public char patternSeparator;
     77     public char percent;
     78     public char perMill;
     79     public char monetarySeparator;
     80     public char minusSign;
     81     public String exponentSeparator;
     82     public String infinity;
     83     public String NaN;
     84     // Also used by Currency.
     85     public String currencySymbol;
     86     public String internationalCurrencySymbol;
     87 
     88     // Used by DecimalFormat and NumberFormat.
     89     public String numberPattern;
     90     public String integerPattern;
     91     public String currencyPattern;
     92     public String percentPattern;
     93 
     94     private LocaleData() {
     95     }
     96 
     97     /**
     98      * Returns a shared LocaleData for the given locale.
     99      */
    100     public static LocaleData get(Locale locale) {
    101         if (locale == null) {
    102             locale = Locale.getDefault();
    103         }
    104         String localeName = locale.toString();
    105         synchronized (localeDataCache) {
    106             LocaleData localeData = localeDataCache.get(localeName);
    107             if (localeData != null) {
    108                 return localeData;
    109             }
    110         }
    111         LocaleData newLocaleData = initLocaleData(locale);
    112         synchronized (localeDataCache) {
    113             LocaleData localeData = localeDataCache.get(localeName);
    114             if (localeData != null) {
    115                 return localeData;
    116             }
    117             localeDataCache.put(localeName, newLocaleData);
    118             return newLocaleData;
    119         }
    120     }
    121 
    122     @Override public String toString() {
    123         return "LocaleData[" +
    124                 "firstDayOfWeek=" + firstDayOfWeek + "," +
    125                 "minimalDaysInFirstWeek=" + minimalDaysInFirstWeek + "," +
    126                 "amPm=" + Arrays.toString(amPm) + "," +
    127                 "eras=" + Arrays.toString(eras) + "," +
    128                 "longMonthNames=" + Arrays.toString(longMonthNames) + "," +
    129                 "shortMonthNames=" + Arrays.toString(shortMonthNames) + "," +
    130                 "longStandAloneMonthNames=" + Arrays.toString(longStandAloneMonthNames) + "," +
    131                 "shortStandAloneMonthNames=" + Arrays.toString(shortStandAloneMonthNames) + "," +
    132                 "longWeekdayNames=" + Arrays.toString(longWeekdayNames) + "," +
    133                 "shortWeekdayNames=" + Arrays.toString(shortWeekdayNames) + "," +
    134                 "longStandAloneWeekdayNames=" + Arrays.toString(longStandAloneWeekdayNames) + "," +
    135                 "shortStandAloneWeekdayNames=" + Arrays.toString(shortStandAloneWeekdayNames) + "," +
    136                 "fullTimeFormat=" + fullTimeFormat + "," +
    137                 "longTimeFormat=" + longTimeFormat + "," +
    138                 "mediumTimeFormat=" + mediumTimeFormat + "," +
    139                 "shortTimeFormat=" + shortTimeFormat + "," +
    140                 "fullDateFormat=" + fullDateFormat + "," +
    141                 "longDateFormat=" + longDateFormat + "," +
    142                 "mediumDateFormat=" + mediumDateFormat + "," +
    143                 "shortDateFormat=" + shortDateFormat + "," +
    144                 "zeroDigit=" + zeroDigit + "," +
    145                 "decimalSeparator=" + decimalSeparator + "," +
    146                 "groupingSeparator=" + groupingSeparator + "," +
    147                 "patternSeparator=" + patternSeparator + "," +
    148                 "percent=" + percent + "," +
    149                 "perMill=" + perMill + "," +
    150                 "monetarySeparator=" + monetarySeparator + "," +
    151                 "minusSign=" + minusSign + "," +
    152                 "exponentSeparator=" + exponentSeparator + "," +
    153                 "infinity=" + infinity + "," +
    154                 "NaN=" + NaN + "," +
    155                 "currencySymbol=" + currencySymbol + "," +
    156                 "internationalCurrencySymbol=" + internationalCurrencySymbol + "," +
    157                 "numberPattern=" + numberPattern + "," +
    158                 "integerPattern=" + integerPattern + "," +
    159                 "currencyPattern=" + currencyPattern + "," +
    160                 "percentPattern=" + percentPattern + "]";
    161     }
    162 
    163     public String getDateFormat(int style) {
    164         switch (style) {
    165         case DateFormat.SHORT:
    166             return shortDateFormat;
    167         case DateFormat.MEDIUM:
    168             return mediumDateFormat;
    169         case DateFormat.LONG:
    170             return longDateFormat;
    171         case DateFormat.FULL:
    172             return fullDateFormat;
    173         }
    174         throw new AssertionError();
    175     }
    176 
    177     public String getTimeFormat(int style) {
    178         switch (style) {
    179         case DateFormat.SHORT:
    180             return shortTimeFormat;
    181         case DateFormat.MEDIUM:
    182             return mediumTimeFormat;
    183         case DateFormat.LONG:
    184             return longTimeFormat;
    185         case DateFormat.FULL:
    186             return fullTimeFormat;
    187         }
    188         throw new AssertionError();
    189     }
    190 
    191     private static LocaleData initLocaleData(Locale locale) {
    192         LocaleData localeData = new LocaleData();
    193         if (!ICU.initLocaleDataImpl(locale.toString(), localeData)) {
    194             throw new AssertionError("couldn't initialize LocaleData for locale " + locale);
    195         }
    196         if (localeData.fullTimeFormat != null) {
    197             // There are some full time format patterns in ICU that use the pattern character 'v'.
    198             // Java doesn't accept this, so we replace it with 'z' which has about the same result
    199             // as 'v', the timezone name.
    200             // 'v' -> "PT", 'z' -> "PST", v is the generic timezone and z the standard tz
    201             // "vvvv" -> "Pacific Time", "zzzz" -> "Pacific Standard Time"
    202             localeData.fullTimeFormat = localeData.fullTimeFormat.replace('v', 'z');
    203         }
    204         if (localeData.numberPattern != null) {
    205             // The number pattern might contain positive and negative subpatterns. Arabic, for
    206             // example, might look like "#,##0.###;#,##0.###-" because the minus sign should be
    207             // written last. Macedonian supposedly looks something like "#,##0.###;(#,##0.###)".
    208             // (The negative subpattern is optional, though, and not present in most locales.)
    209             // By only swallowing '#'es and ','s after the '.', we ensure that we don't
    210             // accidentally eat too much.
    211             localeData.integerPattern = localeData.numberPattern.replaceAll("\\.[#,]*", "");
    212         }
    213         return localeData;
    214     }
    215 }
    216