src/share/classes/java/util/Locale.java

Print this page
rev 5696 : 6336885: RFE: Locale Data Deployment Enhancements
4609153: Provide locale data for Indic locales
5104387: Support for gl_ES locale (galician language)
6337471: desktop/system locale preferences support
7056139: (cal) SPI support for locale-dependent Calendar parameters
7058206: Provide CalendarData SPI for week params and display field value names
7073852: Support multiple scripts for digits and decimal symbols per locale
7079560: [Fmt-Da] Context dependent month names support in SimpleDateFormat
7171324: getAvailableLocales() of locale sensitive services should return the actual availability of locales
7151414: (cal) Support calendar type identification
7168528: LocaleServiceProvider needs to be aware of Locale extensions
7171372: (cal) locale's default Calendar should be created if unknown calendar is specified
Summary: JEP 127: Improve Locale Data Packaging and Adopt Unicode CLDR Data (part 1 w/o packaging changes. by Naoto Sato and Masayoshi Okutsu)
   1 /*
   2  * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


  33  * of a License Agreement between Taligent and Sun. This technology
  34  * is protected by multiple US and International patents.
  35  *
  36  * This notice and attribution to Taligent may not be removed.
  37  * Taligent is a registered trademark of Taligent, Inc.
  38  *
  39  */
  40 
  41 package java.util;
  42 
  43 import java.io.IOException;
  44 import java.io.ObjectInputStream;
  45 import java.io.ObjectOutputStream;
  46 import java.io.ObjectStreamField;
  47 import java.io.Serializable;
  48 import java.security.AccessController;
  49 import java.text.MessageFormat;
  50 import java.util.spi.LocaleNameProvider;
  51 
  52 import sun.security.action.GetPropertyAction;
  53 import sun.util.LocaleServiceProviderPool;
  54 import sun.util.locale.BaseLocale;
  55 import sun.util.locale.InternalLocaleBuilder;
  56 import sun.util.locale.LanguageTag;
  57 import sun.util.locale.LocaleExtensions;
  58 import sun.util.locale.LocaleObjectCache;
  59 import sun.util.locale.LocaleSyntaxException;
  60 import sun.util.locale.LocaleUtils;
  61 import sun.util.locale.ParseStatus;
  62 import sun.util.locale.UnicodeLocaleExtension;
  63 import sun.util.resources.LocaleData;
  64 import sun.util.resources.OpenListResourceBundle;
  65 
  66 /**
  67  * A <code>Locale</code> object represents a specific geographical, political,
  68  * or cultural region. An operation that requires a <code>Locale</code> to perform
  69  * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
  70  * to tailor information for the user. For example, displaying a number
  71  * is a locale-sensitive operation&mdash; the number should be formatted
  72  * according to the customs and conventions of the user's native country,
  73  * region, or culture.
  74  *
  75  * <p> The <code>Locale</code> class implements identifiers
  76  * interchangeable with BCP 47 (IETF BCP 47, "Tags for Identifying
  77  * Languages"), with support for the LDML (UTS#35, "Unicode Locale
  78  * Data Markup Language") BCP 47-compatible extensions for locale data
  79  * exchange.
  80  *
  81  * <p> A <code>Locale</code> object logically consists of the fields
  82  * described below.
  83  *


 948      * <p>
 949      * <b>Note:</b>
 950      * <ul>
 951      * <li>ISO 639 is not a stable standard&mdash; some languages' codes have changed.
 952      * The list this function returns includes both the new and the old codes for the
 953      * languages whose codes have changed.
 954      * <li>The <code>Locale</code> class also supports language codes up to
 955      * 8 characters in length.  Therefore, the list returned by this method does
 956      * not contain ALL valid codes that can be used to create Locales.
 957      * </ul>
 958      */
 959     public static String[] getISOLanguages() {
 960         if (isoLanguages == null) {
 961             isoLanguages = getISO2Table(LocaleISOData.isoLanguageTable);
 962         }
 963         String[] result = new String[isoLanguages.length];
 964         System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
 965         return result;
 966     }
 967 
 968     private static final String[] getISO2Table(String table) {
 969         int len = table.length() / 5;
 970         String[] isoTable = new String[len];
 971         for (int i = 0, j = 0; i < len; i++, j += 5) {
 972             isoTable[i] = table.substring(j, j + 2);
 973         }
 974         return isoTable;
 975     }
 976 
 977     /**
 978      * Returns the language code of this Locale.
 979      *
 980      * <p><b>Note:</b> ISO 639 is not a stable standard&mdash; some languages' codes have changed.
 981      * Locale's constructor recognizes both the new and the old codes for the languages
 982      * whose codes have changed, but this function always returns the old code.  If you
 983      * want to check for a specific language whose code has changed, don't do
 984      * <pre>
 985      * if (locale.getLanguage().equals("he")) // BAD!
 986      *    ...
 987      * </pre>
 988      * Instead, do


1017      * or a UN M.49 3-digit code.
1018      *
1019      * @return The country/region code, or the empty string if none is defined.
1020      * @see #getDisplayCountry
1021      */
1022     public String getCountry() {
1023         return baseLocale.getRegion();
1024     }
1025 
1026     /**
1027      * Returns the variant code for this locale.
1028      *
1029      * @return The variant code, or the empty string if none is defined.
1030      * @see #getDisplayVariant
1031      */
1032     public String getVariant() {
1033         return baseLocale.getVariant();
1034     }
1035 
1036     /**
























1037      * Returns the extension (or private use) value associated with
1038      * the specified key, or null if there is no extension
1039      * associated with the key. To be well-formed, the key must be one
1040      * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so
1041      * for example 'z' and 'Z' represent the same extension.
1042      *
1043      * @param key the extension key
1044      * @return The extension, or null if this locale defines no
1045      * extension for the specified key.
1046      * @throws IllegalArgumentException if key is not well-formed
1047      * @see #PRIVATE_USE_EXTENSION
1048      * @see #UNICODE_LOCALE_EXTENSION
1049      * @since 1.7
1050      */
1051     public String getExtension(char key) {
1052         if (!LocaleExtensions.isValidKey(key)) {
1053             throw new IllegalArgumentException("Ill-formed extension key: " + key);
1054         }
1055         return (localeExtensions == null) ? null : localeExtensions.getExtensionValue(key);
1056     }
1057 
1058     /**
1059      * Returns the set of extension keys associated with this locale, or the
1060      * empty set if it has no extensions. The returned set is unmodifiable.
1061      * The keys will all be lower-case.
1062      *
1063      * @return The set of extension keys, or the empty set if this locale has
1064      * no extensions.
1065      * @since 1.7
1066      */
1067     public Set<Character> getExtensionKeys() {
1068         if (localeExtensions == null) {
1069             return Collections.emptySet();
1070         }
1071         return localeExtensions.getKeys();
1072     }
1073 
1074     /**
1075      * Returns the set of unicode locale attributes associated with
1076      * this locale, or the empty set if it has no attributes. The
1077      * returned set is unmodifiable.
1078      *
1079      * @return The set of attributes.
1080      * @since 1.7
1081      */
1082     public Set<String> getUnicodeLocaleAttributes() {
1083         if (localeExtensions == null) {
1084             return Collections.emptySet();
1085         }
1086         return localeExtensions.getUnicodeLocaleAttributes();
1087     }
1088 
1089     /**
1090      * Returns the Unicode locale type associated with the specified Unicode locale key
1091      * for this locale. Returns the empty string for keys that are defined with no type.
1092      * Returns null if the key is not defined. Keys are case-insensitive. The key must
1093      * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is
1094      * thrown.
1095      *
1096      * @param key the Unicode locale key
1097      * @return The Unicode locale type associated with the key, or null if the
1098      * locale does not define the key.
1099      * @throws IllegalArgumentException if the key is not well-formed
1100      * @throws NullPointerException if <code>key</code> is null
1101      * @since 1.7
1102      */
1103     public String getUnicodeLocaleType(String key) {
1104         if (!UnicodeLocaleExtension.isKey(key)) {
1105             throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
1106         }
1107         return (localeExtensions == null) ? null : localeExtensions.getUnicodeLocaleType(key);
1108     }
1109 
1110     /**
1111      * Returns the set of Unicode locale keys defined by this locale, or the empty set if
1112      * this locale has none.  The returned set is immutable.  Keys are all lower case.
1113      *
1114      * @return The set of Unicode locale keys, or the empty set if this locale has
1115      * no Unicode locale keywords.
1116      * @since 1.7
1117      */
1118     public Set<String> getUnicodeLocaleKeys() {
1119         if (localeExtensions == null) {
1120             return Collections.emptySet();
1121         }
1122         return localeExtensions.getUnicodeLocaleKeys();
1123     }
1124 
1125     /**
1126      * Package locale method returning the Locale's BaseLocale,
1127      * used by ResourceBundle


1268      * <li>A locale with language "no", country "NO", and variant
1269      * "NY", representing Norwegian Nynorsk (Norway), is converted
1270      * to a language tag "nn-NO".</li></ul>
1271      *
1272      * <p><b>Note:</b> Although the language tag created by this
1273      * method is well-formed (satisfies the syntax requirements
1274      * defined by the IETF BCP 47 specification), it is not
1275      * necessarily a valid BCP 47 language tag.  For example,
1276      * <pre>
1277      *   new Locale("xx", "YY").toLanguageTag();</pre>
1278      *
1279      * will return "xx-YY", but the language subtag "xx" and the
1280      * region subtag "YY" are invalid because they are not registered
1281      * in the IANA Language Subtag Registry.
1282      *
1283      * @return a BCP47 language tag representing the locale
1284      * @see #forLanguageTag(String)
1285      * @since 1.7
1286      */
1287     public String toLanguageTag() {




1288         LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
1289         StringBuilder buf = new StringBuilder();
1290 
1291         String subtag = tag.getLanguage();
1292         if (subtag.length() > 0) {
1293             buf.append(LanguageTag.canonicalizeLanguage(subtag));
1294         }
1295 
1296         subtag = tag.getScript();
1297         if (subtag.length() > 0) {
1298             buf.append(LanguageTag.SEP);
1299             buf.append(LanguageTag.canonicalizeScript(subtag));
1300         }
1301 
1302         subtag = tag.getRegion();
1303         if (subtag.length() > 0) {
1304             buf.append(LanguageTag.SEP);
1305             buf.append(LanguageTag.canonicalizeRegion(subtag));
1306         }
1307 


1311             // preserve casing
1312             buf.append(s);
1313         }
1314 
1315         subtags = tag.getExtensions();
1316         for (String s : subtags) {
1317             buf.append(LanguageTag.SEP);
1318             buf.append(LanguageTag.canonicalizeExtension(s));
1319         }
1320 
1321         subtag = tag.getPrivateuse();
1322         if (subtag.length() > 0) {
1323             if (buf.length() > 0) {
1324                 buf.append(LanguageTag.SEP);
1325             }
1326             buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
1327             // preserve casing
1328             buf.append(subtag);
1329         }
1330 
1331         return buf.toString();



