31 * is copyrighted and owned by Taligent, Inc., a wholly-owned
32 * subsidiary of IBM. These materials are provided under terms
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.text.MessageFormat;
49 import java.util.concurrent.ConcurrentHashMap;
50 import java.util.spi.LocaleNameProvider;
51
52 import sun.security.action.GetPropertyAction;
53 import sun.util.locale.BaseLocale;
54 import sun.util.locale.InternalLocaleBuilder;
55 import sun.util.locale.LanguageTag;
56 import sun.util.locale.LocaleExtensions;
57 import sun.util.locale.LocaleMatcher;
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.locale.provider.LocaleResources;
64 import sun.util.locale.provider.LocaleServiceProviderPool;
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} class implements IETF BCP 47 which is composed of
76 * <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 "Matching of Language
77 * Tags"</a> and <a href="http://tools.ietf.org/html/rfc5646">RFC 5646 "Tags
78 * for Identifying Languages"</a> with support for the LDML (UTS#35, "Unicode
79 * Locale Data Markup Language") BCP 47-compatible extensions for locale data
80 * exchange.
81 *
82 * <p> A <code>Locale</code> object logically consists of the fields
83 * described below.
84 *
652 * Map to hold country codes for each ISO3166 part.
653 */
654 private static Map<IsoCountryCode, Set<String>> iso3166CodesMap = new ConcurrentHashMap<>();
655
656 /**
657 * This method is called from Locale class to retrieve country code set
658 * for getISOCountries(type)
659 */
660 static Set<String> retrieveISOCountryCodes(IsoCountryCode type) {
661 return iso3166CodesMap.computeIfAbsent(type, IsoCountryCode::createCountryCodeSet);
662 }
663 }
664
665 /**
666 * Display types for retrieving localized names from the name providers.
667 */
668 private static final int DISPLAY_LANGUAGE = 0;
669 private static final int DISPLAY_COUNTRY = 1;
670 private static final int DISPLAY_VARIANT = 2;
671 private static final int DISPLAY_SCRIPT = 3;
672
673 /**
674 * Private constructor used by getInstance method
675 */
676 private Locale(BaseLocale baseLocale, LocaleExtensions extensions) {
677 this.baseLocale = baseLocale;
678 this.localeExtensions = extensions;
679 }
680
681 /**
682 * Construct a locale from language, country and variant.
683 * This constructor normalizes the language value to lowercase and
684 * the country value to uppercase.
685 * <p>
686 * <b>Note:</b>
687 * <ul>
688 * <li>ISO 639 is not a stable standard; some of the language codes it defines
689 * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
690 * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
691 * API on Locale will return only the OLD codes.
925 language = props.getProperty("user.language", "en");
926 // for compatibility, check for old user.region property
927 region = props.getProperty("user.region");
928 if (region != null) {
929 // region can be of form country, country_variant, or _variant
930 int i = region.indexOf('_');
931 if (i >= 0) {
932 country = region.substring(0, i);
933 variant = region.substring(i + 1);
934 } else {
935 country = region;
936 variant = "";
937 }
938 script = "";
939 } else {
940 script = props.getProperty("user.script", "");
941 country = props.getProperty("user.country", "");
942 variant = props.getProperty("user.variant", "");
943 }
944
945 return getInstance(language, script, country, variant, null);
946 }
947
948 private static Locale initDefault(Locale.Category category) {
949 Properties props = GetPropertyAction.privilegedGetProperties();
950 return getInstance(
951 props.getProperty(category.languageKey,
952 defaultLocale.getLanguage()),
953 props.getProperty(category.scriptKey,
954 defaultLocale.getScript()),
955 props.getProperty(category.countryKey,
956 defaultLocale.getCountry()),
957 props.getProperty(category.variantKey,
958 defaultLocale.getVariant()),
959 null);
960 }
961
962 /**
963 * Sets the default locale for this instance of the Java Virtual Machine.
964 * This does not affect the host locale.
965 * <p>
966 * If there is a security manager, its <code>checkPermission</code>
967 * method is called with a <code>PropertyPermission("user.language", "write")</code>
968 * permission before the default locale is changed.
969 * <p>
970 * The Java Virtual Machine sets the default locale during startup
971 * based on the host environment. It is used by many locale-sensitive
972 * methods if no locale is explicitly specified.
973 * <p>
974 * Since changing the default locale may affect many different areas
975 * of functionality, this method should only be used if the caller
976 * is prepared to reinitialize locale-sensitive code running
977 * within the same Java Virtual Machine.
978 * <p>
979 * By setting the default locale with this method, all of the default
1754 }
1755
1756 /**
1757 * Returns a name for the locale's language that is appropriate for display to the
1758 * user.
1759 * If possible, the name returned will be localized according to inLocale.
1760 * For example, if the locale is fr_FR and inLocale
1761 * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
1762 * inLocale is fr_FR, getDisplayLanguage() will return "anglais".
1763 * If the name returned cannot be localized according to inLocale,
1764 * (say, we don't have a Japanese name for Croatian),
1765 * this function falls back on the English name, and finally
1766 * on the ISO code as a last-resort value. If the locale doesn't specify a language,
1767 * this function returns the empty string.
1768 *
1769 * @param inLocale The locale for which to retrieve the display language.
1770 * @return The name of the display language appropriate to the given locale.
1771 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1772 */
1773 public String getDisplayLanguage(Locale inLocale) {
1774 return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE);
1775 }
1776
1777 /**
1778 * Returns a name for the locale's script that is appropriate for display to
1779 * the user. If possible, the name will be localized for the default
1780 * {@link Locale.Category#DISPLAY DISPLAY} locale. Returns
1781 * the empty string if this locale doesn't specify a script code.
1782 *
1783 * @return the display name of the script code for the current default
1784 * {@link Locale.Category#DISPLAY DISPLAY} locale
1785 * @since 1.7
1786 */
1787 public String getDisplayScript() {
1788 return getDisplayScript(getDefault(Category.DISPLAY));
1789 }
1790
1791 /**
1792 * Returns a name for the locale's script that is appropriate
1793 * for display to the user. If possible, the name will be
1794 * localized for the given locale. Returns the empty string if
1795 * this locale doesn't specify a script code.
1796 *
1797 * @param inLocale The locale for which to retrieve the display script.
1798 * @return the display name of the script code for the current default
1799 * {@link Locale.Category#DISPLAY DISPLAY} locale
1800 * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1801 * @since 1.7
1802 */
1803 public String getDisplayScript(Locale inLocale) {
1804 return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT);
1805 }
1806
1807 /**
1808 * Returns a name for the locale's country that is appropriate for display to the
1809 * user.
1810 * If possible, the name returned will be localized for the default
1811 * {@link Locale.Category#DISPLAY DISPLAY} locale.
1812 * For example, if the locale is fr_FR and the default
1813 * {@link Locale.Category#DISPLAY DISPLAY} locale
1814 * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
1815 * the default {@link Locale.Category#DISPLAY DISPLAY} locale is fr_FR,
1816 * getDisplayCountry() will return "Etats-Unis".
1817 * If the name returned cannot be localized for the default
1818 * {@link Locale.Category#DISPLAY DISPLAY} locale,
1819 * (say, we don't have a Japanese name for Croatia),
1820 * this function falls back on the English name, and uses the ISO code as a last-resort
1821 * value. If the locale doesn't specify a country, this function returns the empty string.
1822 *
1823 * @return The name of the country appropriate to the locale.
1824 */
1827 }
1828
1829 /**
1830 * Returns a name for the locale's country that is appropriate for display to the
1831 * user.
1832 * If possible, the name returned will be localized according to inLocale.
1833 * For example, if the locale is fr_FR and inLocale
1834 * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
1835 * inLocale is fr_FR, getDisplayCountry() will return "Etats-Unis".
1836 * If the name returned cannot be localized according to inLocale.
1837 * (say, we don't have a Japanese name for Croatia),
1838 * this function falls back on the English name, and finally
1839 * on the ISO code as a last-resort value. If the locale doesn't specify a country,
1840 * this function returns the empty string.
1841 *
1842 * @param inLocale The locale for which to retrieve the display country.
1843 * @return The name of the country appropriate to the given locale.
1844 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1845 */
1846 public String getDisplayCountry(Locale inLocale) {
1847 return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY);
1848 }
1849
1850 private String getDisplayString(String code, Locale inLocale, int type) {
1851 if (code.length() == 0) {
1852 return "";
1853 }
1854
1855 if (inLocale == null) {
1856 throw new NullPointerException();
1857 }
1858
1859 LocaleServiceProviderPool pool =
1860 LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
1861 String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
1862 String result = pool.getLocalizedObject(
1863 LocaleNameGetter.INSTANCE,
1864 inLocale, key, type, code);
1865 if (result != null) {
1866 return result;
1867 }
1868
1869 return code;
1870 }
1871
1872 /**
1873 * Returns a name for the locale's variant code that is appropriate for display to the
1874 * user. If possible, the name will be localized for the default
1875 * {@link Locale.Category#DISPLAY DISPLAY} locale. If the locale
1876 * doesn't specify a variant code, this function returns the empty string.
1877 *
1878 * @return The name of the display variant code appropriate to the locale.
1879 */
1880 public final String getDisplayVariant() {
1881 return getDisplayVariant(getDefault(Category.DISPLAY));
1882 }
1883
1884 /**
1885 * Returns a name for the locale's variant code that is appropriate for display to the
1886 * user. If possible, the name will be localized for inLocale. If the locale
1887 * doesn't specify a variant code, this function returns the empty string.
1888 *
1889 * @param inLocale The locale for which to retrieve the display variant code.
1890 * @return The name of the display variant code appropriate to the given locale.
1891 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1892 */
1893 public String getDisplayVariant(Locale inLocale) {
1894 if (baseLocale.getVariant().length() == 0)
1895 return "";
1896
1897 LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale);
1898
1899 String names[] = getDisplayVariantArray(inLocale);
1900
1901 // Get the localized patterns for formatting a list, and use
1902 // them to format the list.
1903 return formatList(names,
1904 lr.getLocaleName("ListPattern"),
1905 lr.getLocaleName("ListCompositionPattern"));
1906 }
1907
1908 /**
1909 * Returns a name for the locale that is appropriate for display to the
1910 * user. This will be the values returned by getDisplayLanguage(),
1911 * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled
1912 * into a single string. The non-empty values are used in order,
1913 * with the second and subsequent names in parentheses. For example:
1914 * <blockquote>
1915 * language (script, country, variant)<br>
1916 * language (country)<br>
1917 * language (variant)<br>
1918 * script (country)<br>
1919 * country<br>
1920 * </blockquote>
1921 * depending on which fields are specified in the locale. If the
1922 * language, script, country, and variant fields are all empty,
1923 * this function returns the empty string.
1924 *
1925 * @return The name of the locale appropriate to display.
1926 */
1927 public final String getDisplayName() {
1928 return getDisplayName(getDefault(Category.DISPLAY));
1929 }
1930
1931 /**
1932 * Returns a name for the locale that is appropriate for display
1933 * to the user. This will be the values returned by
1934 * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(),
1935 * and getDisplayVariant() assembled into a single string.
1936 * The non-empty values are used in order,
1937 * with the second and subsequent names in parentheses. For example:
1938 * <blockquote>
1939 * language (script, country, variant)<br>
1940 * language (country)<br>
1941 * language (variant)<br>
1942 * script (country)<br>
1943 * country<br>
1944 * </blockquote>
1945 * depending on which fields are specified in the locale. If the
1946 * language, script, country, and variant fields are all empty,
1947 * this function returns the empty string.
1948 *
1949 * @param inLocale The locale for which to retrieve the display name.
1950 * @return The name of the locale appropriate to display.
1951 * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1952 */
1953 public String getDisplayName(Locale inLocale) {
1954 LocaleResources lr = LocaleProviderAdapter.forJRE().getLocaleResources(inLocale);
1955
1956 String languageName = getDisplayLanguage(inLocale);
1957 String scriptName = getDisplayScript(inLocale);
1958 String countryName = getDisplayCountry(inLocale);
1959 String[] variantNames = getDisplayVariantArray(inLocale);
1960
1961 // Get the localized patterns for formatting a display name.
1962 String displayNamePattern = lr.getLocaleName("DisplayNamePattern");
1963 String listPattern = lr.getLocaleName("ListPattern");
1964 String listCompositionPattern = lr.getLocaleName("ListCompositionPattern");
1965
1966 // The display name consists of a main name, followed by qualifiers.
1967 // Typically, the format is "MainName (Qualifier, Qualifier)" but this
1968 // depends on what pattern is stored in the display locale.
1969 String mainName = null;
1970 String[] qualifierNames = null;
1971
1972 // The main name is the language, or if there is no language, the script,
1973 // then if no script, the country. If there is no language/script/country
1974 // (an anomalous situation) then the display name is simply the variant's
1975 // display name.
1976 if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
1977 if (variantNames.length == 0) {
1978 return "";
1979 } else {
1980 return formatList(variantNames, listPattern, listCompositionPattern);
1981 }
1982 }
1983 ArrayList<String> names = new ArrayList<>(4);
1984 if (languageName.length() != 0) {
1985 names.add(languageName);
1986 }
1987 if (scriptName.length() != 0) {
1988 names.add(scriptName);
1989 }
1990 if (countryName.length() != 0) {
1991 names.add(countryName);
1992 }
1993 if (variantNames.length != 0) {
1994 names.addAll(Arrays.asList(variantNames));
1995 }
1996
1997 // The first one in the main name
1998 mainName = names.get(0);
1999
2000 // Others are qualifiers
2001 int numNames = names.size();
2002 qualifierNames = (numNames > 1) ?
2003 names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
2004
2005 // Create an array whose first element is the number of remaining
2006 // elements. This serves as a selector into a ChoiceFormat pattern from
2007 // the resource. The second and third elements are the main name and
2008 // the qualifier; if there are no qualifiers, the third element is
2009 // unused by the format pattern.
2010 Object[] displayNames = {
2011 qualifierNames.length != 0 ? 2 : 1,
2012 mainName,
2013 // We could also just call formatList() and have it handle the empty
2014 // list case, but this is more efficient, and we want it to be
2015 // efficient since all the language-only locales will not have any
2016 // qualifiers.
2017 qualifierNames.length != 0 ? formatList(qualifierNames, listPattern, listCompositionPattern) : null
2018 };
2019
2020 if (displayNamePattern != null) {
2021 return new MessageFormat(displayNamePattern).format(displayNames);
2022 }
2023 else {
2024 // If we cannot get the message format pattern, then we use a simple
2025 // hard-coded pattern. This should not occur in practice unless the
2026 // installation is missing some core files (FormatData etc.).
2027 StringBuilder result = new StringBuilder();
2028 result.append((String)displayNames[1]);
2029 if (displayNames.length > 2) {
2030 result.append(" (");
2031 result.append((String)displayNames[2]);
2032 result.append(')');
2033 }
2034 return result.toString();
2035 }
2036 }
2037
2104
2105 private static volatile Locale defaultLocale = initDefault();
2106 private static volatile Locale defaultDisplayLocale;
2107 private static volatile Locale defaultFormatLocale;
2108
2109 private transient volatile String languageTag;
2110
2111 /**
2112 * Return an array of the display names of the variant.
2113 * @param bundle the ResourceBundle to use to get the display names
2114 * @return an array of display names, possible of zero length.
2115 */
2116 private String[] getDisplayVariantArray(Locale inLocale) {
2117 // Split the variant name into tokens separated by '_'.
2118 StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
2119 String[] names = new String[tokenizer.countTokens()];
2120
2121 // For each variant token, lookup the display name. If
2122 // not found, use the variant name itself.
2123 for (int i=0; i<names.length; ++i) {
2124 names[i] = getDisplayString(tokenizer.nextToken(),
2125 inLocale, DISPLAY_VARIANT);
2126 }
2127
2128 return names;
2129 }
2130
2131 /**
2132 * Format a list using given pattern strings.
2133 * If either of the patterns is null, then a the list is
2134 * formatted by concatenation with the delimiter ','.
2135 * @param stringList the list of strings to be formatted.
2136 * @param listPattern should create a MessageFormat taking 0-3 arguments
2137 * and formatting them into a list.
2138 * @param listCompositionPattern should take 2 arguments
2139 * and is used by composeList.
2140 * @return a string representing the list.
2141 */
2142 private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
2143 // If we have no list patterns, compose the list in a simple,
2144 // non-localized way.
2145 if (listPattern == null || listCompositionPattern == null) {
2146 StringJoiner sj = new StringJoiner(",");
2147 for (int i = 0; i < stringList.length; ++i) {
2148 sj.add(stringList[i]);
2149 }
2150 return sj.toString();
2151 }
2152
2153 // Compose the list down to three elements if necessary
2154 if (stringList.length > 3) {
2155 MessageFormat format = new MessageFormat(listCompositionPattern);
2156 stringList = composeList(format, stringList);
2157 }
2158
2159 // Rebuild the argument list with the list length as the first element
2160 Object[] args = new Object[stringList.length + 1];
2161 System.arraycopy(stringList, 0, args, 1, stringList.length);
2162 args[0] = stringList.length;
2163
2164 // Format it using the pattern in the resource
2165 MessageFormat format = new MessageFormat(listPattern);
2166 return format.format(args);
2167 }
2168
2169 /**
2170 * Given a list of strings, return a list shortened to three elements.
2171 * Shorten it by applying the given format to the first two elements
2172 * recursively.
2173 * @param format a format which takes two arguments
2174 * @param list a list of strings
2175 * @return if the list is three elements or shorter, the same list;
2176 * otherwise, a new list of three elements.
2177 */
2178 private static String[] composeList(MessageFormat format, String[] list) {
2179 if (list.length <= 3) return list;
2180
2181 // Use the given format to compose the first two elements into one
2182 String[] listItems = { list[0], list[1] };
2183 String newItem = format.format(listItems);
2184
2185 // Form a new list one element shorter
2186 String[] newList = new String[list.length-1];
2187 System.arraycopy(list, 2, newList, 1, newList.length-1);
2188 newList[0] = newItem;
2189
2190 // Recurse
2191 return composeList(format, newList);
2192 }
2193
2194 // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to
2195 // avoid its class loading.
2196 private static boolean isUnicodeExtensionKey(String s) {
2197 // 2alphanum
2198 return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s);
2199 }
2200
2201 /**
2202 * @serialField language String
2203 * language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
2204 * @serialField country String
2205 * country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
2206 * @serialField variant String
2207 * variant subtags separated by LOWLINE characters. (See <a href="java/util/Locale.html#getVariant()">getVariant()</a>)
2208 * @serialField hashcode int
2209 * deprecated, for forward compatibility only
2210 * @serialField script String
2211 * script subtag in title case (See <a href="java/util/Locale.html#getScript()">getScript()</a>)
2328 && "TH".equals(variant)) {
2329 // th_TH_TH -> u-nu-thai (numbersystem = thai)
2330 extensions = LocaleExtensions.NUMBER_THAI;
2331 }
2332 return extensions;
2333 }
2334
2335 /**
2336 * Obtains a localized locale names from a LocaleNameProvider
2337 * implementation.
2338 */
2339 private static class LocaleNameGetter
2340 implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
2341 private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
2342
2343 @Override
2344 public String getObject(LocaleNameProvider localeNameProvider,
2345 Locale locale,
2346 String key,
2347 Object... params) {
2348 assert params.length == 2;
2349 int type = (Integer)params[0];
2350 String code = (String)params[1];
2351
2352 switch(type) {
2353 case DISPLAY_LANGUAGE:
2354 return localeNameProvider.getDisplayLanguage(code, locale);
2355 case DISPLAY_COUNTRY:
2356 return localeNameProvider.getDisplayCountry(code, locale);
2357 case DISPLAY_VARIANT:
2358 return localeNameProvider.getDisplayVariant(code, locale);
2359 case DISPLAY_SCRIPT:
2360 return localeNameProvider.getDisplayScript(code, locale);
2361 default:
2362 assert false; // shouldn't happen
2363 }
2364
2365 return null;
2366 }
2367 }
2368
2369 /**
2370 * Enum for locale categories. These locale categories are used to get/set
2371 * the default locale for the specific functionality represented by the
2372 * category.
2373 *
2374 * @see #getDefault(Locale.Category)
2375 * @see #setDefault(Locale.Category, Locale)
2376 * @since 1.7
2377 */
2378 public enum Category {
2379
2380 /**
2381 * Category used to represent the default locale for
2382 * displaying user interfaces.
2383 */
2384 DISPLAY("user.language.display",
2385 "user.script.display",
2386 "user.country.display",
2387 "user.variant.display"),
2388
2389 /**
2390 * Category used to represent the default locale for
2391 * formatting dates, numbers, and/or currencies.
2392 */
2393 FORMAT("user.language.format",
2394 "user.script.format",
2395 "user.country.format",
2396 "user.variant.format");
2397
2398 Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
2399 this.languageKey = languageKey;
2400 this.scriptKey = scriptKey;
2401 this.countryKey = countryKey;
2402 this.variantKey = variantKey;
2403 }
2404
2405 final String languageKey;
2406 final String scriptKey;
2407 final String countryKey;
2408 final String variantKey;
2409 }
2410
2411 /**
2412 * <code>Builder</code> is used to build instances of <code>Locale</code>
2413 * from values configured by the setters. Unlike the <code>Locale</code>
2414 * constructors, the <code>Builder</code> checks if a value configured by a
2415 * setter satisfies the syntax requirements defined by the <code>Locale</code>
2416 * class. A <code>Locale</code> object created by a <code>Builder</code> is
2417 * well-formed and can be transformed to a well-formed IETF BCP 47 language tag
2418 * without losing information.
2419 *
2420 * <p><b>Note:</b> The <code>Locale</code> class does not provide any
2421 * syntactic restrictions on variant, while BCP 47 requires each variant
2422 * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3
2423 * alphanumerics. The method <code>setVariant</code> throws
2424 * <code>IllformedLocaleException</code> for a variant that does not satisfy
2425 * this restriction. If it is necessary to support such a variant, use a
2426 * Locale constructor. However, keep in mind that a <code>Locale</code>
2427 * object created this way might lose the variant information when
2428 * transformed to a BCP 47 language tag.
|
31 * is copyrighted and owned by Taligent, Inc., a wholly-owned
32 * subsidiary of IBM. These materials are provided under terms
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.text.MessageFormat;
49 import java.util.concurrent.ConcurrentHashMap;
50 import java.util.spi.LocaleNameProvider;
51 import java.util.stream.Collectors;
52
53 import sun.security.action.GetPropertyAction;
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.LocaleMatcher;
59 import sun.util.locale.LocaleObjectCache;
60 import sun.util.locale.LocaleSyntaxException;
61 import sun.util.locale.LocaleUtils;
62 import sun.util.locale.ParseStatus;
63 import sun.util.locale.provider.LocaleProviderAdapter;
64 import sun.util.locale.provider.LocaleResources;
65 import sun.util.locale.provider.LocaleServiceProviderPool;
66 import sun.util.locale.provider.TimeZoneNameUtility;
67
68 /**
69 * A <code>Locale</code> object represents a specific geographical, political,
70 * or cultural region. An operation that requires a <code>Locale</code> to perform
71 * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
72 * to tailor information for the user. For example, displaying a number
73 * is a locale-sensitive operation— the number should be formatted
74 * according to the customs and conventions of the user's native country,
75 * region, or culture.
76 *
77 * <p> The {@code Locale} class implements IETF BCP 47 which is composed of
78 * <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 "Matching of Language
79 * Tags"</a> and <a href="http://tools.ietf.org/html/rfc5646">RFC 5646 "Tags
80 * for Identifying Languages"</a> with support for the LDML (UTS#35, "Unicode
81 * Locale Data Markup Language") BCP 47-compatible extensions for locale data
82 * exchange.
83 *
84 * <p> A <code>Locale</code> object logically consists of the fields
85 * described below.
86 *
654 * Map to hold country codes for each ISO3166 part.
655 */
656 private static Map<IsoCountryCode, Set<String>> iso3166CodesMap = new ConcurrentHashMap<>();
657
658 /**
659 * This method is called from Locale class to retrieve country code set
660 * for getISOCountries(type)
661 */
662 static Set<String> retrieveISOCountryCodes(IsoCountryCode type) {
663 return iso3166CodesMap.computeIfAbsent(type, IsoCountryCode::createCountryCodeSet);
664 }
665 }
666
667 /**
668 * Display types for retrieving localized names from the name providers.
669 */
670 private static final int DISPLAY_LANGUAGE = 0;
671 private static final int DISPLAY_COUNTRY = 1;
672 private static final int DISPLAY_VARIANT = 2;
673 private static final int DISPLAY_SCRIPT = 3;
674 private static final int DISPLAY_UEXT_KEY = 4;
675 private static final int DISPLAY_UEXT_TYPE = 5;
676
677 /**
678 * Private constructor used by getInstance method
679 */
680 private Locale(BaseLocale baseLocale, LocaleExtensions extensions) {
681 this.baseLocale = baseLocale;
682 this.localeExtensions = extensions;
683 }
684
685 /**
686 * Construct a locale from language, country and variant.
687 * This constructor normalizes the language value to lowercase and
688 * the country value to uppercase.
689 * <p>
690 * <b>Note:</b>
691 * <ul>
692 * <li>ISO 639 is not a stable standard; some of the language codes it defines
693 * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
694 * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
695 * API on Locale will return only the OLD codes.
929 language = props.getProperty("user.language", "en");
930 // for compatibility, check for old user.region property
931 region = props.getProperty("user.region");
932 if (region != null) {
933 // region can be of form country, country_variant, or _variant
934 int i = region.indexOf('_');
935 if (i >= 0) {
936 country = region.substring(0, i);
937 variant = region.substring(i + 1);
938 } else {
939 country = region;
940 variant = "";
941 }
942 script = "";
943 } else {
944 script = props.getProperty("user.script", "");
945 country = props.getProperty("user.country", "");
946 variant = props.getProperty("user.variant", "");
947 }
948
949 return getInstance(language, script, country, variant,
950 getDefaultExtensions(props.getProperty("user.extensions", ""))
951 .orElse(null));
952 }
953
954 private static Locale initDefault(Locale.Category category) {
955 Properties props = GetPropertyAction.privilegedGetProperties();
956
957 return getInstance(
958 props.getProperty(category.languageKey,
959 defaultLocale.getLanguage()),
960 props.getProperty(category.scriptKey,
961 defaultLocale.getScript()),
962 props.getProperty(category.countryKey,
963 defaultLocale.getCountry()),
964 props.getProperty(category.variantKey,
965 defaultLocale.getVariant()),
966 getDefaultExtensions(props.getProperty(category.extensionsKey, ""))
967 .orElse(defaultLocale.getLocaleExtensions()));
968 }
969
970 private static Optional<LocaleExtensions> getDefaultExtensions(String extensionsProp) {
971 LocaleExtensions exts = null;
972
973 try {
974 exts = new InternalLocaleBuilder()
975 .setExtensions(extensionsProp)
976 .getLocaleExtensions();
977 } catch (LocaleSyntaxException e) {
978 // just ignore this incorrect property
979 }
980
981 return Optional.ofNullable(exts);
982 }
983
984 /**
985 * Sets the default locale for this instance of the Java Virtual Machine.
986 * This does not affect the host locale.
987 * <p>
988 * If there is a security manager, its <code>checkPermission</code>
989 * method is called with a <code>PropertyPermission("user.language", "write")</code>
990 * permission before the default locale is changed.
991 * <p>
992 * The Java Virtual Machine sets the default locale during startup
993 * based on the host environment. It is used by many locale-sensitive
994 * methods if no locale is explicitly specified.
995 * <p>
996 * Since changing the default locale may affect many different areas
997 * of functionality, this method should only be used if the caller
998 * is prepared to reinitialize locale-sensitive code running
999 * within the same Java Virtual Machine.
1000 * <p>
1001 * By setting the default locale with this method, all of the default
1776 }
1777
1778 /**
1779 * Returns a name for the locale's language that is appropriate for display to the
1780 * user.
1781 * If possible, the name returned will be localized according to inLocale.
1782 * For example, if the locale is fr_FR and inLocale
1783 * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
1784 * inLocale is fr_FR, getDisplayLanguage() will return "anglais".
1785 * If the name returned cannot be localized according to inLocale,
1786 * (say, we don't have a Japanese name for Croatian),
1787 * this function falls back on the English name, and finally
1788 * on the ISO code as a last-resort value. If the locale doesn't specify a language,
1789 * this function returns the empty string.
1790 *
1791 * @param inLocale The locale for which to retrieve the display language.
1792 * @return The name of the display language appropriate to the given locale.
1793 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1794 */
1795 public String getDisplayLanguage(Locale inLocale) {
1796 return getDisplayString(baseLocale.getLanguage(), null, inLocale, DISPLAY_LANGUAGE);
1797 }
1798
1799 /**
1800 * Returns a name for the locale's script that is appropriate for display to
1801 * the user. If possible, the name will be localized for the default
1802 * {@link Locale.Category#DISPLAY DISPLAY} locale. Returns
1803 * the empty string if this locale doesn't specify a script code.
1804 *
1805 * @return the display name of the script code for the current default
1806 * {@link Locale.Category#DISPLAY DISPLAY} locale
1807 * @since 1.7
1808 */
1809 public String getDisplayScript() {
1810 return getDisplayScript(getDefault(Category.DISPLAY));
1811 }
1812
1813 /**
1814 * Returns a name for the locale's script that is appropriate
1815 * for display to the user. If possible, the name will be
1816 * localized for the given locale. Returns the empty string if
1817 * this locale doesn't specify a script code.
1818 *
1819 * @param inLocale The locale for which to retrieve the display script.
1820 * @return the display name of the script code for the current default
1821 * {@link Locale.Category#DISPLAY DISPLAY} locale
1822 * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1823 * @since 1.7
1824 */
1825 public String getDisplayScript(Locale inLocale) {
1826 return getDisplayString(baseLocale.getScript(), null, inLocale, DISPLAY_SCRIPT);
1827 }
1828
1829 /**
1830 * Returns a name for the locale's country that is appropriate for display to the
1831 * user.
1832 * If possible, the name returned will be localized for the default
1833 * {@link Locale.Category#DISPLAY DISPLAY} locale.
1834 * For example, if the locale is fr_FR and the default
1835 * {@link Locale.Category#DISPLAY DISPLAY} locale
1836 * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
1837 * the default {@link Locale.Category#DISPLAY DISPLAY} locale is fr_FR,
1838 * getDisplayCountry() will return "Etats-Unis".
1839 * If the name returned cannot be localized for the default
1840 * {@link Locale.Category#DISPLAY DISPLAY} locale,
1841 * (say, we don't have a Japanese name for Croatia),
1842 * this function falls back on the English name, and uses the ISO code as a last-resort
1843 * value. If the locale doesn't specify a country, this function returns the empty string.
1844 *
1845 * @return The name of the country appropriate to the locale.
1846 */
1849 }
1850
1851 /**
1852 * Returns a name for the locale's country that is appropriate for display to the
1853 * user.
1854 * If possible, the name returned will be localized according to inLocale.
1855 * For example, if the locale is fr_FR and inLocale
1856 * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
1857 * inLocale is fr_FR, getDisplayCountry() will return "Etats-Unis".
1858 * If the name returned cannot be localized according to inLocale.
1859 * (say, we don't have a Japanese name for Croatia),
1860 * this function falls back on the English name, and finally
1861 * on the ISO code as a last-resort value. If the locale doesn't specify a country,
1862 * this function returns the empty string.
1863 *
1864 * @param inLocale The locale for which to retrieve the display country.
1865 * @return The name of the country appropriate to the given locale.
1866 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1867 */
1868 public String getDisplayCountry(Locale inLocale) {
1869 return getDisplayString(baseLocale.getRegion(), null, inLocale, DISPLAY_COUNTRY);
1870 }
1871
1872 private String getDisplayString(String code, String cat, Locale inLocale, int type) {
1873 Objects.requireNonNull(inLocale);
1874 Objects.requireNonNull(code);
1875
1876 if (code.isEmpty()) {
1877 return "";
1878 }
1879
1880 LocaleServiceProviderPool pool =
1881 LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
1882 String rbKey = (type == DISPLAY_VARIANT ? "%%"+code : code);
1883 String result = pool.getLocalizedObject(
1884 LocaleNameGetter.INSTANCE,
1885 inLocale, rbKey, type, code, cat);
1886 return result != null ? result : code;
1887 }
1888
1889 /**
1890 * Returns a name for the locale's variant code that is appropriate for display to the
1891 * user. If possible, the name will be localized for the default
1892 * {@link Locale.Category#DISPLAY DISPLAY} locale. If the locale
1893 * doesn't specify a variant code, this function returns the empty string.
1894 *
1895 * @return The name of the display variant code appropriate to the locale.
1896 */
1897 public final String getDisplayVariant() {
1898 return getDisplayVariant(getDefault(Category.DISPLAY));
1899 }
1900
1901 /**
1902 * Returns a name for the locale's variant code that is appropriate for display to the
1903 * user. If possible, the name will be localized for inLocale. If the locale
1904 * doesn't specify a variant code, this function returns the empty string.
1905 *
1906 * @param inLocale The locale for which to retrieve the display variant code.
1907 * @return The name of the display variant code appropriate to the given locale.
1908 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1909 */
1910 public String getDisplayVariant(Locale inLocale) {
1911 if (baseLocale.getVariant().length() == 0)
1912 return "";
1913
1914 LocaleResources lr = LocaleProviderAdapter
1915 .getResourceBundleBased()
1916 .getLocaleResources(inLocale);
1917
1918 String names[] = getDisplayVariantArray(inLocale);
1919
1920 // Get the localized patterns for formatting a list, and use
1921 // them to format the list.
1922 return formatList(names,
1923 lr.getLocaleName("ListCompositionPattern"));
1924 }
1925
1926 /**
1927 * Returns a name for the locale that is appropriate for display to the
1928 * user. This will be the values returned by getDisplayLanguage(),
1929 * getDisplayScript(), getDisplayCountry(), getDisplayVariant() and
1930 * optional <a href="./Locale.html#def_locale_extension">Unicode extensions</a>
1931 * assembled into a single string. The non-empty values are used in order, with
1932 * the second and subsequent names in parentheses. For example:
1933 * <blockquote>
1934 * language (script, country, variant(, extension)*)<br>
1935 * language (country(, extension)*)<br>
1936 * language (variant(, extension)*)<br>
1937 * script (country(, extension)*)<br>
1938 * country (extension)*<br>
1939 * </blockquote>
1940 * depending on which fields are specified in the locale. If the
1941 * language, script, country, and variant fields are all empty,
1942 * this function returns the empty string.
1943 *
1944 * @return The name of the locale appropriate to display.
1945 */
1946 public final String getDisplayName() {
1947 return getDisplayName(getDefault(Category.DISPLAY));
1948 }
1949
1950 /**
1951 * Returns a name for the locale that is appropriate for display
1952 * to the user. This will be the values returned by
1953 * getDisplayLanguage(), getDisplayScript(),getDisplayCountry()
1954 * getDisplayVariant(), and optional <a href="./Locale.html#def_locale_extension">
1955 * Unicode extensions</a> assembled into a single string. The non-empty
1956 * values are used in order, with the second and subsequent names in
1957 * parentheses. For example:
1958 * <blockquote>
1959 * language (script, country, variant(, extension)*)<br>
1960 * language (country(, extension)*)<br>
1961 * language (variant(, extension)*)<br>
1962 * script (country(, extension)*)<br>
1963 * country (extension)*<br>
1964 * </blockquote>
1965 * depending on which fields are specified in the locale. If the
1966 * language, script, country, and variant fields are all empty,
1967 * this function returns the empty string.
1968 *
1969 * @param inLocale The locale for which to retrieve the display name.
1970 * @return The name of the locale appropriate to display.
1971 * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1972 */
1973 public String getDisplayName(Locale inLocale) {
1974 LocaleResources lr = LocaleProviderAdapter
1975 .getResourceBundleBased()
1976 .getLocaleResources(inLocale);
1977
1978 String languageName = getDisplayLanguage(inLocale);
1979 String scriptName = getDisplayScript(inLocale);
1980 String countryName = getDisplayCountry(inLocale);
1981 String[] variantNames = getDisplayVariantArray(inLocale);
1982
1983 // Get the localized patterns for formatting a display name.
1984 String displayNamePattern = lr.getLocaleName("DisplayNamePattern");
1985 String listCompositionPattern = lr.getLocaleName("ListCompositionPattern");
1986
1987 // The display name consists of a main name, followed by qualifiers.
1988 // Typically, the format is "MainName (Qualifier, Qualifier)" but this
1989 // depends on what pattern is stored in the display locale.
1990 String mainName = null;
1991 String[] qualifierNames = null;
1992
1993 // The main name is the language, or if there is no language, the script,
1994 // then if no script, the country. If there is no language/script/country
1995 // (an anomalous situation) then the display name is simply the variant's
1996 // display name.
1997 if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
1998 if (variantNames.length == 0) {
1999 return "";
2000 } else {
2001 return formatList(variantNames, listCompositionPattern);
2002 }
2003 }
2004 ArrayList<String> names = new ArrayList<>(4);
2005 if (languageName.length() != 0) {
2006 names.add(languageName);
2007 }
2008 if (scriptName.length() != 0) {
2009 names.add(scriptName);
2010 }
2011 if (countryName.length() != 0) {
2012 names.add(countryName);
2013 }
2014 if (variantNames.length != 0) {
2015 names.addAll(Arrays.asList(variantNames));
2016 }
2017
2018 // add Unicode extensions
2019 if (localeExtensions != null) {
2020 localeExtensions.getUnicodeLocaleAttributes().stream()
2021 .map(key -> getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY))
2022 .forEach(names::add);
2023 localeExtensions.getUnicodeLocaleKeys().stream()
2024 .map(key -> getDisplayKeyTypeExtensionString(key, lr, inLocale))
2025 .forEach(names::add);
2026 }
2027
2028 // The first one in the main name
2029 mainName = names.get(0);
2030
2031 // Others are qualifiers
2032 int numNames = names.size();
2033 qualifierNames = (numNames > 1) ?
2034 names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
2035
2036 // Create an array whose first element is the number of remaining
2037 // elements. This serves as a selector into a ChoiceFormat pattern from
2038 // the resource. The second and third elements are the main name and
2039 // the qualifier; if there are no qualifiers, the third element is
2040 // unused by the format pattern.
2041 Object[] displayNames = {
2042 qualifierNames.length != 0 ? 2 : 1,
2043 mainName,
2044 // We could also just call formatList() and have it handle the empty
2045 // list case, but this is more efficient, and we want it to be
2046 // efficient since all the language-only locales will not have any
2047 // qualifiers.
2048 qualifierNames.length != 0 ? formatList(qualifierNames, listCompositionPattern) : null
2049 };
2050
2051 if (displayNamePattern != null) {
2052 return new MessageFormat(displayNamePattern).format(displayNames);
2053 }
2054 else {
2055 // If we cannot get the message format pattern, then we use a simple
2056 // hard-coded pattern. This should not occur in practice unless the
2057 // installation is missing some core files (FormatData etc.).
2058 StringBuilder result = new StringBuilder();
2059 result.append((String)displayNames[1]);
2060 if (displayNames.length > 2) {
2061 result.append(" (");
2062 result.append((String)displayNames[2]);
2063 result.append(')');
2064 }
2065 return result.toString();
2066 }
2067 }
2068
2135
2136 private static volatile Locale defaultLocale = initDefault();
2137 private static volatile Locale defaultDisplayLocale;
2138 private static volatile Locale defaultFormatLocale;
2139
2140 private transient volatile String languageTag;
2141
2142 /**
2143 * Return an array of the display names of the variant.
2144 * @param bundle the ResourceBundle to use to get the display names
2145 * @return an array of display names, possible of zero length.
2146 */
2147 private String[] getDisplayVariantArray(Locale inLocale) {
2148 // Split the variant name into tokens separated by '_'.
2149 StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
2150 String[] names = new String[tokenizer.countTokens()];
2151
2152 // For each variant token, lookup the display name. If
2153 // not found, use the variant name itself.
2154 for (int i=0; i<names.length; ++i) {
2155 names[i] = getDisplayString(tokenizer.nextToken(), null,
2156 inLocale, DISPLAY_VARIANT);
2157 }
2158
2159 return names;
2160 }
2161
2162 private String getDisplayKeyTypeExtensionString(String key, LocaleResources lr, Locale inLocale) {
2163 String type = localeExtensions.getUnicodeLocaleType(key);
2164 String ret = getDisplayString(type, key, inLocale, DISPLAY_UEXT_TYPE);
2165
2166 if (ret == null || ret.equals(type)) {
2167 // no localization for this type. try combining key/type separately
2168 String displayType = type;
2169 switch (key) {
2170 case "cu":
2171 displayType = lr.getCurrencyName(type.toLowerCase(Locale.ROOT));
2172 break;
2173 case "rg":
2174 if (type != null &&
2175 // UN M.49 code should not be allowed here
2176 type.matches("^[a-zA-Z]{2}[zZ]{4}$")) {
2177 displayType = lr.getLocaleName(type.substring(0, 2).toUpperCase(Locale.ROOT));
2178 }
2179 break;
2180 case "tz":
2181 displayType = TimeZoneNameUtility.retrieveGenericDisplayName(
2182 TimeZoneNameUtility.convertLDMLShortID(type).orElse(type),
2183 TimeZone.LONG, inLocale);
2184 break;
2185 }
2186 ret = MessageFormat.format(lr.getLocaleName("ListKeyTypePattern"),
2187 getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY),
2188 Optional.ofNullable(displayType).orElse(type));
2189 }
2190
2191 return ret;
2192 }
2193
2194 /**
2195 * Format a list using given pattern strings.
2196 * If either of the patterns is null, then a the list is
2197 * formatted by concatenation with the delimiter ','.
2198 * @param stringList the list of strings to be formatted.
2199 * and formatting them into a list.
2200 * @param pattern should take 2 arguments for reduction
2201 * @return a string representing the list.
2202 */
2203 private static String formatList(String[] stringList, String pattern) {
2204 // If we have no list patterns, compose the list in a simple,
2205 // non-localized way.
2206 if (pattern == null) {
2207 return Arrays.stream(stringList).collect(Collectors.joining(","));
2208 }
2209
2210 switch (stringList.length) {
2211 case 0:
2212 return "";
2213 case 1:
2214 return stringList[0];
2215 default:
2216 return Arrays.stream(stringList).reduce("",
2217 (s1, s2) -> {
2218 if (s1.equals("")) {
2219 return s2;
2220 }
2221 if (s2.equals("")) {
2222 return s1;
2223 }
2224 return MessageFormat.format(pattern, s1, s2);
2225 });
2226 }
2227 }
2228
2229 // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to
2230 // avoid its class loading.
2231 private static boolean isUnicodeExtensionKey(String s) {
2232 // 2alphanum
2233 return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s);
2234 }
2235
2236 /**
2237 * @serialField language String
2238 * language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
2239 * @serialField country String
2240 * country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
2241 * @serialField variant String
2242 * variant subtags separated by LOWLINE characters. (See <a href="java/util/Locale.html#getVariant()">getVariant()</a>)
2243 * @serialField hashcode int
2244 * deprecated, for forward compatibility only
2245 * @serialField script String
2246 * script subtag in title case (See <a href="java/util/Locale.html#getScript()">getScript()</a>)
2363 && "TH".equals(variant)) {
2364 // th_TH_TH -> u-nu-thai (numbersystem = thai)
2365 extensions = LocaleExtensions.NUMBER_THAI;
2366 }
2367 return extensions;
2368 }
2369
2370 /**
2371 * Obtains a localized locale names from a LocaleNameProvider
2372 * implementation.
2373 */
2374 private static class LocaleNameGetter
2375 implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
2376 private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
2377
2378 @Override
2379 public String getObject(LocaleNameProvider localeNameProvider,
2380 Locale locale,
2381 String key,
2382 Object... params) {
2383 assert params.length == 3;
2384 int type = (Integer)params[0];
2385 String code = (String)params[1];
2386 String cat = (String)params[2];
2387
2388 switch(type) {
2389 case DISPLAY_LANGUAGE:
2390 return localeNameProvider.getDisplayLanguage(code, locale);
2391 case DISPLAY_COUNTRY:
2392 return localeNameProvider.getDisplayCountry(code, locale);
2393 case DISPLAY_VARIANT:
2394 return localeNameProvider.getDisplayVariant(code, locale);
2395 case DISPLAY_SCRIPT:
2396 return localeNameProvider.getDisplayScript(code, locale);
2397 case DISPLAY_UEXT_KEY:
2398 return localeNameProvider.getDisplayUnicodeExtensionKey(code, locale);
2399 case DISPLAY_UEXT_TYPE:
2400 return localeNameProvider.getDisplayUnicodeExtensionType(code, cat, locale);
2401 default:
2402 assert false; // shouldn't happen
2403 }
2404
2405 return null;
2406 }
2407 }
2408
2409 /**
2410 * Enum for locale categories. These locale categories are used to get/set
2411 * the default locale for the specific functionality represented by the
2412 * category.
2413 *
2414 * @see #getDefault(Locale.Category)
2415 * @see #setDefault(Locale.Category, Locale)
2416 * @since 1.7
2417 */
2418 public enum Category {
2419
2420 /**
2421 * Category used to represent the default locale for
2422 * displaying user interfaces.
2423 */
2424 DISPLAY("user.language.display",
2425 "user.script.display",
2426 "user.country.display",
2427 "user.variant.display",
2428 "user.extensions.display"),
2429
2430 /**
2431 * Category used to represent the default locale for
2432 * formatting dates, numbers, and/or currencies.
2433 */
2434 FORMAT("user.language.format",
2435 "user.script.format",
2436 "user.country.format",
2437 "user.variant.format",
2438 "user.extensions.format");
2439
2440 Category(String languageKey, String scriptKey, String countryKey,
2441 String variantKey, String extensionsKey) {
2442 this.languageKey = languageKey;
2443 this.scriptKey = scriptKey;
2444 this.countryKey = countryKey;
2445 this.variantKey = variantKey;
2446 this.extensionsKey = extensionsKey;
2447 }
2448
2449 final String languageKey;
2450 final String scriptKey;
2451 final String countryKey;
2452 final String variantKey;
2453 final String extensionsKey;
2454 }
2455
2456 /**
2457 * <code>Builder</code> is used to build instances of <code>Locale</code>
2458 * from values configured by the setters. Unlike the <code>Locale</code>
2459 * constructors, the <code>Builder</code> checks if a value configured by a
2460 * setter satisfies the syntax requirements defined by the <code>Locale</code>
2461 * class. A <code>Locale</code> object created by a <code>Builder</code> is
2462 * well-formed and can be transformed to a well-formed IETF BCP 47 language tag
2463 * without losing information.
2464 *
2465 * <p><b>Note:</b> The <code>Locale</code> class does not provide any
2466 * syntactic restrictions on variant, while BCP 47 requires each variant
2467 * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3
2468 * alphanumerics. The method <code>setVariant</code> throws
2469 * <code>IllformedLocaleException</code> for a variant that does not satisfy
2470 * this restriction. If it is necessary to support such a variant, use a
2471 * Locale constructor. However, keep in mind that a <code>Locale</code>
2472 * object created this way might lose the variant information when
2473 * transformed to a BCP 47 language tag.
|