1 /* |
1 /* |
2 * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. |
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. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
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 |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
48 import java.security.AccessController; |
48 import java.security.AccessController; |
49 import java.text.MessageFormat; |
49 import java.text.MessageFormat; |
50 import java.util.spi.LocaleNameProvider; |
50 import java.util.spi.LocaleNameProvider; |
51 |
51 |
52 import sun.security.action.GetPropertyAction; |
52 import sun.security.action.GetPropertyAction; |
53 import sun.util.LocaleServiceProviderPool; |
53 import sun.util.locale.provider.LocaleServiceProviderPool; |
54 import sun.util.locale.BaseLocale; |
54 import sun.util.locale.BaseLocale; |
55 import sun.util.locale.InternalLocaleBuilder; |
55 import sun.util.locale.InternalLocaleBuilder; |
56 import sun.util.locale.LanguageTag; |
56 import sun.util.locale.LanguageTag; |
57 import sun.util.locale.LocaleExtensions; |
57 import sun.util.locale.LocaleExtensions; |
58 import sun.util.locale.LocaleObjectCache; |
58 import sun.util.locale.LocaleObjectCache; |
59 import sun.util.locale.LocaleSyntaxException; |
59 import sun.util.locale.LocaleSyntaxException; |
60 import sun.util.locale.LocaleUtils; |
60 import sun.util.locale.LocaleUtils; |
61 import sun.util.locale.ParseStatus; |
61 import sun.util.locale.ParseStatus; |
62 import sun.util.locale.UnicodeLocaleExtension; |
62 import sun.util.locale.provider.LocaleProviderAdapter; |
63 import sun.util.resources.LocaleData; |
|
64 import sun.util.resources.OpenListResourceBundle; |
63 import sun.util.resources.OpenListResourceBundle; |
65 |
64 |
66 /** |
65 /** |
67 * A <code>Locale</code> object represents a specific geographical, political, |
66 * A <code>Locale</code> object represents a specific geographical, political, |
68 * or cultural region. An operation that requires a <code>Locale</code> to perform |
67 * or cultural region. An operation that requires a <code>Locale</code> to perform |
963 String[] result = new String[isoLanguages.length]; |
962 String[] result = new String[isoLanguages.length]; |
964 System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length); |
963 System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length); |
965 return result; |
964 return result; |
966 } |
965 } |
967 |
966 |
968 private static final String[] getISO2Table(String table) { |
967 private static String[] getISO2Table(String table) { |
969 int len = table.length() / 5; |
968 int len = table.length() / 5; |
970 String[] isoTable = new String[len]; |
969 String[] isoTable = new String[len]; |
971 for (int i = 0, j = 0; i < len; i++, j += 5) { |
970 for (int i = 0, j = 0; i < len; i++, j += 5) { |
972 isoTable[i] = table.substring(j, j + 2); |
971 isoTable[i] = table.substring(j, j + 2); |
973 } |
972 } |
1032 public String getVariant() { |
1031 public String getVariant() { |
1033 return baseLocale.getVariant(); |
1032 return baseLocale.getVariant(); |
1034 } |
1033 } |
1035 |
1034 |
1036 /** |
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 /** |
1037 * Returns the extension (or private use) value associated with |
1060 * Returns the extension (or private use) value associated with |
1038 * the specified key, or null if there is no extension |
1061 * the specified key, or null if there is no extension |
1039 * associated with the key. To be well-formed, the key must be one |
1062 * 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 |
1063 * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so |
1041 * for example 'z' and 'Z' represent the same extension. |
1064 * for example 'z' and 'Z' represent the same extension. |
1050 */ |
1073 */ |
1051 public String getExtension(char key) { |
1074 public String getExtension(char key) { |
1052 if (!LocaleExtensions.isValidKey(key)) { |
1075 if (!LocaleExtensions.isValidKey(key)) { |
1053 throw new IllegalArgumentException("Ill-formed extension key: " + key); |
1076 throw new IllegalArgumentException("Ill-formed extension key: " + key); |
1054 } |
1077 } |
1055 return (localeExtensions == null) ? null : localeExtensions.getExtensionValue(key); |
1078 return hasExtensions() ? localeExtensions.getExtensionValue(key) : null; |
1056 } |
1079 } |
1057 |
1080 |
1058 /** |
1081 /** |
1059 * Returns the set of extension keys associated with this locale, or the |
1082 * 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. |
1083 * empty set if it has no extensions. The returned set is unmodifiable. |
1063 * @return The set of extension keys, or the empty set if this locale has |
1086 * @return The set of extension keys, or the empty set if this locale has |
1064 * no extensions. |
1087 * no extensions. |
1065 * @since 1.7 |
1088 * @since 1.7 |
1066 */ |
1089 */ |
1067 public Set<Character> getExtensionKeys() { |
1090 public Set<Character> getExtensionKeys() { |
1068 if (localeExtensions == null) { |
1091 if (!hasExtensions()) { |
1069 return Collections.emptySet(); |
1092 return Collections.emptySet(); |
1070 } |
1093 } |
1071 return localeExtensions.getKeys(); |
1094 return localeExtensions.getKeys(); |
1072 } |
1095 } |
1073 |
1096 |
1078 * |
1101 * |
1079 * @return The set of attributes. |
1102 * @return The set of attributes. |
1080 * @since 1.7 |
1103 * @since 1.7 |
1081 */ |
1104 */ |
1082 public Set<String> getUnicodeLocaleAttributes() { |
1105 public Set<String> getUnicodeLocaleAttributes() { |
1083 if (localeExtensions == null) { |
1106 if (!hasExtensions()) { |
1084 return Collections.emptySet(); |
1107 return Collections.emptySet(); |
1085 } |
1108 } |
1086 return localeExtensions.getUnicodeLocaleAttributes(); |
1109 return localeExtensions.getUnicodeLocaleAttributes(); |
1087 } |
1110 } |
1088 |
1111 |
1099 * @throws IllegalArgumentException if the key is not well-formed |
1122 * @throws IllegalArgumentException if the key is not well-formed |
1100 * @throws NullPointerException if <code>key</code> is null |
1123 * @throws NullPointerException if <code>key</code> is null |
1101 * @since 1.7 |
1124 * @since 1.7 |
1102 */ |
1125 */ |
1103 public String getUnicodeLocaleType(String key) { |
1126 public String getUnicodeLocaleType(String key) { |
1104 if (!UnicodeLocaleExtension.isKey(key)) { |
1127 if (!isUnicodeExtensionKey(key)) { |
1105 throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key); |
1128 throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key); |
1106 } |
1129 } |
1107 return (localeExtensions == null) ? null : localeExtensions.getUnicodeLocaleType(key); |
1130 return hasExtensions() ? localeExtensions.getUnicodeLocaleType(key) : null; |
1108 } |
1131 } |
1109 |
1132 |
1110 /** |
1133 /** |
1111 * Returns the set of Unicode locale keys defined by this locale, or the empty set if |
1134 * 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. |
1135 * this locale has none. The returned set is immutable. Keys are all lower case. |
1283 * @return a BCP47 language tag representing the locale |
1306 * @return a BCP47 language tag representing the locale |
1284 * @see #forLanguageTag(String) |
1307 * @see #forLanguageTag(String) |
1285 * @since 1.7 |
1308 * @since 1.7 |
1286 */ |
1309 */ |
1287 public String toLanguageTag() { |
1310 public String toLanguageTag() { |
|
1311 if (languageTag != null) { |
|
1312 return languageTag; |
|
1313 } |
|
1314 |
1288 LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions); |
1315 LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions); |
1289 StringBuilder buf = new StringBuilder(); |
1316 StringBuilder buf = new StringBuilder(); |
1290 |
1317 |
1291 String subtag = tag.getLanguage(); |
1318 String subtag = tag.getLanguage(); |
1292 if (subtag.length() > 0) { |
1319 if (subtag.length() > 0) { |
1512 + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry"); |
1545 + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry"); |
1513 } |
1546 } |
1514 return country3; |
1547 return country3; |
1515 } |
1548 } |
1516 |
1549 |
1517 private static final String getISO3Code(String iso2Code, String table) { |
1550 private static String getISO3Code(String iso2Code, String table) { |
1518 int codeLength = iso2Code.length(); |
1551 int codeLength = iso2Code.length(); |
1519 if (codeLength == 0) { |
1552 if (codeLength == 0) { |
1520 return ""; |
1553 return ""; |
1521 } |
1554 } |
1522 |
1555 |
1638 |
1671 |
1639 if (inLocale == null) { |
1672 if (inLocale == null) { |
1640 throw new NullPointerException(); |
1673 throw new NullPointerException(); |
1641 } |
1674 } |
1642 |
1675 |
1643 try { |
1676 LocaleServiceProviderPool pool = |
1644 OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale); |
1677 LocaleServiceProviderPool.getPool(LocaleNameProvider.class); |
1645 String key = (type == DISPLAY_VARIANT ? "%%"+code : code); |
1678 String key = (type == DISPLAY_VARIANT ? "%%"+code : code); |
1646 String result = null; |
1679 String result = pool.getLocalizedObject( |
1647 |
1680 LocaleNameGetter.INSTANCE, |
1648 // Check whether a provider can provide an implementation that's closer |
1681 inLocale, key, type, code); |
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) { |
1682 if (result != null) { |
1664 return result; |
1683 return result; |
1665 } |
1684 } |
1666 } |
1685 |
1667 catch (Exception e) { |
|
1668 // just fall through |
|
1669 } |
|
1670 return code; |
1686 return code; |
1671 } |
1687 } |
1672 |
1688 |
1673 /** |
1689 /** |
1674 * Returns a name for the locale's variant code that is appropriate for display to the |
1690 * Returns a name for the locale's variant code that is appropriate for display to the |
1688 */ |
1704 */ |
1689 public String getDisplayVariant(Locale inLocale) { |
1705 public String getDisplayVariant(Locale inLocale) { |
1690 if (baseLocale.getVariant().length() == 0) |
1706 if (baseLocale.getVariant().length() == 0) |
1691 return ""; |
1707 return ""; |
1692 |
1708 |
1693 OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale); |
1709 OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale); |
1694 |
1710 |
1695 String names[] = getDisplayVariantArray(bundle, inLocale); |
1711 String names[] = getDisplayVariantArray(bundle, inLocale); |
1696 |
1712 |
1697 // Get the localized patterns for formatting a list, and use |
1713 // Get the localized patterns for formatting a list, and use |
1698 // them to format the list. |
1714 // them to format the list. |
1746 * this function returns the empty string. |
1762 * this function returns the empty string. |
1747 * |
1763 * |
1748 * @throws NullPointerException if <code>inLocale</code> is <code>null</code> |
1764 * @throws NullPointerException if <code>inLocale</code> is <code>null</code> |
1749 */ |
1765 */ |
1750 public String getDisplayName(Locale inLocale) { |
1766 public String getDisplayName(Locale inLocale) { |
1751 OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale); |
1767 OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale); |
1752 |
1768 |
1753 String languageName = getDisplayLanguage(inLocale); |
1769 String languageName = getDisplayLanguage(inLocale); |
1754 String scriptName = getDisplayScript(inLocale); |
1770 String scriptName = getDisplayScript(inLocale); |
1755 String countryName = getDisplayCountry(inLocale); |
1771 String countryName = getDisplayCountry(inLocale); |
1756 String[] variantNames = getDisplayVariantArray(bundle, inLocale); |
1772 String[] variantNames = getDisplayVariantArray(bundle, inLocale); |
1792 } |
1808 } |
1793 if (countryName.length() != 0) { |
1809 if (countryName.length() != 0) { |
1794 names.add(countryName); |
1810 names.add(countryName); |
1795 } |
1811 } |
1796 if (variantNames.length != 0) { |
1812 if (variantNames.length != 0) { |
1797 for (String var : variantNames) { |
1813 names.addAll(Arrays.asList(variantNames)); |
1798 names.add(var); |
|
1799 } |
|
1800 } |
1814 } |
1801 |
1815 |
1802 // The first one in the main name |
1816 // The first one in the main name |
1803 mainName = names.get(0); |
1817 mainName = names.get(0); |
1804 |
1818 |
1908 |
1923 |
1909 private volatile static Locale defaultLocale = initDefault(); |
1924 private volatile static Locale defaultLocale = initDefault(); |
1910 private volatile static Locale defaultDisplayLocale = null; |
1925 private volatile static Locale defaultDisplayLocale = null; |
1911 private volatile static Locale defaultFormatLocale = null; |
1926 private volatile static Locale defaultFormatLocale = null; |
1912 |
1927 |
|
1928 private transient volatile String languageTag; |
|
1929 |
1913 /** |
1930 /** |
1914 * Return an array of the display names of the variant. |
1931 * Return an array of the display names of the variant. |
1915 * @param bundle the ResourceBundle to use to get the display names |
1932 * @param bundle the ResourceBundle to use to get the display names |
1916 * @return an array of display names, possible of zero length. |
1933 * @return an array of display names, possible of zero length. |
1917 */ |
1934 */ |
1943 */ |
1960 */ |
1944 private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) { |
1961 private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) { |
1945 // If we have no list patterns, compose the list in a simple, |
1962 // If we have no list patterns, compose the list in a simple, |
1946 // non-localized way. |
1963 // non-localized way. |
1947 if (listPattern == null || listCompositionPattern == null) { |
1964 if (listPattern == null || listCompositionPattern == null) { |
1948 StringBuffer result = new StringBuffer(); |
1965 StringBuilder result = new StringBuilder(); |
1949 for (int i=0; i<stringList.length; ++i) { |
1966 for (int i = 0; i < stringList.length; ++i) { |
1950 if (i>0) result.append(','); |
1967 if (i > 0) { |
|
1968 result.append(','); |
|
1969 } |
1951 result.append(stringList[i]); |
1970 result.append(stringList[i]); |
1952 } |
1971 } |
1953 return result.toString(); |
1972 return result.toString(); |
1954 } |
1973 } |
1955 |
1974 |
1990 System.arraycopy(list, 2, newList, 1, newList.length-1); |
2009 System.arraycopy(list, 2, newList, 1, newList.length-1); |
1991 newList[0] = newItem; |
2010 newList[0] = newItem; |
1992 |
2011 |
1993 // Recurse |
2012 // Recurse |
1994 return composeList(format, newList); |
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); |
1995 } |
2021 } |
1996 |
2022 |
1997 /** |
2023 /** |
1998 * @serialField language String |
2024 * @serialField language String |
1999 * language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>) |
2025 * language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>) |
2134 */ |
2160 */ |
2135 private static class LocaleNameGetter |
2161 private static class LocaleNameGetter |
2136 implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> { |
2162 implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> { |
2137 private static final LocaleNameGetter INSTANCE = new LocaleNameGetter(); |
2163 private static final LocaleNameGetter INSTANCE = new LocaleNameGetter(); |
2138 |
2164 |
|
2165 @Override |
2139 public String getObject(LocaleNameProvider localeNameProvider, |
2166 public String getObject(LocaleNameProvider localeNameProvider, |
2140 Locale locale, |
2167 Locale locale, |
2141 String key, |
2168 String key, |
2142 Object... params) { |
2169 Object... params) { |
2143 assert params.length == 2; |
2170 assert params.length == 2; |