1332     }



1333 
1334     /**
1335      * Returns a locale for the specified IETF BCP 47 language tag string.
1336      *
1337      * <p>If the specified language tag contains any ill-formed subtags,
1338      * the first such subtag and all following subtags are ignored.  Compare
1339      * to {@link Locale.Builder#setLanguageTag} which throws an exception
1340      * in this case.
1341      *
1342      * <p>The following <b>conversions</b> are performed:<ul>
1343      *
1344      * <li>The language code "und" is mapped to language "".
1345      *
1346      * <li>The language codes "he", "yi", and "id" are mapped to "iw",
1347      * "ji", and "in" respectively. (This is the same canonicalization
1348      * that's done in Locale's constructors.)
1349      *
1350      * <li>The portion of a private use subtag prefixed by "lvariant",
1351      * if any, is removed and appended to the variant field in the
1352      * result locale (without case normalization).  If it is then


1497      * If the country matches an ISO 3166-1 alpha-2 code, the
1498      * corresponding ISO 3166-1 alpha-3 uppercase code is returned.
1499      * If the locale doesn't specify a country, this will be the empty
1500      * string.
1501      *
1502      * <p>The ISO 3166-1 codes can be found on-line.
1503      *
1504      * @return A three-letter abbreviation of this locale's country.
1505      * @exception MissingResourceException Throws MissingResourceException if the
1506      * three-letter country abbreviation is not available for this locale.
1507      */
1508     public String getISO3Country() throws MissingResourceException {
1509         String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
1510         if (country3 == null) {
1511             throw new MissingResourceException("Couldn't find 3-letter country code for "
1512                     + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
1513         }
1514         return country3;
1515     }
1516 
1517     private static final String getISO3Code(String iso2Code, String table) {
1518         int codeLength = iso2Code.length();
1519         if (codeLength == 0) {
1520             return "";
1521         }
1522 
1523         int tableLength = table.length();
1524         int index = tableLength;
1525         if (codeLength == 2) {
1526             char c1 = iso2Code.charAt(0);
1527             char c2 = iso2Code.charAt(1);
1528             for (index = 0; index < tableLength; index += 5) {
1529                 if (table.charAt(index) == c1
1530                     && table.charAt(index + 1) == c2) {
1531                     break;
1532                 }
1533             }
1534         }
1535         return index < tableLength ? table.substring(index + 2, index + 5) : null;
1536     }
1537 


1623      * (say, we don't have a Japanese name for Croatia),
1624      * this function falls back on the English name, and finally
1625      * on the ISO code as a last-resort value.  If the locale doesn't specify a country,
1626      * this function returns the empty string.
1627      *
1628      * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1629      */
1630     public String getDisplayCountry(Locale inLocale) {
1631         return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY);
1632     }
1633 
1634     private String getDisplayString(String code, Locale inLocale, int type) {
1635         if (code.length() == 0) {
1636             return "";
1637         }
1638 
1639         if (inLocale == null) {
1640             throw new NullPointerException();
1641         }
1642 
1643         try {
1644             OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1645             String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
1646             String result = null;
1647 
1648             // Check whether a provider can provide an implementation that's closer
1649             // to the requested locale than what the Java runtime itself can provide.
1650             LocaleServiceProviderPool pool =
1651                 LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
1652             if (pool.hasProviders()) {
1653                 result = pool.getLocalizedObject(
1654                                     LocaleNameGetter.INSTANCE,
1655                                     inLocale, bundle, key,
1656                                     type, code);
1657             }
1658 
1659             if (result == null) {
1660                 result = bundle.getString(key);
1661             }
1662 
1663             if (result != null) {
1664                 return result;
1665             }
1666         }
1667         catch (Exception e) {
1668             // just fall through
1669         }
1670         return code;
1671     }
1672 
1673     /**
1674      * Returns a name for the locale's variant code that is appropriate for display to the
1675      * user.  If possible, the name will be localized for the default locale.  If the locale
1676      * doesn't specify a variant code, this function returns the empty string.
1677      */
1678     public final String getDisplayVariant() {
1679         return getDisplayVariant(getDefault(Category.DISPLAY));
1680     }
1681 
1682     /**
1683      * Returns a name for the locale's variant code that is appropriate for display to the
1684      * user.  If possible, the name will be localized for inLocale.  If the locale
1685      * doesn't specify a variant code, this function returns the empty string.
1686      *
1687      * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1688      */
1689     public String getDisplayVariant(Locale inLocale) {
1690         if (baseLocale.getVariant().length() == 0)
1691             return "";
1692 
1693         OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1694 
1695         String names[] = getDisplayVariantArray(bundle, inLocale);
1696 
1697         // Get the localized patterns for formatting a list, and use
1698         // them to format the list.
1699         String listPattern = null;
1700         String listCompositionPattern = null;
1701         try {
1702             listPattern = bundle.getString("ListPattern");
1703             listCompositionPattern = bundle.getString("ListCompositionPattern");
1704         } catch (MissingResourceException e) {
1705         }
1706         return formatList(names, listPattern, listCompositionPattern);
1707     }
1708 
1709     /**
1710      * Returns a name for the locale that is appropriate for display to the
1711      * user. This will be the values returned by getDisplayLanguage(),
1712      * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled
1713      * into a single string. The the non-empty values are used in order,


1731      * Returns a name for the locale that is appropriate for display
1732      * to the user.  This will be the values returned by
1733      * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(),
1734      * and getDisplayVariant() assembled into a single string.
1735      * The non-empty values are used in order,
1736      * with the second and subsequent names in parentheses.  For example:
1737      * <blockquote>
1738      * language (script, country, variant)<br>
1739      * language (country)<br>
1740      * language (variant)<br>
1741      * script (country)<br>
1742      * country<br>
1743      * </blockquote>
1744      * depending on which fields are specified in the locale.  If the
1745      * language, script, country, and variant fields are all empty,
1746      * this function returns the empty string.
1747      *
1748      * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1749      */
1750     public String getDisplayName(Locale inLocale) {
1751         OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1752 
1753         String languageName = getDisplayLanguage(inLocale);
1754         String scriptName = getDisplayScript(inLocale);
1755         String countryName = getDisplayCountry(inLocale);
1756         String[] variantNames = getDisplayVariantArray(bundle, inLocale);
1757 
1758         // Get the localized patterns for formatting a display name.
1759         String displayNamePattern = null;
1760         String listPattern = null;
1761         String listCompositionPattern = null;
1762         try {
1763             displayNamePattern = bundle.getString("DisplayNamePattern");
1764             listPattern = bundle.getString("ListPattern");
1765             listCompositionPattern = bundle.getString("ListCompositionPattern");
1766         } catch (MissingResourceException e) {
1767         }
1768 
1769         // The display name consists of a main name, followed by qualifiers.
1770         // Typically, the format is "MainName (Qualifier, Qualifier)" but this
1771         // depends on what pattern is stored in the display locale.


1777         // (an anomalous situation) then the display name is simply the variant's
1778         // display name.
1779         if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
1780             if (variantNames.length == 0) {
1781                 return "";
1782             } else {
1783                 return formatList(variantNames, listPattern, listCompositionPattern);
1784             }
1785         }
1786         ArrayList<String> names = new ArrayList<>(4);
1787         if (languageName.length() != 0) {
1788             names.add(languageName);
1789         }
1790         if (scriptName.length() != 0) {
1791             names.add(scriptName);
1792         }
1793         if (countryName.length() != 0) {
1794             names.add(countryName);
1795         }
1796         if (variantNames.length != 0) {
1797             for (String var : variantNames) {
1798                 names.add(var);
1799             }
1800         }
1801 
1802         // The first one in the main name
1803         mainName = names.get(0);
1804 
1805         // Others are qualifiers
1806         int numNames = names.size();
1807         qualifierNames = (numNames > 1) ?
1808                 names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
1809 
1810         // Create an array whose first element is the number of remaining
1811         // elements.  This serves as a selector into a ChoiceFormat pattern from
1812         // the resource.  The second and third elements are the main name and
1813         // the qualifier; if there are no qualifiers, the third element is
1814         // unused by the format pattern.
1815         Object[] displayNames = {
1816             new Integer(qualifierNames.length != 0 ? 2 : 1),
1817             mainName,
1818             // We could also just call formatList() and have it handle the empty
1819             // list case, but this is more efficient, and we want it to be
1820             // efficient since all the language-only locales will not have any


1826             return new MessageFormat(displayNamePattern).format(displayNames);
1827         }
1828         else {
1829             // If we cannot get the message format pattern, then we use a simple
1830             // hard-coded pattern.  This should not occur in practice unless the
1831             // installation is missing some core files (FormatData etc.).
1832             StringBuilder result = new StringBuilder();
1833             result.append((String)displayNames[1]);
1834             if (displayNames.length > 2) {
1835                 result.append(" (");
1836                 result.append((String)displayNames[2]);
1837                 result.append(')');
1838             }
1839             return result.toString();
1840         }
1841     }
1842 
1843     /**
1844      * Overrides Cloneable.
1845      */

