• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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);
Locale.getDefault()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 
LocaleData()94     private LocaleData() {
95     }
96 
97     /**
98      * Returns a shared LocaleData for the given locale.
99      */
get(Locale locale)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 
toString()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 
getDateFormat(int style)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 
getTimeFormat(int style)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 
initLocaleData(Locale locale)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