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— 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— 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— 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— 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— 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— 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 }
|