1379 * previous uses of <code>toString</code> that expected language, country, and variant
1380 * fields only. To represent a Locale as a String for interchange purposes, use
1381 * {@link #toLanguageTag}.
1382 *
1383 * <p>Examples: <ul>
1384 * <li>{@code en}</li>
1385 * <li>{@code de_DE}</li>
1386 * <li>{@code _GB}</li>
1387 * <li>{@code en_US_WIN}</li>
1388 * <li>{@code de__POSIX}</li>
1389 * <li>{@code zh_CN_#Hans}</li>
1390 * <li>{@code zh_TW_#Hant_x-java}</li>
1391 * <li>{@code th_TH_TH_#u-nu-thai}</li></ul>
1392 *
1393 * @return A string representation of the Locale, for debugging.
1394 * @see #getDisplayName
1395 * @see #toLanguageTag
1396 */
1397 @Override
1398 public final String toString() {
1399 boolean l = (baseLocale.getLanguage().length() != 0);
1400 boolean s = (baseLocale.getScript().length() != 0);
1401 boolean r = (baseLocale.getRegion().length() != 0);
1402 boolean v = (baseLocale.getVariant().length() != 0);
1403 boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0);
1404
1405 StringBuilder result = new StringBuilder(baseLocale.getLanguage());
1406 if (r || (l && (v || s || e))) {
1407 result.append('_')
1408 .append(baseLocale.getRegion()); // This may just append '_'
1409 }
1410 if (v && (l || r)) {
1411 result.append('_')
1412 .append(baseLocale.getVariant());
1413 }
1414
1415 if (s && (l || r)) {
1416 result.append("_#")
1417 .append(baseLocale.getScript());
1418 }
1419
1420 if (e && (l || r)) {
1421 result.append('_');
1422 if (!s) {
1423 result.append('#');
1487 * <pre>
1488 * new Locale("xx", "YY").toLanguageTag();</pre>
1489 *
1490 * will return "xx-YY", but the language subtag "xx" and the
1491 * region subtag "YY" are invalid because they are not registered
1492 * in the IANA Language Subtag Registry.
1493 *
1494 * @return a BCP47 language tag representing the locale
1495 * @see #forLanguageTag(String)
1496 * @since 1.7
1497 */
1498 public String toLanguageTag() {
1499 if (languageTag != null) {
1500 return languageTag;
1501 }
1502
1503 LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
1504 StringBuilder buf = new StringBuilder();
1505
1506 String subtag = tag.getLanguage();
1507 if (subtag.length() > 0) {
1508 buf.append(LanguageTag.canonicalizeLanguage(subtag));
1509 }
1510
1511 subtag = tag.getScript();
1512 if (subtag.length() > 0) {
1513 buf.append(LanguageTag.SEP);
1514 buf.append(LanguageTag.canonicalizeScript(subtag));
1515 }
1516
1517 subtag = tag.getRegion();
1518 if (subtag.length() > 0) {
1519 buf.append(LanguageTag.SEP);
1520 buf.append(LanguageTag.canonicalizeRegion(subtag));
1521 }
1522
1523 List<String>subtags = tag.getVariants();
1524 for (String s : subtags) {
1525 buf.append(LanguageTag.SEP);
1526 // preserve casing
1527 buf.append(s);
1528 }
1529
1530 subtags = tag.getExtensions();
1531 for (String s : subtags) {
1532 buf.append(LanguageTag.SEP);
1533 buf.append(LanguageTag.canonicalizeExtension(s));
1534 }
1535
1536 subtag = tag.getPrivateuse();
1537 if (subtag.length() > 0) {
1538 if (buf.length() > 0) {
1539 buf.append(LanguageTag.SEP);
1540 }
1541 buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
1542 // preserve casing
1543 buf.append(subtag);
1544 }
1545
1546 String langTag = buf.toString();
1547 synchronized (this) {
1548 if (languageTag == null) {
1549 languageTag = langTag;
1550 }
1551 }
1552 return languageTag;
1553 }
1554
1555 /**
1556 * Returns a locale for the specified IETF BCP 47 language tag string.
1557 *
1667 *
1668 * <p>For a list of all grandfathered tags, see the
1669 * IANA Language Subtag Registry (search for "Type: grandfathered").
1670 *
1671 * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>
1672 * and <code>forLanguageTag</code> will round-trip.
1673 *
1674 * @param languageTag the language tag
1675 * @return The locale that best represents the language tag.
1676 * @throws NullPointerException if <code>languageTag</code> is <code>null</code>
1677 * @see #toLanguageTag()
1678 * @see java.util.Locale.Builder#setLanguageTag(String)
1679 * @since 1.7
1680 */
1681 public static Locale forLanguageTag(String languageTag) {
1682 LanguageTag tag = LanguageTag.parse(languageTag, null);
1683 InternalLocaleBuilder bldr = new InternalLocaleBuilder();
1684 bldr.setLanguageTag(tag);
1685 BaseLocale base = bldr.getBaseLocale();
1686 LocaleExtensions exts = bldr.getLocaleExtensions();
1687 if (exts == null && base.getVariant().length() > 0) {
1688 exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
1689 base.getRegion(), base.getVariant());
1690 }
1691 return getInstance(base, exts);
1692 }
1693
1694 /**
1695 * Returns a three-letter abbreviation of this locale's language.
1696 * If the language matches an ISO 639-1 two-letter code, the
1697 * corresponding ISO 639-2/T three-letter lowercase code is
1698 * returned. The ISO 639-2 language codes can be found on-line,
1699 * see "Codes for the Representation of Names of Languages Part 2:
1700 * Alpha-3 Code". If the locale specifies a three-letter
1701 * language, the language is returned as is. If the locale does
1702 * not specify a language the empty string is returned.
1703 *
1704 * @return A three-letter abbreviation of this locale's language.
1705 * @exception MissingResourceException Throws MissingResourceException if
1706 * three-letter language abbreviation is not available for this locale.
1707 */
1900 * user. If possible, the name will be localized for the default
1901 * {@link Locale.Category#DISPLAY DISPLAY} locale. If the locale
1902 * doesn't specify a variant code, this function returns the empty string.
1903 *
1904 * @return The name of the display variant code appropriate to the locale.
1905 */
1906 public final String getDisplayVariant() {
1907 return getDisplayVariant(getDefault(Category.DISPLAY));
1908 }
1909
1910 /**
1911 * Returns a name for the locale's variant code that is appropriate for display to the
1912 * user. If possible, the name will be localized for inLocale. If the locale
1913 * doesn't specify a variant code, this function returns the empty string.
1914 *
1915 * @param inLocale The locale for which to retrieve the display variant code.
1916 * @return The name of the display variant code appropriate to the given locale.
1917 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1918 */
1919 public String getDisplayVariant(Locale inLocale) {
1920 if (baseLocale.getVariant().length() == 0)
1921 return "";
1922
1923 LocaleResources lr = LocaleProviderAdapter
1924 .getResourceBundleBased()
1925 .getLocaleResources(inLocale);
1926
1927 String names[] = getDisplayVariantArray(inLocale);
1928
1929 // Get the localized patterns for formatting a list, and use
1930 // them to format the list.
1931 return formatList(names,
1932 lr.getLocaleName("ListCompositionPattern"));
1933 }
1934
1935 /**
1936 * Returns a name for the locale that is appropriate for display to the
1937 * user. This will be the values returned by getDisplayLanguage(),
1938 * getDisplayScript(), getDisplayCountry(), getDisplayVariant() and
1939 * optional <a href="./Locale.html#def_locale_extension">Unicode extensions</a>
1940 * assembled into a single string. The non-empty values are used in order, with
1981 * @return The name of the locale appropriate to display.
1982 * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1983 */
1984 public String getDisplayName(Locale inLocale) {
1985 LocaleResources lr = LocaleProviderAdapter
1986 .getResourceBundleBased()
1987 .getLocaleResources(inLocale);
1988
1989 String languageName = getDisplayLanguage(inLocale);
1990 String scriptName = getDisplayScript(inLocale);
1991 String countryName = getDisplayCountry(inLocale);
1992 String[] variantNames = getDisplayVariantArray(inLocale);
1993
1994 // Get the localized patterns for formatting a display name.
1995 String displayNamePattern = lr.getLocaleName("DisplayNamePattern");
1996 String listCompositionPattern = lr.getLocaleName("ListCompositionPattern");
1997
1998 // The display name consists of a main name, followed by qualifiers.
1999 // Typically, the format is "MainName (Qualifier, Qualifier)" but this
2000 // depends on what pattern is stored in the display locale.
2001 String mainName = null;
2002 String[] qualifierNames = null;
2003
2004 // The main name is the language, or if there is no language, the script,
2005 // then if no script, the country. If there is no language/script/country
2006 // (an anomalous situation) then the display name is simply the variant's
2007 // display name.
2008 if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
2009 if (variantNames.length == 0) {
2010 return "";
2011 } else {
2012 return formatList(variantNames, listCompositionPattern);
2013 }
2014 }
2015 ArrayList<String> names = new ArrayList<>(4);
2016 if (languageName.length() != 0) {
2017 names.add(languageName);
2018 }
2019 if (scriptName.length() != 0) {
2020 names.add(scriptName);
2021 }
2022 if (countryName.length() != 0) {
2023 names.add(countryName);
2024 }
2025 if (variantNames.length != 0) {
2026 names.addAll(Arrays.asList(variantNames));
2027 }
2028
2029 // add Unicode extensions
2030 if (localeExtensions != null) {
2031 localeExtensions.getUnicodeLocaleAttributes().stream()
2032 .map(key -> getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY))
2033 .forEach(names::add);
2034 localeExtensions.getUnicodeLocaleKeys().stream()
2035 .map(key -> getDisplayKeyTypeExtensionString(key, lr, inLocale))
2036 .forEach(names::add);
2037 }
2038
2039 // The first one in the main name
2040 mainName = names.get(0);
2041
2042 // Others are qualifiers
2292 fields.put("hashcode", -1); // place holder just for backward support
2293 out.writeFields();
2294 }
2295
2296 /**
2297 * Deserializes this <code>Locale</code>.
2298 * @param in the <code>ObjectInputStream</code> to read
2299 * @throws IOException
2300 * @throws ClassNotFoundException
2301 * @throws IllformedLocaleException
2302 * @since 1.7
2303 */
2304 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
2305 ObjectInputStream.GetField fields = in.readFields();
2306 String language = (String)fields.get("language", "");
2307 String script = (String)fields.get("script", "");
2308 String country = (String)fields.get("country", "");
2309 String variant = (String)fields.get("variant", "");
2310 String extStr = (String)fields.get("extensions", "");
2311 baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
2312 if (extStr.length() > 0) {
2313 try {
2314 InternalLocaleBuilder bldr = new InternalLocaleBuilder();
2315 bldr.setExtensions(extStr);
2316 localeExtensions = bldr.getLocaleExtensions();
2317 } catch (LocaleSyntaxException e) {
2318 throw new IllformedLocaleException(e.getMessage());
2319 }
2320 } else {
2321 localeExtensions = null;
2322 }
2323 }
2324
2325 /**
2326 * Returns a cached <code>Locale</code> instance equivalent to
2327 * the deserialized <code>Locale</code>. When serialized
2328 * language, country and variant fields read from the object data stream
2329 * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
2330 * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>
2331 * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
2332 * type is "thai"). See <a href="Locale.html#special_cases_constructor">Special Cases</a>
2350 // codes have changed, but we always store the OLD code, for backward compatibility
2351 language = LocaleUtils.toLowerString(language).intern();
2352 if (language == "he") {
2353 return "iw";
2354 } else if (language == "yi") {
2355 return "ji";
2356 } else if (language == "id") {
2357 return "in";
2358 } else {
2359 return language;
2360 }
2361 }
2362
2363 private static LocaleExtensions getCompatibilityExtensions(String language,
2364 String script,
2365 String country,
2366 String variant) {
2367 LocaleExtensions extensions = null;
2368 // Special cases for backward compatibility support
2369 if (LocaleUtils.caseIgnoreMatch(language, "ja")
2370 && script.length() == 0
2371 && LocaleUtils.caseIgnoreMatch(country, "jp")
2372 && "JP".equals(variant)) {
2373 // ja_JP_JP -> u-ca-japanese (calendar = japanese)
2374 extensions = LocaleExtensions.CALENDAR_JAPANESE;
2375 } else if (LocaleUtils.caseIgnoreMatch(language, "th")
2376 && script.length() == 0
2377 && LocaleUtils.caseIgnoreMatch(country, "th")
2378 && "TH".equals(variant)) {
2379 // th_TH_TH -> u-nu-thai (numbersystem = thai)
2380 extensions = LocaleExtensions.NUMBER_THAI;
2381 }
2382 return extensions;
2383 }
2384
2385 /**
2386 * Obtains a localized locale names from a LocaleNameProvider
2387 * implementation.
2388 */
2389 private static class LocaleNameGetter
2390 implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
2391 private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
2392
2393 @Override
2394 public String getObject(LocaleNameProvider localeNameProvider,
2395 Locale locale,
2396 String key,
2789 * @see #setExtension(char, String)
2790 */
2791 public Builder clearExtensions() {
2792 localeBuilder.clearExtensions();
2793 return this;
2794 }
2795
2796 /**
2797 * Returns an instance of <code>Locale</code> created from the fields set
2798 * on this builder.
2799 *
2800 * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
2801 * when constructing a Locale. (Grandfathered tags are handled in
2802 * {@link #setLanguageTag}.)
2803 *
2804 * @return A Locale.
2805 */
2806 public Locale build() {
2807 BaseLocale baseloc = localeBuilder.getBaseLocale();
2808 LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
2809 if (extensions == null && baseloc.getVariant().length() > 0) {
2810 extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
2811 baseloc.getRegion(), baseloc.getVariant());
2812 }
2813 return Locale.getInstance(baseloc, extensions);
2814 }
2815 }
2816
2817 /**
2818 * This enum provides constants to select a filtering mode for locale
2819 * matching. Refer to <a href="http://tools.ietf.org/html/rfc4647">RFC 4647
2820 * Matching of Language Tags</a> for details.
2821 *
2822 * <p>As an example, think of two Language Priority Lists each of which
2823 * includes only one language range and a set of following language tags:
2824 *
2825 * <pre>
2826 * de (German)
2827 * de-DE (German, Germany)
2828 * de-Deva (German, in Devanagari script)
2829 * de-Deva-DE (German, in Devanagari script, Germany)
|
1379 * previous uses of <code>toString</code> that expected language, country, and variant
1380 * fields only. To represent a Locale as a String for interchange purposes, use
1381 * {@link #toLanguageTag}.
1382 *
1383 * <p>Examples: <ul>
1384 * <li>{@code en}</li>
1385 * <li>{@code de_DE}</li>
1386 * <li>{@code _GB}</li>
1387 * <li>{@code en_US_WIN}</li>
1388 * <li>{@code de__POSIX}</li>
1389 * <li>{@code zh_CN_#Hans}</li>
1390 * <li>{@code zh_TW_#Hant_x-java}</li>
1391 * <li>{@code th_TH_TH_#u-nu-thai}</li></ul>
1392 *
1393 * @return A string representation of the Locale, for debugging.
1394 * @see #getDisplayName
1395 * @see #toLanguageTag
1396 */
1397 @Override
1398 public final String toString() {
1399 boolean l = !baseLocale.getLanguage().isEmpty();
1400 boolean s = !baseLocale.getScript().isEmpty();
1401 boolean r = !baseLocale.getRegion().isEmpty();
1402 boolean v = !baseLocale.getVariant().isEmpty();
1403 boolean e = localeExtensions != null && !localeExtensions.getID().isEmpty();
1404
1405 StringBuilder result = new StringBuilder(baseLocale.getLanguage());
1406 if (r || (l && (v || s || e))) {
1407 result.append('_')
1408 .append(baseLocale.getRegion()); // This may just append '_'
1409 }
1410 if (v && (l || r)) {
1411 result.append('_')
1412 .append(baseLocale.getVariant());
1413 }
1414
1415 if (s && (l || r)) {
1416 result.append("_#")
1417 .append(baseLocale.getScript());
1418 }
1419
1420 if (e && (l || r)) {
1421 result.append('_');
1422 if (!s) {
1423 result.append('#');
1487 * <pre>
1488 * new Locale("xx", "YY").toLanguageTag();</pre>
1489 *
1490 * will return "xx-YY", but the language subtag "xx" and the
1491 * region subtag "YY" are invalid because they are not registered
1492 * in the IANA Language Subtag Registry.
1493 *
1494 * @return a BCP47 language tag representing the locale
1495 * @see #forLanguageTag(String)
1496 * @since 1.7
1497 */
1498 public String toLanguageTag() {
1499 if (languageTag != null) {
1500 return languageTag;
1501 }
1502
1503 LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
1504 StringBuilder buf = new StringBuilder();
1505
1506 String subtag = tag.getLanguage();
1507 if (!subtag.isEmpty()) {
1508 buf.append(LanguageTag.canonicalizeLanguage(subtag));
1509 }
1510
1511 subtag = tag.getScript();
1512 if (!subtag.isEmpty()) {
1513 buf.append(LanguageTag.SEP);
1514 buf.append(LanguageTag.canonicalizeScript(subtag));
1515 }
1516
1517 subtag = tag.getRegion();
1518 if (!subtag.isEmpty()) {
1519 buf.append(LanguageTag.SEP);
1520 buf.append(LanguageTag.canonicalizeRegion(subtag));
1521 }
1522
1523 List<String>subtags = tag.getVariants();
1524 for (String s : subtags) {
1525 buf.append(LanguageTag.SEP);
1526 // preserve casing
1527 buf.append(s);
1528 }
1529
1530 subtags = tag.getExtensions();
1531 for (String s : subtags) {
1532 buf.append(LanguageTag.SEP);
1533 buf.append(LanguageTag.canonicalizeExtension(s));
1534 }
1535
1536 subtag = tag.getPrivateuse();
1537 if (!subtag.isEmpty()) {
1538 if (buf.length() > 0) {
1539 buf.append(LanguageTag.SEP);
1540 }
1541 buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
1542 // preserve casing
1543 buf.append(subtag);
1544 }
1545
1546 String langTag = buf.toString();
1547 synchronized (this) {
1548 if (languageTag == null) {
1549 languageTag = langTag;
1550 }
1551 }
1552 return languageTag;
1553 }
1554
1555 /**
1556 * Returns a locale for the specified IETF BCP 47 language tag string.
1557 *
1667 *
1668 * <p>For a list of all grandfathered tags, see the
1669 * IANA Language Subtag Registry (search for "Type: grandfathered").
1670 *
1671 * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>
1672 * and <code>forLanguageTag</code> will round-trip.
1673 *
1674 * @param languageTag the language tag
1675 * @return The locale that best represents the language tag.
1676 * @throws NullPointerException if <code>languageTag</code> is <code>null</code>
1677 * @see #toLanguageTag()
1678 * @see java.util.Locale.Builder#setLanguageTag(String)
1679 * @since 1.7
1680 */
1681 public static Locale forLanguageTag(String languageTag) {
1682 LanguageTag tag = LanguageTag.parse(languageTag, null);
1683 InternalLocaleBuilder bldr = new InternalLocaleBuilder();
1684 bldr.setLanguageTag(tag);
1685 BaseLocale base = bldr.getBaseLocale();
1686 LocaleExtensions exts = bldr.getLocaleExtensions();
1687 if (exts == null && !base.getVariant().isEmpty()) {
1688 exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
1689 base.getRegion(), base.getVariant());
1690 }
1691 return getInstance(base, exts);
1692 }
1693
1694 /**
1695 * Returns a three-letter abbreviation of this locale's language.
1696 * If the language matches an ISO 639-1 two-letter code, the
1697 * corresponding ISO 639-2/T three-letter lowercase code is
1698 * returned. The ISO 639-2 language codes can be found on-line,
1699 * see "Codes for the Representation of Names of Languages Part 2:
1700 * Alpha-3 Code". If the locale specifies a three-letter
1701 * language, the language is returned as is. If the locale does
1702 * not specify a language the empty string is returned.
1703 *
1704 * @return A three-letter abbreviation of this locale's language.
1705 * @exception MissingResourceException Throws MissingResourceException if
1706 * three-letter language abbreviation is not available for this locale.
1707 */
1900 * user. If possible, the name will be localized for the default
1901 * {@link Locale.Category#DISPLAY DISPLAY} locale. If the locale
1902 * doesn't specify a variant code, this function returns the empty string.
1903 *
1904 * @return The name of the display variant code appropriate to the locale.
1905 */
1906 public final String getDisplayVariant() {
1907 return getDisplayVariant(getDefault(Category.DISPLAY));
1908 }
1909
1910 /**
1911 * Returns a name for the locale's variant code that is appropriate for display to the
1912 * user. If possible, the name will be localized for inLocale. If the locale
1913 * doesn't specify a variant code, this function returns the empty string.
1914 *
1915 * @param inLocale The locale for which to retrieve the display variant code.
1916 * @return The name of the display variant code appropriate to the given locale.
1917 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1918 */
1919 public String getDisplayVariant(Locale inLocale) {
1920 if (baseLocale.getVariant().isEmpty())
1921 return "";
1922
1923 LocaleResources lr = LocaleProviderAdapter
1924 .getResourceBundleBased()
1925 .getLocaleResources(inLocale);
1926
1927 String names[] = getDisplayVariantArray(inLocale);
1928
1929 // Get the localized patterns for formatting a list, and use
1930 // them to format the list.
1931 return formatList(names,
1932 lr.getLocaleName("ListCompositionPattern"));
1933 }
1934
1935 /**
1936 * Returns a name for the locale that is appropriate for display to the
1937 * user. This will be the values returned by getDisplayLanguage(),
1938 * getDisplayScript(), getDisplayCountry(), getDisplayVariant() and
1939 * optional <a href="./Locale.html#def_locale_extension">Unicode extensions</a>
1940 * assembled into a single string. The non-empty values are used in order, with
1981 * @return The name of the locale appropriate to display.
1982 * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1983 */
1984 public String getDisplayName(Locale inLocale) {
1985 LocaleResources lr = LocaleProviderAdapter
1986 .getResourceBundleBased()
1987 .getLocaleResources(inLocale);
1988
1989 String languageName = getDisplayLanguage(inLocale);
1990 String scriptName = getDisplayScript(inLocale);
1991 String countryName = getDisplayCountry(inLocale);
1992 String[] variantNames = getDisplayVariantArray(inLocale);
1993
1994 // Get the localized patterns for formatting a display name.
1995 String displayNamePattern = lr.getLocaleName("DisplayNamePattern");
1996 String listCompositionPattern = lr.getLocaleName("ListCompositionPattern");
1997
1998 // The display name consists of a main name, followed by qualifiers.
1999 // Typically, the format is "MainName (Qualifier, Qualifier)" but this
2000 // depends on what pattern is stored in the display locale.
2001 String mainName;
2002 String[] qualifierNames;
2003
2004 // The main name is the language, or if there is no language, the script,
2005 // then if no script, the country. If there is no language/script/country
2006 // (an anomalous situation) then the display name is simply the variant's
2007 // display name.
2008 if (languageName.isEmpty() && scriptName.isEmpty() && countryName.isEmpty()) {
2009 if (variantNames.length == 0) {
2010 return "";
2011 } else {
2012 return formatList(variantNames, listCompositionPattern);
2013 }
2014 }
2015 ArrayList<String> names = new ArrayList<>(4);
2016 if (!languageName.isEmpty()) {
2017 names.add(languageName);
2018 }
2019 if (!scriptName.isEmpty()) {
2020 names.add(scriptName);
2021 }
2022 if (!countryName.isEmpty()) {
2023 names.add(countryName);
2024 }
2025 if (variantNames.length != 0) {
2026 names.addAll(Arrays.asList(variantNames));
2027 }
2028
2029 // add Unicode extensions
2030 if (localeExtensions != null) {
2031 localeExtensions.getUnicodeLocaleAttributes().stream()
2032 .map(key -> getDisplayString(key, null, inLocale, DISPLAY_UEXT_KEY))
2033 .forEach(names::add);
2034 localeExtensions.getUnicodeLocaleKeys().stream()
2035 .map(key -> getDisplayKeyTypeExtensionString(key, lr, inLocale))
2036 .forEach(names::add);
2037 }
2038
2039 // The first one in the main name
2040 mainName = names.get(0);
2041
2042 // Others are qualifiers
2292 fields.put("hashcode", -1); // place holder just for backward support
2293 out.writeFields();
2294 }
2295
2296 /**
2297 * Deserializes this <code>Locale</code>.
2298 * @param in the <code>ObjectInputStream</code> to read
2299 * @throws IOException
2300 * @throws ClassNotFoundException
2301 * @throws IllformedLocaleException
2302 * @since 1.7
2303 */
2304 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
2305 ObjectInputStream.GetField fields = in.readFields();
2306 String language = (String)fields.get("language", "");
2307 String script = (String)fields.get("script", "");
2308 String country = (String)fields.get("country", "");
2309 String variant = (String)fields.get("variant", "");
2310 String extStr = (String)fields.get("extensions", "");
2311 baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
2312 if (!extStr.isEmpty()) {
2313 try {
2314 InternalLocaleBuilder bldr = new InternalLocaleBuilder();
2315 bldr.setExtensions(extStr);
2316 localeExtensions = bldr.getLocaleExtensions();
2317 } catch (LocaleSyntaxException e) {
2318 throw new IllformedLocaleException(e.getMessage());
2319 }
2320 } else {
2321 localeExtensions = null;
2322 }
2323 }
2324
2325 /**
2326 * Returns a cached <code>Locale</code> instance equivalent to
2327 * the deserialized <code>Locale</code>. When serialized
2328 * language, country and variant fields read from the object data stream
2329 * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
2330 * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>
2331 * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
2332 * type is "thai"). See <a href="Locale.html#special_cases_constructor">Special Cases</a>
2350 // codes have changed, but we always store the OLD code, for backward compatibility
2351 language = LocaleUtils.toLowerString(language).intern();
2352 if (language == "he") {
2353 return "iw";
2354 } else if (language == "yi") {
2355 return "ji";
2356 } else if (language == "id") {
2357 return "in";
2358 } else {
2359 return language;
2360 }
2361 }
2362
2363 private static LocaleExtensions getCompatibilityExtensions(String language,
2364 String script,
2365 String country,
2366 String variant) {
2367 LocaleExtensions extensions = null;
2368 // Special cases for backward compatibility support
2369 if (LocaleUtils.caseIgnoreMatch(language, "ja")
2370 && script.isEmpty()
2371 && LocaleUtils.caseIgnoreMatch(country, "jp")
2372 && "JP".equals(variant)) {
2373 // ja_JP_JP -> u-ca-japanese (calendar = japanese)
2374 extensions = LocaleExtensions.CALENDAR_JAPANESE;
2375 } else if (LocaleUtils.caseIgnoreMatch(language, "th")
2376 && script.isEmpty()
2377 && LocaleUtils.caseIgnoreMatch(country, "th")
2378 && "TH".equals(variant)) {
2379 // th_TH_TH -> u-nu-thai (numbersystem = thai)
2380 extensions = LocaleExtensions.NUMBER_THAI;
2381 }
2382 return extensions;
2383 }
2384
2385 /**
2386 * Obtains a localized locale names from a LocaleNameProvider
2387 * implementation.
2388 */
2389 private static class LocaleNameGetter
2390 implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
2391 private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
2392
2393 @Override
2394 public String getObject(LocaleNameProvider localeNameProvider,
2395 Locale locale,
2396 String key,
2789 * @see #setExtension(char, String)
2790 */
2791 public Builder clearExtensions() {
2792 localeBuilder.clearExtensions();
2793 return this;
2794 }
2795
2796 /**
2797 * Returns an instance of <code>Locale</code> created from the fields set
2798 * on this builder.
2799 *
2800 * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
2801 * when constructing a Locale. (Grandfathered tags are handled in
2802 * {@link #setLanguageTag}.)
2803 *
2804 * @return A Locale.
2805 */
2806 public Locale build() {
2807 BaseLocale baseloc = localeBuilder.getBaseLocale();
2808 LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
2809 if (extensions == null && !baseloc.getVariant().isEmpty()) {
2810 extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
2811 baseloc.getRegion(), baseloc.getVariant());
2812 }
2813 return Locale.getInstance(baseloc, extensions);
2814 }
2815 }
2816
2817 /**
2818 * This enum provides constants to select a filtering mode for locale
2819 * matching. Refer to <a href="http://tools.ietf.org/html/rfc4647">RFC 4647
2820 * Matching of Language Tags</a> for details.
2821 *
2822 * <p>As an example, think of two Language Priority Lists each of which
2823 * includes only one language range and a set of following language tags:
2824 *
2825 * <pre>
2826 * de (German)
2827 * de-DE (German, Germany)
2828 * de-Deva (German, in Devanagari script)
2829 * de-Deva-DE (German, in Devanagari script, Germany)
|