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