1846     public Object clone()
1847     {
1848         try {
1849             Locale that = (Locale)super.clone();
1850             return that;
1851         } catch (CloneNotSupportedException e) {
1852             throw new InternalError(e);
1853         }
1854     }
1855 
1856     /**
1857      * Override hashCode.
1858      * Since Locales are often used in hashtables, caches the value
1859      * for speed.
1860      */
1861     @Override
1862     public int hashCode() {
1863         int hc = hashCodeValue;
1864         if (hc == 0) {
1865             hc = baseLocale.hashCode();


1893         if (localeExtensions == null) {
1894             return ((Locale)obj).localeExtensions == null;
1895         }
1896         return localeExtensions.equals(((Locale)obj).localeExtensions);
1897     }
1898 
1899     // ================= privates =====================================
1900 
1901     private transient BaseLocale baseLocale;
1902     private transient LocaleExtensions localeExtensions;
1903 
1904     /**
1905      * Calculated hashcode
1906      */
1907     private transient volatile int hashCodeValue = 0;
1908 
1909     private volatile static Locale defaultLocale = initDefault();
1910     private volatile static Locale defaultDisplayLocale = null;
1911     private volatile static Locale defaultFormatLocale = null;
1912 


1913     /**
1914      * Return an array of the display names of the variant.
1915      * @param bundle the ResourceBundle to use to get the display names
1916      * @return an array of display names, possible of zero length.
1917      */
1918     private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) {
1919         // Split the variant name into tokens separated by '_'.
1920         StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
1921         String[] names = new String[tokenizer.countTokens()];
1922 
1923         // For each variant token, lookup the display name.  If
1924         // not found, use the variant name itself.
1925         for (int i=0; i<names.length; ++i) {
1926             names[i] = getDisplayString(tokenizer.nextToken(),
1927                                 inLocale, DISPLAY_VARIANT);
1928         }
1929 
1930         return names;
1931     }
1932 
1933     /**
1934      * Format a list using given pattern strings.
1935      * If either of the patterns is null, then a the list is
1936      * formatted by concatenation with the delimiter ','.
1937      * @param stringList the list of strings to be formatted.
1938      * @param listPattern should create a MessageFormat taking 0-3 arguments
1939      * and formatting them into a list.
1940      * @param listCompositionPattern should take 2 arguments
1941      * and is used by composeList.
1942      * @return a string representing the list.
1943      */
1944     private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
1945         // If we have no list patterns, compose the list in a simple,
1946         // non-localized way.
1947         if (listPattern == null || listCompositionPattern == null) {
1948             StringBuffer result = new StringBuffer();
1949             for (int i=0; i<stringList.length; ++i) {
1950                 if (i>0) result.append(',');


1951                 result.append(stringList[i]);
1952             }
1953             return result.toString();
1954         }
1955 
1956         // Compose the list down to three elements if necessary
1957         if (stringList.length > 3) {
1958             MessageFormat format = new MessageFormat(listCompositionPattern);
1959             stringList = composeList(format, stringList);
1960         }
1961 
1962         // Rebuild the argument list with the list length as the first element
1963         Object[] args = new Object[stringList.length + 1];
1964         System.arraycopy(stringList, 0, args, 1, stringList.length);
1965         args[0] = new Integer(stringList.length);
1966 
1967         // Format it using the pattern in the resource
1968         MessageFormat format = new MessageFormat(listPattern);
1969         return format.format(args);
1970     }


