Home | History | Annotate | Download | only in util
      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      */
    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      */
    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      */
    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      */
    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 
    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      */
    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      */
    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      */
    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      */
    357     public static Locale getDefault() {
    358         return defaultLocale;
    359     }
    360 
    361     /**
    362      * Equivalent to {@code getDisplayCountry(Locale.getDefault())}.
    363      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    535     public String getVariant() {
    536         return variantCode;
    537     }
    538 
    539     @Override
    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      */
    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
    572     public final String toString() {
    573         String result = cachedToStringResult;
    574         return (result == null) ? (cachedToStringResult = toNewString()) : result;
    575     }
    576 
    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 
    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 
    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