• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 
18 package java.util;
19 
20 import java.io.IOException;
21 import java.io.ObjectInputStream;
22 import java.io.ObjectOutputStream;
23 import java.io.ObjectStreamField;
24 import java.io.Serializable;
25 import libcore.icu.ICU;
26 
27 /**
28  * {@code Locale} represents a language/country/variant combination. Locales are used to
29  * alter the presentation of information such as numbers or dates to suit the conventions
30  * in the region they describe.
31  *
32  * <p>The language codes are two-letter lowercase ISO language codes (such as "en") as defined by
33  * <a href="http://en.wikipedia.org/wiki/ISO_639-1">ISO 639-1</a>.
34  * The country codes are two-letter uppercase ISO country codes (such as "US") as defined by
35  * <a href="http://en.wikipedia.org/wiki/ISO_3166-1_alpha-3">ISO 3166-1</a>.
36  * The variant codes are unspecified.
37  *
38  * <p>Note that Java uses several deprecated two-letter codes. The Hebrew ("he") language
39  * code is rewritten as "iw", Indonesian ("id") as "in", and Yiddish ("yi") as "ji". This
40  * rewriting happens even if you construct your own {@code Locale} object, not just for
41  * instances returned by the various lookup methods.
42  *
43  * <a name="available_locales"><h3>Available locales</h3></a>
44  * <p>This class' constructors do no error checking. You can create a {@code Locale} for languages
45  * and countries that don't exist, and you can create instances for combinations that don't
46  * exist (such as "de_US" for "German as spoken in the US").
47  *
48  * <p>Note that locale data is not necessarily available for any of the locales pre-defined as
49  * constants in this class except for en_US, which is the only locale Java guarantees is always
50  * available.
51  *
52  * <p>It is also a mistake to assume that all devices have the same locales available.
53  * A device sold in the US will almost certainly support en_US and es_US, but not necessarily
54  * any locales with the same language but different countries (such as en_GB or es_ES),
55  * nor any locales for other languages (such as de_DE). The opposite may well be true for a device
56  * sold in Europe.
57  *
58  * <p>You can use {@link Locale#getDefault} to get an appropriate locale for the <i>user</i> of the
59  * device you're running on, or {@link Locale#getAvailableLocales} to get a list of all the locales
60  * available on the device you're running on.
61  *
62  * <a name="locale_data"><h3>Locale data</h3></a>
63  * <p>Note that locale data comes solely from ICU. User-supplied locale service providers (using
64  * the {@code java.text.spi} or {@code java.util.spi} mechanisms) are not supported.
65  *
66  * <p>Here are the versions of ICU (and the corresponding CLDR and Unicode versions) used in
67  * various Android releases:
68  * <table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
69  * <tr><td>cupcake/donut/eclair</td> <td>ICU 3.8</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-5">CLDR 1.5</a></td> <td><a href="http://www.unicode.org/versions/Unicode5.0.0/">Unicode 5.0</a></td></tr>
70  * <tr><td>froyo</td>                <td>ICU 4.2</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-7">CLDR 1.7</a></td> <td><a href="http://www.unicode.org/versions/Unicode5.1.0/">Unicode 5.1</a></td></tr>
71  * <tr><td>gingerbread/honeycomb</td><td>ICU 4.4</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-8">CLDR 1.8</a></td> <td><a href="http://www.unicode.org/versions/Unicode5.2.0/">Unicode 5.2</a></td></tr>
72  * <tr><td>ice cream sandwich</td>   <td>ICU 4.6</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-9">CLDR 1.9</a></td> <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
73  * <tr><td>jelly bean</td>           <td>ICU 4.8</td> <td><a href="http://cldr.unicode.org/index/downloads/cldr-2-0">CLDR 2.0</a></td> <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
74  * </table>
75  *
76  * <a name="default_locale"><h3>Be wary of the default locale</h3></a>
77  * <p>Note that there are many convenience methods that automatically use the default locale, but
78  * using them may lead to subtle bugs.
79  *
80  * <p>The default locale is appropriate for tasks that involve presenting data to the user. In
81  * this case, you want to use the user's date/time formats, number
82  * formats, rules for conversion to lowercase, and so on. In this case, it's safe to use the
83  * convenience methods.
84  *
85  * <p>The default locale is <i>not</i> appropriate for machine-readable output. The best choice
86  * there is usually {@code Locale.US}&nbsp;&ndash; this locale is guaranteed to be available on all
87  * devices, and the fact that it has no surprising special cases and is frequently used (especially
88  * for computer-computer communication) means that it tends to be the most efficient choice too.
89  *
90  * <p>A common mistake is to implicitly use the default locale when producing output meant to be
91  * machine-readable. This tends to work on the developer's test devices (especially because so many
92  * developers use en_US), but fails when run on a device whose user is in a more complex locale.
93  *
94  * <p>For example, if you're formatting integers some locales will use non-ASCII decimal
95  * digits. As another example, if you're formatting floating-point numbers some locales will use
96  * {@code ','} as the decimal point and {@code '.'} for digit grouping. That's correct for
97  * human-readable output, but likely to cause problems if presented to another
98  * computer ({@link Double#parseDouble} can't parse such a number, for example).
99  * You should also be wary of the {@link String#toLowerCase} and
100  * {@link String#toUpperCase} overloads that don't take a {@code Locale}: in Turkey, for example,
101  * the characters {@code 'i'} and {@code 'I'} won't be converted to {@code 'I'} and {@code 'i'}.
102  * This is the correct behavior for Turkish text (such as user input), but inappropriate for, say,
103  * HTTP headers.
104  */
105 public final class Locale implements Cloneable, Serializable {
106 
107     private static final long serialVersionUID = 9149081749638150636L;
108 
109     /**
110      * Locale constant for en_CA.
111      */
112     public static final Locale CANADA = new Locale(true, "en", "CA");
113 
114     /**
115      * Locale constant for fr_CA.
116      */
117     public static final Locale CANADA_FRENCH = new Locale(true, "fr", "CA");
118 
119     /**
120      * Locale constant for zh_CN.
121      */
122     public static final Locale CHINA = new Locale(true, "zh", "CN");
123 
124     /**
125      * Locale constant for zh.
126      */
127     public static final Locale CHINESE = new Locale(true, "zh", "");
128 
129     /**
130      * Locale constant for en.
131      */
132     public static final Locale ENGLISH = new Locale(true, "en", "");
133 
134     /**
135      * Locale constant for fr_FR.
136      */
137     public static final Locale FRANCE = new Locale(true, "fr", "FR");
138 
139     /**
140      * Locale constant for fr.
141      */
142     public static final Locale FRENCH = new Locale(true, "fr", "");
143 
144     /**
145      * Locale constant for de.
146      */
147     public static final Locale GERMAN = new Locale(true, "de", "");
148 
149     /**
150      * Locale constant for de_DE.
151      */
152     public static final Locale GERMANY = new Locale(true, "de", "DE");
153 
154     /**
155      * Locale constant for it.
156      */
157     public static final Locale ITALIAN = new Locale(true, "it", "");
158 
159     /**
160      * Locale constant for it_IT.
161      */
162     public static final Locale ITALY = new Locale(true, "it", "IT");
163 
164     /**
165      * Locale constant for ja_JP.
166      */
167     public static final Locale JAPAN = new Locale(true, "ja", "JP");
168 
169     /**
170      * Locale constant for ja.
171      */
172     public static final Locale JAPANESE = new Locale(true, "ja", "");
173 
174     /**
175      * Locale constant for ko_KR.
176      */
177     public static final Locale KOREA = new Locale(true, "ko", "KR");
178 
179     /**
180      * Locale constant for ko.
181      */
182     public static final Locale KOREAN = new Locale(true, "ko", "");
183 
184     /**
185      * Locale constant for zh_CN.
186      */
187     public static final Locale PRC = new Locale(true, "zh", "CN");
188 
189     /**
190      * Locale constant for the root locale. The root locale has an empty language,
191      * country, and variant.
192      *
193      * @since 1.6
194      */
195     public static final Locale ROOT = new Locale(true, "", "");
196 
197     /**
198      * Locale constant for zh_CN.
199      */
200     public static final Locale SIMPLIFIED_CHINESE = new Locale(true, "zh", "CN");
201 
202     /**
203      * Locale constant for zh_TW.
204      */
205     public static final Locale TAIWAN = new Locale(true, "zh", "TW");
206 
207     /**
208      * Locale constant for zh_TW.
209      */
210     public static final Locale TRADITIONAL_CHINESE = new Locale(true, "zh", "TW");
211 
212     /**
213      * Locale constant for en_GB.
214      */
215     public static final Locale UK = new Locale(true, "en", "GB");
216 
217     /**
218      * Locale constant for en_US.
219      */
220     public static final Locale US = new Locale(true, "en", "US");
221 
222     /**
223      * The current default locale. It is temporarily assigned to US because we
224      * need a default locale to lookup the real default locale.
225      */
226     private static Locale defaultLocale = US;
227 
228     static {
229         String language = System.getProperty("user.language", "en");
230         String region = System.getProperty("user.region", "US");
231         String variant = System.getProperty("user.variant", "");
232         defaultLocale = new Locale(language, region, variant);
233     }
234 
235     private transient String countryCode;
236     private transient String languageCode;
237     private transient String variantCode;
238     private transient String cachedToStringResult;
239 
240     /**
241      * There's a circular dependency between toLowerCase/toUpperCase and
242      * Locale.US. Work around this by avoiding these methods when constructing
243      * the built-in locales.
244      *
245      * @param unused required for this constructor to have a unique signature
246      */
Locale(boolean unused, String lowerCaseLanguageCode, String upperCaseCountryCode)247     private Locale(boolean unused, String lowerCaseLanguageCode, String upperCaseCountryCode) {
248         this.languageCode = lowerCaseLanguageCode;
249         this.countryCode = upperCaseCountryCode;
250         this.variantCode = "";
251     }
252 
253     /**
254      * Constructs a new {@code Locale} using the specified language.
255      */
Locale(String language)256     public Locale(String language) {
257         this(language, "", "");
258     }
259 
260     /**
261      * Constructs a new {@code Locale} using the specified language and country codes.
262      */
Locale(String language, String country)263     public Locale(String language, String country) {
264         this(language, country, "");
265     }
266 
267     /**
268      * Constructs a new {@code Locale} using the specified language, country,
269      * and variant codes.
270      */
Locale(String language, String country, String variant)271     public Locale(String language, String country, String variant) {
272         if (language == null || country == null || variant == null) {
273             throw new NullPointerException();
274         }
275         if (language.isEmpty() && country.isEmpty()) {
276             languageCode = "";
277             countryCode = "";
278             variantCode = variant;
279             return;
280         }
281 
282         languageCode = language.toLowerCase(Locale.US);
283         // Map new language codes to the obsolete language
284         // codes so the correct resource bundles will be used.
285         if (languageCode.equals("he")) {
286             languageCode = "iw";
287         } else if (languageCode.equals("id")) {
288             languageCode = "in";
289         } else if (languageCode.equals("yi")) {
290             languageCode = "ji";
291         }
292 
293         countryCode = country.toUpperCase(Locale.US);
294 
295         // Work around for be compatible with RI
296         variantCode = variant;
297     }
298 
clone()299     @Override public Object clone() {
300         try {
301             return super.clone();
302         } catch (CloneNotSupportedException e) {
303             throw new AssertionError(e);
304         }
305     }
306 
307     /**
308      * Returns true if {@code object} is a locale with the same language,
309      * country and variant.
310      */
equals(Object object)311     @Override public boolean equals(Object object) {
312         if (object == this) {
313             return true;
314         }
315         if (object instanceof Locale) {
316             Locale o = (Locale) object;
317             return languageCode.equals(o.languageCode)
318                     && countryCode.equals(o.countryCode)
319                     && variantCode.equals(o.variantCode);
320         }
321         return false;
322     }
323 
324     /**
325      * Returns the system's installed locales. This array always includes {@code
326      * Locale.US}, and usually several others. Most locale-sensitive classes
327      * offer their own {@code getAvailableLocales} method, which should be
328      * preferred over this general purpose method.
329      *
330      * @see java.text.BreakIterator#getAvailableLocales()
331      * @see java.text.Collator#getAvailableLocales()
332      * @see java.text.DateFormat#getAvailableLocales()
333      * @see java.text.DateFormatSymbols#getAvailableLocales()
334      * @see java.text.DecimalFormatSymbols#getAvailableLocales()
335      * @see java.text.NumberFormat#getAvailableLocales()
336      * @see java.util.Calendar#getAvailableLocales()
337      */
getAvailableLocales()338     public static Locale[] getAvailableLocales() {
339         return ICU.getAvailableLocales();
340     }
341 
342     /**
343      * Returns the country code for this locale, or {@code ""} if this locale
344      * doesn't correspond to a specific country.
345      */
getCountry()346     public String getCountry() {
347         return countryCode;
348     }
349 
350     /**
351      * Returns the user's preferred locale. This may have been overridden for
352      * this process with {@link #setDefault}.
353      *
354      * <p>Since the user's locale changes dynamically, avoid caching this value.
355      * Instead, use this method to look it up for each use.
356      */
getDefault()357     public static Locale getDefault() {
358         return defaultLocale;
359     }
360 
361     /**
362      * Equivalent to {@code getDisplayCountry(Locale.getDefault())}.
363      */
getDisplayCountry()364     public final String getDisplayCountry() {
365         return getDisplayCountry(getDefault());
366     }
367 
368     /**
369      * Returns the name of this locale's country, localized to {@code locale}.
370      * Returns the empty string if this locale does not correspond to a specific
371      * country.
372      */
getDisplayCountry(Locale locale)373     public String getDisplayCountry(Locale locale) {
374         if (countryCode.isEmpty()) {
375             return "";
376         }
377         String result = ICU.getDisplayCountryNative(toString(), locale.toString());
378         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
379             result = ICU.getDisplayCountryNative(toString(), Locale.getDefault().toString());
380         }
381         return result;
382     }
383 
384     /**
385      * Equivalent to {@code getDisplayLanguage(Locale.getDefault())}.
386      */
getDisplayLanguage()387     public final String getDisplayLanguage() {
388         return getDisplayLanguage(getDefault());
389     }
390 
391     /**
392      * Returns the name of this locale's language, localized to {@code locale}.
393      * If the language name is unknown, the language code is returned.
394      */
getDisplayLanguage(Locale locale)395     public String getDisplayLanguage(Locale locale) {
396         if (languageCode.isEmpty()) {
397             return "";
398         }
399         String result = ICU.getDisplayLanguageNative(toString(), locale.toString());
400         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
401             result = ICU.getDisplayLanguageNative(toString(), Locale.getDefault().toString());
402         }
403         return result;
404     }
405 
406     /**
407      * Equivalent to {@code getDisplayName(Locale.getDefault())}.
408      */
getDisplayName()409     public final String getDisplayName() {
410         return getDisplayName(getDefault());
411     }
412 
413     /**
414      * Returns this locale's language name, country name, and variant, localized
415      * to {@code locale}. The exact output form depends on whether this locale
416      * corresponds to a specific language, country and variant.
417      *
418      * <p>For example:
419      * <ul>
420      * <li>{@code new Locale("en").getDisplayName(Locale.US)} -> {@code English}
421      * <li>{@code new Locale("en", "US").getDisplayName(Locale.US)} -> {@code English (United States)}
422      * <li>{@code new Locale("en", "US", "POSIX").getDisplayName(Locale.US)} -> {@code English (United States,Computer)}
423      * <li>{@code new Locale("en").getDisplayName(Locale.FRANCE)} -> {@code anglais}
424      * <li>{@code new Locale("en", "US").getDisplayName(Locale.FRANCE)} -> {@code anglais (États-Unis)}
425      * <li>{@code new Locale("en", "US", "POSIX").getDisplayName(Locale.FRANCE)} -> {@code anglais (États-Unis,informatique)}.
426      * </ul>
427      */
getDisplayName(Locale locale)428     public String getDisplayName(Locale locale) {
429         int count = 0;
430         StringBuilder buffer = new StringBuilder();
431         if (!languageCode.isEmpty()) {
432             String displayLanguage = getDisplayLanguage(locale);
433             buffer.append(displayLanguage.isEmpty() ? languageCode : displayLanguage);
434             ++count;
435         }
436         if (!countryCode.isEmpty()) {
437             if (count == 1) {
438                 buffer.append(" (");
439             }
440             String displayCountry = getDisplayCountry(locale);
441             buffer.append(displayCountry.isEmpty() ? countryCode : displayCountry);
442             ++count;
443         }
444         if (!variantCode.isEmpty()) {
445             if (count == 1) {
446                 buffer.append(" (");
447             } else if (count == 2) {
448                 buffer.append(",");
449             }
450             String displayVariant = getDisplayVariant(locale);
451             buffer.append(displayVariant.isEmpty() ? variantCode : displayVariant);
452             ++count;
453         }
454         if (count > 1) {
455             buffer.append(")");
456         }
457         return buffer.toString();
458     }
459 
460     /**
461      * Returns the full variant name in the default {@code Locale} for the variant code of
462      * this {@code Locale}. If there is no matching variant name, the variant code is
463      * returned.
464      */
getDisplayVariant()465     public final String getDisplayVariant() {
466         return getDisplayVariant(getDefault());
467     }
468 
469     /**
470      * Returns the full variant name in the specified {@code Locale} for the variant code
471      * of this {@code Locale}. If there is no matching variant name, the variant code is
472      * returned.
473      */
getDisplayVariant(Locale locale)474     public String getDisplayVariant(Locale locale) {
475         if (variantCode.length() == 0) {
476             return variantCode;
477         }
478         String result = ICU.getDisplayVariantNative(toString(), locale.toString());
479         if (result == null) { // TODO: do we need to do this, or does ICU do it for us?
480             result = ICU.getDisplayVariantNative(toString(), Locale.getDefault().toString());
481         }
482         return result;
483     }
484 
485     /**
486      * Returns the three letter ISO country code which corresponds to the country
487      * code for this {@code Locale}.
488      */
getISO3Country()489     public String getISO3Country() {
490         if (countryCode.length() == 0) {
491             return countryCode;
492         }
493         return ICU.getISO3CountryNative(toString());
494     }
495 
496     /**
497      * Returns the three letter ISO language code which corresponds to the language
498      * code for this {@code Locale}.
499      */
getISO3Language()500     public String getISO3Language() {
501         if (languageCode.length() == 0) {
502             return languageCode;
503         }
504         return ICU.getISO3LanguageNative(toString());
505     }
506 
507     /**
508      * Returns an array of strings containing all the two-letter ISO country codes that can be
509      * used as the country code when constructing a {@code Locale}.
510      */
getISOCountries()511     public static String[] getISOCountries() {
512         return ICU.getISOCountries();
513     }
514 
515     /**
516      * Returns an array of strings containing all the two-letter ISO language codes that can be
517      * used as the language code when constructing a {@code Locale}.
518      */
getISOLanguages()519     public static String[] getISOLanguages() {
520         return ICU.getISOLanguages();
521     }
522 
523     /**
524      * Returns the language code for this {@code Locale} or the empty string if no language
525      * was set.
526      */
getLanguage()527     public String getLanguage() {
528         return languageCode;
529     }
530 
531     /**
532      * Returns the variant code for this {@code Locale} or an empty {@code String} if no variant
533      * was set.
534      */
getVariant()535     public String getVariant() {
536         return variantCode;
537     }
538 
539     @Override
hashCode()540     public synchronized int hashCode() {
541         return countryCode.hashCode() + languageCode.hashCode()
542                 + variantCode.hashCode();
543     }
544 
545     /**
546      * Overrides the default locale. This does not affect system configuration,
547      * and attempts to override the system-provided default locale may
548      * themselves be overridden by actual changes to the system configuration.
549      * Code that calls this method is usually incorrect, and should be fixed by
550      * passing the appropriate locale to each locale-sensitive method that's
551      * called.
552      */
setDefault(Locale locale)553     public synchronized static void setDefault(Locale locale) {
554         if (locale == null) {
555             throw new NullPointerException();
556         }
557         defaultLocale = locale;
558     }
559 
560     /**
561      * Returns the string representation of this {@code Locale}. It consists of the
562      * language code, country code and variant separated by underscores.
563      * If the language is missing the string begins
564      * with an underscore. If the country is missing there are 2 underscores
565      * between the language and the variant. The variant cannot stand alone
566      * without a language and/or country code: in this case this method would
567      * return the empty string.
568      *
569      * <p>Examples: "en", "en_US", "_US", "en__POSIX", "en_US_POSIX"
570      */
571     @Override
toString()572     public final String toString() {
573         String result = cachedToStringResult;
574         return (result == null) ? (cachedToStringResult = toNewString()) : result;
575     }
576 
toNewString()577     private String toNewString() {
578         // The string form of a locale that only has a variant is the empty string.
579         if (languageCode.length() == 0 && countryCode.length() == 0) {
580             return "";
581         }
582         // Otherwise, the output format is "ll_cc_variant", where language and country are always
583         // two letters, but the variant is an arbitrary length. A size of 11 characters has room
584         // for "en_US_POSIX", the largest "common" value. (In practice, the string form is almost
585         // always 5 characters: "ll_cc".)
586         StringBuilder result = new StringBuilder(11);
587         result.append(languageCode);
588         if (countryCode.length() > 0 || variantCode.length() > 0) {
589             result.append('_');
590         }
591         result.append(countryCode);
592         if (variantCode.length() > 0) {
593             result.append('_');
594         }
595         result.append(variantCode);
596         return result.toString();
597     }
598 
599     private static final ObjectStreamField[] serialPersistentFields = {
600         new ObjectStreamField("country", String.class),
601         new ObjectStreamField("hashcode", int.class),
602         new ObjectStreamField("language", String.class),
603         new ObjectStreamField("variant", String.class),
604     };
605 
writeObject(ObjectOutputStream stream)606     private void writeObject(ObjectOutputStream stream) throws IOException {
607         ObjectOutputStream.PutField fields = stream.putFields();
608         fields.put("country", countryCode);
609         fields.put("hashcode", -1);
610         fields.put("language", languageCode);
611         fields.put("variant", variantCode);
612         stream.writeFields();
613     }
614 
readObject(ObjectInputStream stream)615     private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
616         ObjectInputStream.GetField fields = stream.readFields();
617         countryCode = (String) fields.get("country", "");
618         languageCode = (String) fields.get("language", "");
619         variantCode = (String) fields.get("variant", "");
620     }
621 }
622