1977      * @param list a list of strings
1978      * @return if the list is three elements or shorter, the same list;
1979      * otherwise, a new list of three elements.
1980      */
1981     private static String[] composeList(MessageFormat format, String[] list) {
1982         if (list.length <= 3) return list;
1983 
1984         // Use the given format to compose the first two elements into one
1985         String[] listItems = { list[0], list[1] };
1986         String newItem = format.format(listItems);
1987 
1988         // Form a new list one element shorter
1989         String[] newList = new String[list.length-1];
1990         System.arraycopy(list, 2, newList, 1, newList.length-1);
1991         newList[0] = newItem;
1992 
1993         // Recurse
1994         return composeList(format, newList);
1995     }
1996 







1997     /**
1998      * @serialField language    String
1999      *      language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
2000      * @serialField country     String
2001      *      country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
2002      * @serialField variant     String
2003      *      variant subtags separated by LOWLINE characters. (See <a href="java/util/Locale.html#getVariant()">getVariant()</a>)
2004      * @serialField hashcode    int
2005      *      deprecated, for forward compatibility only
2006      * @serialField script      String
2007      *      script subtag in title case (See <a href="java/util/Locale.html#getScript()">getScript()</a>)
2008      * @serialField extensions  String
2009      *      canonical representation of extensions, that is,
2010      *      BCP47 extensions in alphabetical order followed by
2011      *      BCP47 private use subtags, all in lower case letters
2012      *      separated by HYPHEN-MINUS characters.
2013      *      (See <a href="java/util/Locale.html#getExtensionKeys()">getExtensionKeys()</a>,
2014      *      <a href="java/util/Locale.html#getExtension(char)">getExtension(char)</a>)
2015      */
2016     private static final ObjectStreamField[] serialPersistentFields = {


2119             // ja_JP_JP -> u-ca-japanese (calendar = japanese)
2120             extensions = LocaleExtensions.CALENDAR_JAPANESE;
2121         } else if (LocaleUtils.caseIgnoreMatch(language, "th")
2122                 && script.length() == 0
2123                 && LocaleUtils.caseIgnoreMatch(country, "th")
2124                 && "TH".equals(variant)) {
2125             // th_TH_TH -> u-nu-thai (numbersystem = thai)
2126             extensions = LocaleExtensions.NUMBER_THAI;
2127         }
2128         return extensions;
2129     }
2130 
2131     /**
2132      * Obtains a localized locale names from a LocaleNameProvider
2133      * implementation.
2134      */
2135     private static class LocaleNameGetter
2136         implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
2137         private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
2138 

2139         public String getObject(LocaleNameProvider localeNameProvider,
2140                                 Locale locale,
2141                                 String key,
2142                                 Object... params) {
2143             assert params.length == 2;
2144             int type = (Integer)params[0];
2145             String code = (String)params[1];
2146 
2147             switch(type) {
2148             case DISPLAY_LANGUAGE:
2149                 return localeNameProvider.getDisplayLanguage(code, locale);
2150             case DISPLAY_COUNTRY:
2151                 return localeNameProvider.getDisplayCountry(code, locale);
2152             case DISPLAY_VARIANT:
2153                 return localeNameProvider.getDisplayVariant(code, locale);
2154             case DISPLAY_SCRIPT:
2155                 return localeNameProvider.getDisplayScript(code, locale);
2156             default:
2157                 assert false; // shouldn't happen
2158             }


   1 /*
   2  * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any


  33  * of a License Agreement between Taligent and Sun. This technology
  34  * is protected by multiple US and International patents.
  35  *
  36  * This notice and attribution to Taligent may not be removed.
  37  * Taligent is a registered trademark of Taligent, Inc.
  38  *
  39  */
  40 
  41 package java.util;
  42 
  43 import java.io.IOException;
  44 import java.io.ObjectInputStream;
  45 import java.io.ObjectOutputStream;
  46 import java.io.ObjectStreamField;
  47 import java.io.Serializable;
  48 import java.security.AccessController;
  49 import java.text.MessageFormat;
  50 import java.util.spi.LocaleNameProvider;
  51 
  52 import sun.security.action.GetPropertyAction;
  53 import sun.util.locale.provider.LocaleServiceProviderPool;
  54 import sun.util.locale.BaseLocale;
  55 import sun.util.locale.InternalLocaleBuilder;
  56 import sun.util.locale.LanguageTag;
  57 import sun.util.locale.LocaleExtensions;
  58 import sun.util.locale.LocaleObjectCache;
  59 import sun.util.locale.LocaleSyntaxException;
  60 import sun.util.locale.LocaleUtils;
  61 import sun.util.locale.ParseStatus;
  62 import sun.util.locale.provider.LocaleProviderAdapter;

  63 import sun.util.resources.OpenListResourceBundle;
  64 
  65 /**
  66  * A <code>Locale</code> object represents a specific geographical, political,
  67  * or cultural region. An operation that requires a <code>Locale</code> to perform
  68  * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
  69  * to tailor information for the user. For example, displaying a number
  70  * is a locale-sensitive operation&mdash; the number should be formatted
  71  * according to the customs and conventions of the user's native country,
  72  * region, or culture.
  73  *
  74  * <p> The <code>Locale</code> class implements identifiers
  75  * interchangeable with BCP 47 (IETF BCP 47, "Tags for Identifying
  76  * Languages"), with support for the LDML (UTS#35, "Unicode Locale
  77  * Data Markup Language") BCP 47-compatible extensions for locale data
  78  * exchange.
  79  *
  80  * <p> A <code>Locale</code> object logically consists of the fields
  81  * described below.
  82  *


 947      * <p>
 948      * <b>Note:</b>
 949      * <ul>
 950      * <li>ISO 639 is not a stable standard&mdash; some languages' codes have changed.
 951      * The list this function returns includes both the new and the old codes for the
 952      * languages whose codes have changed.
 953      * <li>The <code>Locale</code> class also supports language codes up to
 954      * 8 characters in length.  Therefore, the list returned by this method does
 955      * not contain ALL valid codes that can be used to create Locales.
 956      * </ul>
 957      */
 958     public static String[] getISOLanguages() {
 959         if (isoLanguages == null) {
 960             isoLanguages = getISO2Table(LocaleISOData.isoLanguageTable);
 961         }
 962         String[] result = new String[isoLanguages.length];
 963         System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
 964         return result;
 965     }
 966 
 967     private static String[] getISO2Table(String table) {
 968         int len = table.length() / 5;
 969         String[] isoTable = new String[len];
 970         for (int i = 0, j = 0; i < len; i++, j += 5) {
 971             isoTable[i] = table.substring(j, j + 2);
 972         }
 973         return isoTable;
 974     }
 975 
 976     /**
 977      * Returns the language code of this Locale.
 978      *
 979      * <p><b>Note:</b> ISO 639 is not a stable standard&mdash; some languages' codes have changed.
 980      * Locale's constructor recognizes both the new and the old codes for the languages
 981      * whose codes have changed, but this function always returns the old code.  If you
 982      * want to check for a specific language whose code has changed, don't do
 983      * <pre>
 984      * if (locale.getLanguage().equals("he")) // BAD!
 985      *    ...
 986      * </pre>
 987      * Instead, do


1016      * or a UN M.49 3-digit code.
1017      *
1018      * @return The country/region code, or the empty string if none is defined.
1019      * @see #getDisplayCountry
1020      */
1021     public String getCountry() {
1022         return baseLocale.getRegion();
1023     }
1024 
1025     /**
1026      * Returns the variant code for this locale.
1027      *
1028      * @return The variant code, or the empty string if none is defined.
1029      * @see #getDisplayVariant
1030      */
1031     public String getVariant() {
1032         return baseLocale.getVariant();
1033     }
1034 
1035     /**
1036      * Returns {@code true} if this {@code Locale} has any <a href="#def_extensions">
1037      * extensions</a>.
1038      *
1039      * @return {@code true} if this {@code Locale} has any extensions
1040      * @since 1.8
1041      */
1042     public boolean hasExtensions() {
1043         return localeExtensions != null;
1044     }
1045 
1046     /**
1047      * Returns a copy of this {@code Locale} with no <a href="#def_extensions">
1048      * extensions</a>. If this {@code Locale} has no extensions, this {@code Locale}
1049      * is returned.
1050      *
1051      * @return a copy of this {@code Locale} with no extensions, or {@code this}
1052      *         if {@code this} has no extensions
1053      * @since 1.8
1054      */
1055     public Locale stripExtensions() {
1056         return hasExtensions() ? Locale.getInstance(baseLocale, null) : this;
1057     }
1058 
1059     /**
1060      * Returns the extension (or private use) value associated with
1061      * the specified key, or null if there is no extension
1062      * associated with the key. To be well-formed, the key must be one
1063      * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so
1064      * for example 'z' and 'Z' represent the same extension.
1065      *
1066      * @param key the extension key
1067      * @return The extension, or null if this locale defines no
1068      * extension for the specified key.
1069      * @throws IllegalArgumentException if key is not well-formed
1070      * @see #PRIVATE_USE_EXTENSION
1071      * @see #UNICODE_LOCALE_EXTENSION
1072      * @since 1.7
1073      */
1074     public String getExtension(char key) {
1075         if (!LocaleExtensions.isValidKey(key)) {
1076             throw new IllegalArgumentException("Ill-formed extension key: " + key);
1077         }
1078         return hasExtensions() ? localeExtensions.getExtensionValue(key) : null;
1079     }
1080 
1081     /**
1082      * Returns the set of extension keys associated with this locale, or the
1083      * empty set if it has no extensions. The returned set is unmodifiable.
1084      * The keys will all be lower-case.
1085      *
1086      * @return The set of extension keys, or the empty set if this locale has
1087      * no extensions.
1088      * @since 1.7
1089      */
1090     public Set<Character> getExtensionKeys() {
1091         if (!hasExtensions()) {
1092             return Collections.emptySet();
1093         }
1094         return localeExtensions.getKeys();
1095     }
1096 
1097     /**
1098      * Returns the set of unicode locale attributes associated with
1099      * this locale, or the empty set if it has no attributes. The
1100      * returned set is unmodifiable.
1101      *
1102      * @return The set of attributes.
1103      * @since 1.7
1104      */
1105     public Set<String> getUnicodeLocaleAttributes() {
1106         if (!hasExtensions()) {
1107             return Collections.emptySet();
1108         }
1109         return localeExtensions.getUnicodeLocaleAttributes();
1110     }
1111 
1112     /**
1113      * Returns the Unicode locale type associated with the specified Unicode locale key
1114      * for this locale. Returns the empty string for keys that are defined with no type.
1115      * Returns null if the key is not defined. Keys are case-insensitive. The key must
1116      * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is
1117      * thrown.
1118      *
1119      * @param key the Unicode locale key
1120      * @return The Unicode locale type associated with the key, or null if the
1121      * locale does not define the key.
1122      * @throws IllegalArgumentException if the key is not well-formed
1123      * @throws NullPointerException if <code>key</code> is null
1124      * @since 1.7
1125      */
1126     public String getUnicodeLocaleType(String key) {
1127         if (!isUnicodeExtensionKey(key)) {
1128             throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
1129         }
1130         return hasExtensions() ? localeExtensions.getUnicodeLocaleType(key) : null;
1131     }
1132 
1133     /**
1134      * Returns the set of Unicode locale keys defined by this locale, or the empty set if
1135      * this locale has none.  The returned set is immutable.  Keys are all lower case.
1136      *
1137      * @return The set of Unicode locale keys, or the empty set if this locale has
1138      * no Unicode locale keywords.
1139      * @since 1.7
1140      */
1141     public Set<String> getUnicodeLocaleKeys() {
1142         if (localeExtensions == null) {
1143             return Collections.emptySet();
1144         }
1145         return localeExtensions.getUnicodeLocaleKeys();
1146     }
1147 
1148     /**
1149      * Package locale method returning the Locale's BaseLocale,
1150      * used by ResourceBundle


1291      * <li>A locale with language "no", country "NO", and variant
1292      * "NY", representing Norwegian Nynorsk (Norway), is converted
1293      * to a language tag "nn-NO".</li></ul>
1294      *
1295      * <p><b>Note:</b> Although the language tag created by this
1296      * method is well-formed (satisfies the syntax requirements
1297      * defined by the IETF BCP 47 specification), it is not
1298      * necessarily a valid BCP 47 language tag.  For example,
1299      * <pre>
1300      *   new Locale("xx", "YY").toLanguageTag();</pre>
1301      *
1302      * will return "xx-YY", but the language subtag "xx" and the
1303      * region subtag "YY" are invalid because they are not registered
1304      * in the IANA Language Subtag Registry.
1305      *
1306      * @return a BCP47 language tag representing the locale
1307      * @see #forLanguageTag(String)
1308      * @since 1.7
1309      */
1310     public String toLanguageTag() {
1311         if (languageTag != null) {
1312             return languageTag;
1313         }
1314 
1315         LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
1316         StringBuilder buf = new StringBuilder();
1317 
1318         String subtag = tag.getLanguage();
1319         if (subtag.length() > 0) {
1320             buf.append(LanguageTag.canonicalizeLanguage(subtag));
1321         }
1322 
1323         subtag = tag.getScript();
1324         if (subtag.length() > 0) {
1325             buf.append(LanguageTag.SEP);
1326             buf.append(LanguageTag.canonicalizeScript(subtag));
1327         }
1328 
1329         subtag = tag.getRegion();
1330         if (subtag.length() > 0) {
1331             buf.append(LanguageTag.SEP);
1332             buf.append(LanguageTag.canonicalizeRegion(subtag));
1333         }
1334 


1338             // preserve casing
1339             buf.append(s);
1340         }
1341 
1342         subtags = tag.getExtensions();
1343         for (String s : subtags) {
1344             buf.append(LanguageTag.SEP);
1345             buf.append(LanguageTag.canonicalizeExtension(s));
1346         }
1347 
1348         subtag = tag.getPrivateuse();
1349         if (subtag.length() > 0) {
1350             if (buf.length() > 0) {
1351                 buf.append(LanguageTag.SEP);
1352             }
1353             buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
1354             // preserve casing
1355             buf.append(subtag);
1356         }
1357 
1358         String langTag = buf.toString();
1359         synchronized (this) {
1360             if (languageTag == null) {
1361                 languageTag = langTag;
1362             }
1363         }
1364         return languageTag;
1365     }
1366 
1367     /**
1368      * Returns a locale for the specified IETF BCP 47 language tag string.
1369      *
1370      * <p>If the specified language tag contains any ill-formed subtags,
1371      * the first such subtag and all following subtags are ignored.  Compare
1372      * to {@link Locale.Builder#setLanguageTag} which throws an exception
1373      * in this case.
1374      *
1375      * <p>The following <b>conversions</b> are performed:<ul>
1376      *
1377      * <li>The language code "und" is mapped to language "".
1378      *
1379      * <li>The language codes "he", "yi", and "id" are mapped to "iw",
1380      * "ji", and "in" respectively. (This is the same canonicalization
1381      * that's done in Locale's constructors.)
1382      *
1383      * <li>The portion of a private use subtag prefixed by "lvariant",
1384      * if any, is removed and appended to the variant field in the
1385      * result locale (without case normalization).  If it is then


1530      * If the country matches an ISO 3166-1 alpha-2 code, the
1531      * corresponding ISO 3166-1 alpha-3 uppercase code is returned.
1532      * If the locale doesn't specify a country, this will be the empty
1533      * string.
1534      *
1535      * <p>The ISO 3166-1 codes can be found on-line.
1536      *
1537      * @return A three-letter abbreviation of this locale's country.
1538      * @exception MissingResourceException Throws MissingResourceException if the
1539      * three-letter country abbreviation is not available for this locale.
1540      */
1541     public String getISO3Country() throws MissingResourceException {
1542         String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
1543         if (country3 == null) {
1544             throw new MissingResourceException("Couldn't find 3-letter country code for "
1545                     + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
1546         }
1547         return country3;
1548     }
1549 
1550     private static String getISO3Code(String iso2Code, String table) {
1551         int codeLength = iso2Code.length();
1552         if (codeLength == 0) {
1553             return "";
1554         }
1555 
1556         int tableLength = table.length();
1557         int index = tableLength;
1558         if (codeLength == 2) {
1559             char c1 = iso2Code.charAt(0);
1560             char c2 = iso2Code.charAt(1);
1561             for (index = 0; index < tableLength; index += 5) {
1562                 if (table.charAt(index) == c1
1563                     && table.charAt(index + 1) == c2) {
1564                     break;
1565                 }
1566             }
1567         }
1568         return index < tableLength ? table.substring(index + 2, index + 5) : null;
1569     }
1570 


1656      * (say, we don't have a Japanese name for Croatia),
1657      * this function falls back on the English name, and finally
1658      * on the ISO code as a last-resort value.  If the locale doesn't specify a country,
1659      * this function returns the empty string.
1660      *
1661      * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1662      */
1663     public String getDisplayCountry(Locale inLocale) {
1664         return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY);
1665     }
1666 
1667     private String getDisplayString(String code, Locale inLocale, int type) {
1668         if (code.length() == 0) {
1669             return "";
1670         }
1671 
1672         if (inLocale == null) {
1673             throw new NullPointerException();
1674         }
1675 







1676         LocaleServiceProviderPool pool =
1677             LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
1678         String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
1679         String result = pool.getLocalizedObject(
1680                                 LocaleNameGetter.INSTANCE,
1681                                 inLocale, key, type, code);







1682             if (result != null) {
1683                 return result;
1684             }
1685 



1686         return code;
1687     }
1688 
1689     /**
1690      * Returns a name for the locale's variant code that is appropriate for display to the
1691      * user.  If possible, the name will be localized for the default locale.  If the locale
1692      * doesn't specify a variant code, this function returns the empty string.
1693      */
1694     public final String getDisplayVariant() {
1695         return getDisplayVariant(getDefault(Category.DISPLAY));
1696     }
1697 
1698     /**
1699      * Returns a name for the locale's variant code that is appropriate for display to the
1700      * user.  If possible, the name will be localized for inLocale.  If the locale
1701      * doesn't specify a variant code, this function returns the empty string.
1702      *
1703      * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1704      */
1705     public String getDisplayVariant(Locale inLocale) {
1706         if (baseLocale.getVariant().length() == 0)
1707             return "";
1708 
1709         OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale);
1710 
1711         String names[] = getDisplayVariantArray(bundle, inLocale);
1712 
1713         // Get the localized patterns for formatting a list, and use
1714         // them to format the list.
1715         String listPattern = null;
1716         String listCompositionPattern = null;
1717         try {
1718             listPattern = bundle.getString("ListPattern");
1719             listCompositionPattern = bundle.getString("ListCompositionPattern");
1720         } catch (MissingResourceException e) {
1721         }
1722         return formatList(names, listPattern, listCompositionPattern);
1723     }
1724 
1725     /**
1726      * Returns a name for the locale that is appropriate for display to the
1727      * user. This will be the values returned by getDisplayLanguage(),
1728      * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled
1729      * into a single string. The the non-empty values are used in order,


1747      * Returns a name for the locale that is appropriate for display
1748      * to the user.  This will be the values returned by
1749      * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(),
1750      * and getDisplayVariant() assembled into a single string.
1751      * The non-empty values are used in order,
1752      * with the second and subsequent names in parentheses.  For example:
1753      * <blockquote>
1754      * language (script, country, variant)<br>
1755      * language (country)<br>
1756      * language (variant)<br>
1757      * script (country)<br>
1758      * country<br>
1759      * </blockquote>
1760      * depending on which fields are specified in the locale.  If the
1761      * language, script, country, and variant fields are all empty,
1762      * this function returns the empty string.
1763      *
1764      * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1765      */
1766     public String getDisplayName(Locale inLocale) {
1767         OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale);
1768 
1769         String languageName = getDisplayLanguage(inLocale);
1770         String scriptName = getDisplayScript(inLocale);
1771         String countryName = getDisplayCountry(inLocale);
1772         String[] variantNames = getDisplayVariantArray(bundle, inLocale);
1773 
1774         // Get the localized patterns for formatting a display name.
1775         String displayNamePattern = null;
1776         String listPattern = null;
1777         String listCompositionPattern = null;
1778         try {
1779             displayNamePattern = bundle.getString("DisplayNamePattern");
1780             listPattern = bundle.getString("ListPattern");
1781             listCompositionPattern = bundle.getString("ListCompositionPattern");
1782         } catch (MissingResourceException e) {
1783         }
1784 
1785         // The display name consists of a main name, followed by qualifiers.
1786         // Typically, the format is "MainName (Qualifier, Qualifier)" but this
1787         // depends on what pattern is stored in the display locale.


1793         // (an anomalous situation) then the display name is simply the variant's
1794         // display name.
1795         if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
1796             if (variantNames.length == 0) {
1797                 return "";
1798             } else {
1799                 return formatList(variantNames, listPattern, listCompositionPattern);
1800             }
1801         }
1802         ArrayList<String> names = new ArrayList<>(4);
1803         if (languageName.length() != 0) {
1804             names.add(languageName);
1805         }
1806         if (scriptName.length() != 0) {
1807             names.add(scriptName);
1808         }
1809         if (countryName.length() != 0) {
1810             names.add(countryName);
1811         }
1812         if (variantNames.length != 0) {
1813             names.addAll(Arrays.asList(variantNames));

1814         }

1815 
1816         // The first one in the main name
1817         mainName = names.get(0);
1818 
1819         // Others are qualifiers
1820         int numNames = names.size();
1821         qualifierNames = (numNames > 1) ?
1822                 names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
1823 
1824         // Create an array whose first element is the number of remaining
1825         // elements.  This serves as a selector into a ChoiceFormat pattern from
1826         // the resource.  The second and third elements are the main name and
1827         // the qualifier; if there are no qualifiers, the third element is
1828         // unused by the format pattern.
1829         Object[] displayNames = {
1830             new Integer(qualifierNames.length != 0 ? 2 : 1),
1831             mainName,
1832             // We could also just call formatList() and have it handle the empty
1833             // list case, but this is more efficient, and we want it to be
1834             // efficient since all the language-only locales will not have any


1840             return new MessageFormat(displayNamePattern).format(displayNames);
1841         }
1842         else {
1843             // If we cannot get the message format pattern, then we use a simple
1844             // hard-coded pattern.  This should not occur in practice unless the
1845             // installation is missing some core files (FormatData etc.).
1846             StringBuilder result = new StringBuilder();
1847             result.append((String)displayNames[1]);
1848             if (displayNames.length > 2) {
1849                 result.append(" (");
1850                 result.append((String)displayNames[2]);
1851                 result.append(')');
1852             }
1853             return result.toString();
1854         }
1855     }
1856 
1857     /**
1858      * Overrides Cloneable.
1859      */
1860     @Override
1861     public Object clone()
1862     {
1863         try {
1864             Locale that = (Locale)super.clone();
1865             return that;
1866         } catch (CloneNotSupportedException e) {
1867             throw new InternalError(e);
1868         }
1869     }
1870 
1871     /**
1872      * Override hashCode.
1873      * Since Locales are often used in hashtables, caches the value
1874      * for speed.
1875      */
1876     @Override
1877     public int hashCode() {
1878         int hc = hashCodeValue;
1879         if (hc == 0) {
1880             hc = baseLocale.hashCode();


1908         if (localeExtensions == null) {
1909             return ((Locale)obj).localeExtensions == null;
1910         }
1911         return localeExtensions.equals(((Locale)obj).localeExtensions);
1912     }
1913 
1914     // ================= privates =====================================
1915 
1916     private transient BaseLocale baseLocale;
1917     private transient LocaleExtensions localeExtensions;
1918 
1919     /**
1920      * Calculated hashcode
1921      */
1922     private transient volatile int hashCodeValue = 0;
1923 
1924     private volatile static Locale defaultLocale = initDefault();
1925     private volatile static Locale defaultDisplayLocale = null;
1926     private volatile static Locale defaultFormatLocale = null;
1927 
1928     private transient volatile String languageTag;
1929 
1930     /**
1931      * Return an array of the display names of the variant.
1932      * @param bundle the ResourceBundle to use to get the display names
1933      * @return an array of display names, possible of zero length.
1934      */
1935     private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) {
1936         // Split the variant name into tokens separated by '_'.
1937         StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
1938         String[] names = new String[tokenizer.countTokens()];
1939 
1940         // For each variant token, lookup the display name.  If
1941         // not found, use the variant name itself.
1942         for (int i=0; i<names.length; ++i) {
1943             names[i] = getDisplayString(tokenizer.nextToken(),
1944                                 inLocale, DISPLAY_VARIANT);
1945         }
1946 
1947         return names;
1948     }
1949 
1950     /**
1951      * Format a list using given pattern strings.
1952      * If either of the patterns is null, then a the list is
1953      * formatted by concatenation with the delimiter ','.
1954      * @param stringList the list of strings to be formatted.
1955      * @param listPattern should create a MessageFormat taking 0-3 arguments
1956      * and formatting them into a list.
1957      * @param listCompositionPattern should take 2 arguments
1958      * and is used by composeList.
1959      * @return a string representing the list.
1960      */
1961     private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
1962         // If we have no list patterns, compose the list in a simple,
1963         // non-localized way.
1964         if (listPattern == null || listCompositionPattern == null) {
1965             StringBuilder result = new StringBuilder();
1966             for (int i = 0; i < stringList.length; ++i) {
1967                 if (i > 0) {
1968                     result.append(',');
1969                 }
1970                 result.append(stringList[i]);
1971             }
1972             return result.toString();
1973         }
1974 
1975         // Compose the list down to three elements if necessary
1976         if (stringList.length > 3) {
1977             MessageFormat format = new MessageFormat(listCompositionPattern);
1978             stringList = composeList(format, stringList);
1979         }
1980 
1981         // Rebuild the argument list with the list length as the first element
1982         Object[] args = new Object[stringList.length + 1];
1983         System.arraycopy(stringList, 0, args, 1, stringList.length);
1984         args[0] = new Integer(stringList.length);
1985 
1986         // Format it using the pattern in the resource
1987         MessageFormat format = new MessageFormat(listPattern);
1988         return format.format(args);
1989     }


1996      * @param list a list of strings
1997      * @return if the list is three elements or shorter, the same list;
1998      * otherwise, a new list of three elements.
1999      */
2000     private static String[] composeList(MessageFormat format, String[] list) {
2001         if (list.length <= 3) return list;
2002 
2003         // Use the given format to compose the first two elements into one
2004         String[] listItems = { list[0], list[1] };
2005         String newItem = format.format(listItems);
2006 
2007         // Form a new list one element shorter
2008         String[] newList = new String[list.length-1];
2009         System.arraycopy(list, 2, newList, 1, newList.length-1);
2010         newList[0] = newItem;
2011 
2012         // Recurse
2013         return composeList(format, newList);
2014     }
2015 
2016     // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to
2017     // avoid its class loading.
2018     private static boolean isUnicodeExtensionKey(String s) {
2019         // 2alphanum
2020         return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s);
2021     }
2022 
2023     /**
2024      * @serialField language    String
2025      *      language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
2026      * @serialField country     String
2027      *      country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
2028      * @serialField variant     String
2029      *      variant subtags separated by LOWLINE characters. (See <a href="java/util/Locale.html#getVariant()">getVariant()</a>)
2030      * @serialField hashcode    int
2031      *      deprecated, for forward compatibility only
2032      * @serialField script      String
2033      *      script subtag in title case (See <a href="java/util/Locale.html#getScript()">getScript()</a>)
2034      * @serialField extensions  String
2035      *      canonical representation of extensions, that is,
2036      *      BCP47 extensions in alphabetical order followed by
2037      *      BCP47 private use subtags, all in lower case letters
2038      *      separated by HYPHEN-MINUS characters.
2039      *      (See <a href="java/util/Locale.html#getExtensionKeys()">getExtensionKeys()</a>,
2040      *      <a href="java/util/Locale.html#getExtension(char)">getExtension(char)</a>)
2041      */
2042     private static final ObjectStreamField[] serialPersistentFields = {


2145             // ja_JP_JP -> u-ca-japanese (calendar = japanese)
2146             extensions = LocaleExtensions.CALENDAR_JAPANESE;
2147         } else if (LocaleUtils.caseIgnoreMatch(language, "th")
2148                 && script.length() == 0
2149                 && LocaleUtils.caseIgnoreMatch(country, "th")
2150                 && "TH".equals(variant)) {
2151             // th_TH_TH -> u-nu-thai (numbersystem = thai)
2152             extensions = LocaleExtensions.NUMBER_THAI;
2153         }
2154         return extensions;
2155     }
2156 
2157     /**
2158      * Obtains a localized locale names from a LocaleNameProvider
2159      * implementation.
2160      */
2161     private static class LocaleNameGetter
2162         implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
2163         private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
2164 
2165         @Override
2166         public String getObject(LocaleNameProvider localeNameProvider,
2167                                 Locale locale,
2168                                 String key,
2169                                 Object... params) {
2170             assert params.length == 2;
2171             int type = (Integer)params[0];
2172             String code = (String)params[1];
2173 
2174             switch(type) {
2175             case DISPLAY_LANGUAGE:
2176                 return localeNameProvider.getDisplayLanguage(code, locale);
2177             case DISPLAY_COUNTRY:
2178                 return localeNameProvider.getDisplayCountry(code, locale);
2179             case DISPLAY_VARIANT:
2180                 return localeNameProvider.getDisplayVariant(code, locale);
2181             case DISPLAY_SCRIPT:
2182                 return localeNameProvider.getDisplayScript(code, locale);
2183             default:
2184                 assert false; // shouldn't happen
2185             }