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.LocaleServiceProviderPool; |
54 import sun.util.locale.AsciiUtil; |
|
55 import sun.util.locale.BaseLocale; |
54 import sun.util.locale.BaseLocale; |
56 import sun.util.locale.InternalLocaleBuilder; |
55 import sun.util.locale.InternalLocaleBuilder; |
57 import sun.util.locale.LanguageTag; |
56 import sun.util.locale.LanguageTag; |
58 import sun.util.locale.LocaleExtensions; |
57 import sun.util.locale.LocaleExtensions; |
59 import sun.util.locale.LocaleObjectCache; |
58 import sun.util.locale.LocaleObjectCache; |
60 import sun.util.locale.LocaleSyntaxException; |
59 import sun.util.locale.LocaleSyntaxException; |
|
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.UnicodeLocaleExtension; |
63 import sun.util.resources.LocaleData; |
63 import sun.util.resources.LocaleData; |
64 import sun.util.resources.OpenListResourceBundle; |
64 import sun.util.resources.OpenListResourceBundle; |
65 |
65 |
410 |
410 |
411 static private final Cache LOCALECACHE = new Cache(); |
411 static private final Cache LOCALECACHE = new Cache(); |
412 |
412 |
413 /** Useful constant for language. |
413 /** Useful constant for language. |
414 */ |
414 */ |
415 static public final Locale ENGLISH = getInstance("en", "", ""); |
415 static public final Locale ENGLISH = createConstant("en", ""); |
416 |
416 |
417 /** Useful constant for language. |
417 /** Useful constant for language. |
418 */ |
418 */ |
419 static public final Locale FRENCH = getInstance("fr", "", ""); |
419 static public final Locale FRENCH = createConstant("fr", ""); |
420 |
420 |
421 /** Useful constant for language. |
421 /** Useful constant for language. |
422 */ |
422 */ |
423 static public final Locale GERMAN = getInstance("de", "", ""); |
423 static public final Locale GERMAN = createConstant("de", ""); |
424 |
424 |
425 /** Useful constant for language. |
425 /** Useful constant for language. |
426 */ |
426 */ |
427 static public final Locale ITALIAN = getInstance("it", "", ""); |
427 static public final Locale ITALIAN = createConstant("it", ""); |
428 |
428 |
429 /** Useful constant for language. |
429 /** Useful constant for language. |
430 */ |
430 */ |
431 static public final Locale JAPANESE = getInstance("ja", "", ""); |
431 static public final Locale JAPANESE = createConstant("ja", ""); |
432 |
432 |
433 /** Useful constant for language. |
433 /** Useful constant for language. |
434 */ |
434 */ |
435 static public final Locale KOREAN = getInstance("ko", "", ""); |
435 static public final Locale KOREAN = createConstant("ko", ""); |
436 |
436 |
437 /** Useful constant for language. |
437 /** Useful constant for language. |
438 */ |
438 */ |
439 static public final Locale CHINESE = getInstance("zh", "", ""); |
439 static public final Locale CHINESE = createConstant("zh", ""); |
440 |
440 |
441 /** Useful constant for language. |
441 /** Useful constant for language. |
442 */ |
442 */ |
443 static public final Locale SIMPLIFIED_CHINESE = getInstance("zh", "CN", ""); |
443 static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN"); |
444 |
444 |
445 /** Useful constant for language. |
445 /** Useful constant for language. |
446 */ |
446 */ |
447 static public final Locale TRADITIONAL_CHINESE = getInstance("zh", "TW", ""); |
447 static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW"); |
448 |
448 |
449 /** Useful constant for country. |
449 /** Useful constant for country. |
450 */ |
450 */ |
451 static public final Locale FRANCE = getInstance("fr", "FR", ""); |
451 static public final Locale FRANCE = createConstant("fr", "FR"); |
452 |
452 |
453 /** Useful constant for country. |
453 /** Useful constant for country. |
454 */ |
454 */ |
455 static public final Locale GERMANY = getInstance("de", "DE", ""); |
455 static public final Locale GERMANY = createConstant("de", "DE"); |
456 |
456 |
457 /** Useful constant for country. |
457 /** Useful constant for country. |
458 */ |
458 */ |
459 static public final Locale ITALY = getInstance("it", "IT", ""); |
459 static public final Locale ITALY = createConstant("it", "IT"); |
460 |
460 |
461 /** Useful constant for country. |
461 /** Useful constant for country. |
462 */ |
462 */ |
463 static public final Locale JAPAN = getInstance("ja", "JP", ""); |
463 static public final Locale JAPAN = createConstant("ja", "JP"); |
464 |
464 |
465 /** Useful constant for country. |
465 /** Useful constant for country. |
466 */ |
466 */ |
467 static public final Locale KOREA = getInstance("ko", "KR", ""); |
467 static public final Locale KOREA = createConstant("ko", "KR"); |
468 |
468 |
469 /** Useful constant for country. |
469 /** Useful constant for country. |
470 */ |
470 */ |
471 static public final Locale CHINA = SIMPLIFIED_CHINESE; |
471 static public final Locale CHINA = SIMPLIFIED_CHINESE; |
472 |
472 |
478 */ |
478 */ |
479 static public final Locale TAIWAN = TRADITIONAL_CHINESE; |
479 static public final Locale TAIWAN = TRADITIONAL_CHINESE; |
480 |
480 |
481 /** Useful constant for country. |
481 /** Useful constant for country. |
482 */ |
482 */ |
483 static public final Locale UK = getInstance("en", "GB", ""); |
483 static public final Locale UK = createConstant("en", "GB"); |
484 |
484 |
485 /** Useful constant for country. |
485 /** Useful constant for country. |
486 */ |
486 */ |
487 static public final Locale US = getInstance("en", "US", ""); |
487 static public final Locale US = createConstant("en", "US"); |
488 |
488 |
489 /** Useful constant for country. |
489 /** Useful constant for country. |
490 */ |
490 */ |
491 static public final Locale CANADA = getInstance("en", "CA", ""); |
491 static public final Locale CANADA = createConstant("en", "CA"); |
492 |
492 |
493 /** Useful constant for country. |
493 /** Useful constant for country. |
494 */ |
494 */ |
495 static public final Locale CANADA_FRENCH = getInstance("fr", "CA", ""); |
495 static public final Locale CANADA_FRENCH = createConstant("fr", "CA"); |
496 |
496 |
497 /** |
497 /** |
498 * Useful constant for the root locale. The root locale is the locale whose |
498 * Useful constant for the root locale. The root locale is the locale whose |
499 * language, country, and variant are empty ("") strings. This is regarded |
499 * language, country, and variant are empty ("") strings. This is regarded |
500 * as the base locale of all locales, and is used as the language/country |
500 * as the base locale of all locales, and is used as the language/country |
501 * neutral locale for the locale sensitive operations. |
501 * neutral locale for the locale sensitive operations. |
502 * |
502 * |
503 * @since 1.6 |
503 * @since 1.6 |
504 */ |
504 */ |
505 static public final Locale ROOT = getInstance("", "", ""); |
505 static public final Locale ROOT = createConstant("", ""); |
506 |
506 |
507 /** |
507 /** |
508 * The key for the private use extension ('x'). |
508 * The key for the private use extension ('x'). |
509 * |
509 * |
510 * @see #getExtension(char) |
510 * @see #getExtension(char) |
530 * Display types for retrieving localized names from the name providers. |
530 * Display types for retrieving localized names from the name providers. |
531 */ |
531 */ |
532 private static final int DISPLAY_LANGUAGE = 0; |
532 private static final int DISPLAY_LANGUAGE = 0; |
533 private static final int DISPLAY_COUNTRY = 1; |
533 private static final int DISPLAY_COUNTRY = 1; |
534 private static final int DISPLAY_VARIANT = 2; |
534 private static final int DISPLAY_VARIANT = 2; |
535 private static final int DISPLAY_SCRIPT = 3; |
535 private static final int DISPLAY_SCRIPT = 3; |
536 |
536 |
537 /** |
537 /** |
538 * Private constructor used by getInstance method |
538 * Private constructor used by getInstance method |
539 */ |
539 */ |
540 private Locale(BaseLocale baseLocale, LocaleExtensions extensions) { |
540 private Locale(BaseLocale baseLocale, LocaleExtensions extensions) { |
541 _baseLocale = baseLocale; |
541 this.baseLocale = baseLocale; |
542 _extensions = extensions; |
542 this.localeExtensions = extensions; |
543 } |
543 } |
544 |
544 |
545 /** |
545 /** |
546 * Construct a locale from language, country and variant. |
546 * Construct a locale from language, country and variant. |
547 * This constructor normalizes the language value to lowercase and |
547 * This constructor normalizes the language value to lowercase and |
570 */ |
570 */ |
571 public Locale(String language, String country, String variant) { |
571 public Locale(String language, String country, String variant) { |
572 if (language== null || country == null || variant == null) { |
572 if (language== null || country == null || variant == null) { |
573 throw new NullPointerException(); |
573 throw new NullPointerException(); |
574 } |
574 } |
575 _baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant); |
575 baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant); |
576 _extensions = getCompatibilityExtensions(language, "", country, variant); |
576 localeExtensions = getCompatibilityExtensions(language, "", country, variant); |
577 } |
577 } |
578 |
578 |
579 /** |
579 /** |
580 * Construct a locale from language and country. |
580 * Construct a locale from language and country. |
581 * This constructor normalizes the language value to lowercase and |
581 * This constructor normalizes the language value to lowercase and |
625 public Locale(String language) { |
625 public Locale(String language) { |
626 this(language, "", ""); |
626 this(language, "", ""); |
627 } |
627 } |
628 |
628 |
629 /** |
629 /** |
|
630 * This method must be called only for creating the Locale.* |
|
631 * constants due to making shortcuts. |
|
632 */ |
|
633 private static Locale createConstant(String lang, String country) { |
|
634 BaseLocale base = BaseLocale.createInstance(lang, country); |
|
635 return getInstance(base, null); |
|
636 } |
|
637 |
|
638 /** |
630 * Returns a <code>Locale</code> constructed from the given |
639 * Returns a <code>Locale</code> constructed from the given |
631 * <code>language</code>, <code>country</code> and |
640 * <code>language</code>, <code>country</code> and |
632 * <code>variant</code>. If the same <code>Locale</code> instance |
641 * <code>variant</code>. If the same <code>Locale</code> instance |
633 * is available in the cache, then that instance is |
642 * is available in the cache, then that instance is |
634 * returned. Otherwise, a new <code>Locale</code> instance is |
643 * returned. Otherwise, a new <code>Locale</code> instance is |
639 * @param variant vendor and browser specific code. See class description. |
648 * @param variant vendor and browser specific code. See class description. |
640 * @return the <code>Locale</code> instance requested |
649 * @return the <code>Locale</code> instance requested |
641 * @exception NullPointerException if any argument is null. |
650 * @exception NullPointerException if any argument is null. |
642 */ |
651 */ |
643 static Locale getInstance(String language, String country, String variant) { |
652 static Locale getInstance(String language, String country, String variant) { |
644 return getInstance(language, "", country, variant, LocaleExtensions.EMPTY_EXTENSIONS); |
653 return getInstance(language, "", country, variant, null); |
645 } |
654 } |
646 |
655 |
647 static Locale getInstance(String language, String script, String country, |
656 static Locale getInstance(String language, String script, String country, |
648 String variant, LocaleExtensions extensions) { |
657 String variant, LocaleExtensions extensions) { |
649 if (language== null || script == null || country == null || variant == null) { |
658 if (language== null || script == null || country == null || variant == null) { |
650 throw new NullPointerException(); |
659 throw new NullPointerException(); |
651 } |
660 } |
652 |
661 |
653 if (extensions == null) { |
662 if (extensions == null) { |
654 extensions = LocaleExtensions.EMPTY_EXTENSIONS; |
|
655 } |
|
656 |
|
657 if (extensions.equals(LocaleExtensions.EMPTY_EXTENSIONS)) { |
|
658 extensions = getCompatibilityExtensions(language, script, country, variant); |
663 extensions = getCompatibilityExtensions(language, script, country, variant); |
659 } |
664 } |
660 |
665 |
661 BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant); |
666 BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant); |
662 return getInstance(baseloc, extensions); |
667 return getInstance(baseloc, extensions); |
666 LocaleKey key = new LocaleKey(baseloc, extensions); |
671 LocaleKey key = new LocaleKey(baseloc, extensions); |
667 return LOCALECACHE.get(key); |
672 return LOCALECACHE.get(key); |
668 } |
673 } |
669 |
674 |
670 private static class Cache extends LocaleObjectCache<LocaleKey, Locale> { |
675 private static class Cache extends LocaleObjectCache<LocaleKey, Locale> { |
671 public Cache() { |
676 private Cache() { |
672 } |
677 } |
|
678 |
|
679 @Override |
673 protected Locale createObject(LocaleKey key) { |
680 protected Locale createObject(LocaleKey key) { |
674 return new Locale(key._base, key._exts); |
681 return new Locale(key.base, key.exts); |
675 } |
682 } |
676 } |
683 } |
677 |
684 |
678 private static class LocaleKey { |
685 private static final class LocaleKey { |
679 private BaseLocale _base; |
686 private final BaseLocale base; |
680 private LocaleExtensions _exts; |
687 private final LocaleExtensions exts; |
|
688 private final int hash; |
681 |
689 |
682 private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) { |
690 private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) { |
683 _base = baseLocale; |
691 base = baseLocale; |
684 _exts = extensions; |
692 exts = extensions; |
685 } |
693 |
686 |
694 // Calculate the hash value here because it's always used. |
|
695 int h = base.hashCode(); |
|
696 if (exts != null) { |
|
697 h ^= exts.hashCode(); |
|
698 } |
|
699 hash = h; |
|
700 } |
|
701 |
|
702 @Override |
687 public boolean equals(Object obj) { |
703 public boolean equals(Object obj) { |
688 if (this == obj) { |
704 if (this == obj) { |
689 return true; |
705 return true; |
690 } |
706 } |
691 if (!(obj instanceof LocaleKey)) { |
707 if (!(obj instanceof LocaleKey)) { |
692 return false; |
708 return false; |
693 } |
709 } |
694 LocaleKey other = (LocaleKey)obj; |
710 LocaleKey other = (LocaleKey)obj; |
695 return _base.equals(other._base) && _exts.equals(other._exts); |
711 if (hash != other.hash || !base.equals(other.base)) { |
696 } |
712 return false; |
697 |
713 } |
|
714 if (exts == null) { |
|
715 return other.exts == null; |
|
716 } |
|
717 return exts.equals(other.exts); |
|
718 } |
|
719 |
|
720 @Override |
698 public int hashCode() { |
721 public int hashCode() { |
699 return _base.hashCode() ^ _exts.hashCode(); |
722 return hash; |
700 } |
723 } |
701 } |
724 } |
702 |
725 |
703 /** |
726 /** |
704 * Gets the current value of the default locale for this instance |
727 * Gets the current value of the default locale for this instance |
1005 * |
1028 * |
1006 * @return The country/region code, or the empty string if none is defined. |
1029 * @return The country/region code, or the empty string if none is defined. |
1007 * @see #getDisplayCountry |
1030 * @see #getDisplayCountry |
1008 */ |
1031 */ |
1009 public String getCountry() { |
1032 public String getCountry() { |
1010 return _baseLocale.getRegion(); |
1033 return baseLocale.getRegion(); |
1011 } |
1034 } |
1012 |
1035 |
1013 /** |
1036 /** |
1014 * Returns the variant code for this locale. |
1037 * Returns the variant code for this locale. |
1015 * |
1038 * |
1016 * @return The variant code, or the empty string if none is defined. |
1039 * @return The variant code, or the empty string if none is defined. |
1017 * @see #getDisplayVariant |
1040 * @see #getDisplayVariant |
1018 */ |
1041 */ |
1019 public String getVariant() { |
1042 public String getVariant() { |
1020 return _baseLocale.getVariant(); |
1043 return baseLocale.getVariant(); |
1021 } |
1044 } |
1022 |
1045 |
1023 /** |
1046 /** |
1024 * Returns the extension (or private use) value associated with |
1047 * Returns the extension (or private use) value associated with |
1025 * the specified key, or null if there is no extension |
1048 * the specified key, or null if there is no extension |
1095 * @return The set of Unicode locale keys, or the empty set if this locale has |
1124 * @return The set of Unicode locale keys, or the empty set if this locale has |
1096 * no Unicode locale keywords. |
1125 * no Unicode locale keywords. |
1097 * @since 1.7 |
1126 * @since 1.7 |
1098 */ |
1127 */ |
1099 public Set<String> getUnicodeLocaleKeys() { |
1128 public Set<String> getUnicodeLocaleKeys() { |
1100 return _extensions.getUnicodeLocaleKeys(); |
1129 if (localeExtensions == null) { |
|
1130 return Collections.emptySet(); |
|
1131 } |
|
1132 return localeExtensions.getUnicodeLocaleKeys(); |
1101 } |
1133 } |
1102 |
1134 |
1103 /** |
1135 /** |
1104 * Package locale method returning the Locale's BaseLocale, |
1136 * Package locale method returning the Locale's BaseLocale, |
1105 * used by ResourceBundle |
1137 * used by ResourceBundle |
1106 * @return base locale of this Locale |
1138 * @return base locale of this Locale |
1107 */ |
1139 */ |
1108 BaseLocale getBaseLocale() { |
1140 BaseLocale getBaseLocale() { |
1109 return _baseLocale; |
1141 return baseLocale; |
1110 } |
1142 } |
1111 |
1143 |
1112 /** |
1144 /** |
1113 * Package local method returning the Locale's LocaleExtensions, |
1145 * Package private method returning the Locale's LocaleExtensions, |
1114 * used by ResourceBundle |
1146 * used by ResourceBundle. |
1115 * @return locale exnteions of this Locale |
1147 * @return locale exnteions of this Locale, |
|
1148 * or {@code null} if no extensions are defined |
1116 */ |
1149 */ |
1117 LocaleExtensions getLocaleExtensions() { |
1150 LocaleExtensions getLocaleExtensions() { |
1118 return _extensions; |
1151 return localeExtensions; |
1119 } |
1152 } |
1120 |
1153 |
1121 /** |
1154 /** |
1122 * Returns a string representation of this <code>Locale</code> |
1155 * Returns a string representation of this <code>Locale</code> |
1123 * object, consisting of language, country, variant, script, |
1156 * object, consisting of language, country, variant, script, |
1158 * |
1191 * |
1159 * @return A string representation of the Locale, for debugging. |
1192 * @return A string representation of the Locale, for debugging. |
1160 * @see #getDisplayName |
1193 * @see #getDisplayName |
1161 * @see #toLanguageTag |
1194 * @see #toLanguageTag |
1162 */ |
1195 */ |
|
1196 @Override |
1163 public final String toString() { |
1197 public final String toString() { |
1164 boolean l = (_baseLocale.getLanguage().length() != 0); |
1198 boolean l = (baseLocale.getLanguage().length() != 0); |
1165 boolean s = (_baseLocale.getScript().length() != 0); |
1199 boolean s = (baseLocale.getScript().length() != 0); |
1166 boolean r = (_baseLocale.getRegion().length() != 0); |
1200 boolean r = (baseLocale.getRegion().length() != 0); |
1167 boolean v = (_baseLocale.getVariant().length() != 0); |
1201 boolean v = (baseLocale.getVariant().length() != 0); |
1168 boolean e = (_extensions.getID().length() != 0); |
1202 boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0); |
1169 |
1203 |
1170 StringBuilder result = new StringBuilder(_baseLocale.getLanguage()); |
1204 StringBuilder result = new StringBuilder(baseLocale.getLanguage()); |
1171 if (r || (l && (v || s || e))) { |
1205 if (r || (l && (v || s || e))) { |
1172 result.append('_') |
1206 result.append('_') |
1173 .append(_baseLocale.getRegion()); // This may just append '_' |
1207 .append(baseLocale.getRegion()); // This may just append '_' |
1174 } |
1208 } |
1175 if (v && (l || r)) { |
1209 if (v && (l || r)) { |
1176 result.append('_') |
1210 result.append('_') |
1177 .append(_baseLocale.getVariant()); |
1211 .append(baseLocale.getVariant()); |
1178 } |
1212 } |
1179 |
1213 |
1180 if (s && (l || r)) { |
1214 if (s && (l || r)) { |
1181 result.append("_#") |
1215 result.append("_#") |
1182 .append(_baseLocale.getScript()); |
1216 .append(baseLocale.getScript()); |
1183 } |
1217 } |
1184 |
1218 |
1185 if (e && (l || r)) { |
1219 if (e && (l || r)) { |
1186 result.append('_'); |
1220 result.append('_'); |
1187 if (!s) { |
1221 if (!s) { |
1188 result.append('#'); |
1222 result.append('#'); |
1189 } |
1223 } |
1190 result.append(_extensions.getID()); |
1224 result.append(localeExtensions.getID()); |
1191 } |
1225 } |
1192 |
1226 |
1193 return result.toString(); |
1227 return result.toString(); |
1194 } |
1228 } |
1195 |
1229 |
1259 * @return a BCP47 language tag representing the locale |
1293 * @return a BCP47 language tag representing the locale |
1260 * @see #forLanguageTag(String) |
1294 * @see #forLanguageTag(String) |
1261 * @since 1.7 |
1295 * @since 1.7 |
1262 */ |
1296 */ |
1263 public String toLanguageTag() { |
1297 public String toLanguageTag() { |
1264 LanguageTag tag = LanguageTag.parseLocale(_baseLocale, _extensions); |
1298 LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions); |
1265 StringBuilder buf = new StringBuilder(); |
1299 StringBuilder buf = new StringBuilder(); |
1266 |
1300 |
1267 String subtag = tag.getLanguage(); |
1301 String subtag = tag.getLanguage(); |
1268 if (subtag.length() > 0) { |
1302 if (subtag.length() > 0) { |
1269 buf.append(LanguageTag.canonicalizeLanguage(subtag)); |
1303 buf.append(LanguageTag.canonicalizeLanguage(subtag)); |
1431 LanguageTag tag = LanguageTag.parse(languageTag, null); |
1465 LanguageTag tag = LanguageTag.parse(languageTag, null); |
1432 InternalLocaleBuilder bldr = new InternalLocaleBuilder(); |
1466 InternalLocaleBuilder bldr = new InternalLocaleBuilder(); |
1433 bldr.setLanguageTag(tag); |
1467 bldr.setLanguageTag(tag); |
1434 BaseLocale base = bldr.getBaseLocale(); |
1468 BaseLocale base = bldr.getBaseLocale(); |
1435 LocaleExtensions exts = bldr.getLocaleExtensions(); |
1469 LocaleExtensions exts = bldr.getLocaleExtensions(); |
1436 if (exts.isEmpty() && base.getVariant().length() > 0) { |
1470 if (exts == null && base.getVariant().length() > 0) { |
1437 exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(), base.getRegion(), base.getVariant()); |
1471 exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(), |
|
1472 base.getRegion(), base.getVariant()); |
1438 } |
1473 } |
1439 return getInstance(base, exts); |
1474 return getInstance(base, exts); |
1440 } |
1475 } |
1441 |
1476 |
1442 /** |
1477 /** |
1479 * @return A three-letter abbreviation of this locale's country. |
1514 * @return A three-letter abbreviation of this locale's country. |
1480 * @exception MissingResourceException Throws MissingResourceException if the |
1515 * @exception MissingResourceException Throws MissingResourceException if the |
1481 * three-letter country abbreviation is not available for this locale. |
1516 * three-letter country abbreviation is not available for this locale. |
1482 */ |
1517 */ |
1483 public String getISO3Country() throws MissingResourceException { |
1518 public String getISO3Country() throws MissingResourceException { |
1484 String country3 = getISO3Code(_baseLocale.getRegion(), LocaleISOData.isoCountryTable); |
1519 String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable); |
1485 if (country3 == null) { |
1520 if (country3 == null) { |
1486 throw new MissingResourceException("Couldn't find 3-letter country code for " |
1521 throw new MissingResourceException("Couldn't find 3-letter country code for " |
1487 + _baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry"); |
1522 + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry"); |
1488 } |
1523 } |
1489 return country3; |
1524 return country3; |
1490 } |
1525 } |
1491 |
1526 |
1492 private static final String getISO3Code(String iso2Code, String table) { |
1527 private static final String getISO3Code(String iso2Code, String table) { |
1849 * deemed equal to another Locale with identical language, script, country, |
1888 * deemed equal to another Locale with identical language, script, country, |
1850 * variant and extensions, and unequal to all other objects. |
1889 * variant and extensions, and unequal to all other objects. |
1851 * |
1890 * |
1852 * @return true if this Locale is equal to the specified object. |
1891 * @return true if this Locale is equal to the specified object. |
1853 */ |
1892 */ |
1854 |
1893 @Override |
1855 public boolean equals(Object obj) { |
1894 public boolean equals(Object obj) { |
1856 if (this == obj) // quick check |
1895 if (this == obj) // quick check |
1857 return true; |
1896 return true; |
1858 if (!(obj instanceof Locale)) |
1897 if (!(obj instanceof Locale)) |
1859 return false; |
1898 return false; |
1860 BaseLocale otherBase = ((Locale)obj)._baseLocale; |
1899 BaseLocale otherBase = ((Locale)obj).baseLocale; |
1861 LocaleExtensions otherExt = ((Locale)obj)._extensions; |
1900 if (!baseLocale.equals(otherBase)) { |
1862 return _baseLocale.equals(otherBase) && _extensions.equals(otherExt); |
1901 return false; |
|
1902 } |
|
1903 if (localeExtensions == null) { |
|
1904 return ((Locale)obj).localeExtensions == null; |
|
1905 } |
|
1906 return localeExtensions.equals(((Locale)obj).localeExtensions); |
1863 } |
1907 } |
1864 |
1908 |
1865 // ================= privates ===================================== |
1909 // ================= privates ===================================== |
1866 |
1910 |
1867 private transient BaseLocale _baseLocale; |
1911 private transient BaseLocale baseLocale; |
1868 private transient LocaleExtensions _extensions; |
1912 private transient LocaleExtensions localeExtensions; |
1869 |
1913 |
1870 /** |
1914 /** |
1871 * Calculated hashcode |
1915 * Calculated hashcode |
1872 */ |
1916 */ |
1873 private transient volatile int hashCodeValue = 0; |
1917 private transient volatile int hashCodeValue = 0; |
1881 * @param bundle the ResourceBundle to use to get the display names |
1925 * @param bundle the ResourceBundle to use to get the display names |
1882 * @return an array of display names, possible of zero length. |
1926 * @return an array of display names, possible of zero length. |
1883 */ |
1927 */ |
1884 private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) { |
1928 private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) { |
1885 // Split the variant name into tokens separated by '_'. |
1929 // Split the variant name into tokens separated by '_'. |
1886 StringTokenizer tokenizer = new StringTokenizer(_baseLocale.getVariant(), "_"); |
1930 StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_"); |
1887 String[] names = new String[tokenizer.countTokens()]; |
1931 String[] names = new String[tokenizer.countTokens()]; |
1888 |
1932 |
1889 // For each variant token, lookup the display name. If |
1933 // For each variant token, lookup the display name. If |
1890 // not found, use the variant name itself. |
1934 // not found, use the variant name itself. |
1891 for (int i=0; i<names.length; ++i) { |
1935 for (int i=0; i<names.length; ++i) { |
1994 * @throws IOException |
2038 * @throws IOException |
1995 * @since 1.7 |
2039 * @since 1.7 |
1996 */ |
2040 */ |
1997 private void writeObject(ObjectOutputStream out) throws IOException { |
2041 private void writeObject(ObjectOutputStream out) throws IOException { |
1998 ObjectOutputStream.PutField fields = out.putFields(); |
2042 ObjectOutputStream.PutField fields = out.putFields(); |
1999 fields.put("language", _baseLocale.getLanguage()); |
2043 fields.put("language", baseLocale.getLanguage()); |
2000 fields.put("script", _baseLocale.getScript()); |
2044 fields.put("script", baseLocale.getScript()); |
2001 fields.put("country", _baseLocale.getRegion()); |
2045 fields.put("country", baseLocale.getRegion()); |
2002 fields.put("variant", _baseLocale.getVariant()); |
2046 fields.put("variant", baseLocale.getVariant()); |
2003 fields.put("extensions", _extensions.getID()); |
2047 fields.put("extensions", localeExtensions == null ? "" : localeExtensions.getID()); |
2004 fields.put("hashcode", -1); // place holder just for backward support |
2048 fields.put("hashcode", -1); // place holder just for backward support |
2005 out.writeFields(); |
2049 out.writeFields(); |
2006 } |
2050 } |
2007 |
2051 |
2008 /** |
2052 /** |
2018 String language = (String)fields.get("language", ""); |
2062 String language = (String)fields.get("language", ""); |
2019 String script = (String)fields.get("script", ""); |
2063 String script = (String)fields.get("script", ""); |
2020 String country = (String)fields.get("country", ""); |
2064 String country = (String)fields.get("country", ""); |
2021 String variant = (String)fields.get("variant", ""); |
2065 String variant = (String)fields.get("variant", ""); |
2022 String extStr = (String)fields.get("extensions", ""); |
2066 String extStr = (String)fields.get("extensions", ""); |
2023 _baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant); |
2067 baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant); |
2024 try { |
2068 if (extStr.length() > 0) { |
2025 InternalLocaleBuilder bldr = new InternalLocaleBuilder(); |
2069 try { |
2026 bldr.setExtensions(extStr); |
2070 InternalLocaleBuilder bldr = new InternalLocaleBuilder(); |
2027 _extensions = bldr.getLocaleExtensions(); |
2071 bldr.setExtensions(extStr); |
2028 } catch (LocaleSyntaxException e) { |
2072 localeExtensions = bldr.getLocaleExtensions(); |
2029 throw new IllformedLocaleException(e.getMessage()); |
2073 } catch (LocaleSyntaxException e) { |
|
2074 throw new IllformedLocaleException(e.getMessage()); |
|
2075 } |
|
2076 } else { |
|
2077 localeExtensions = null; |
2030 } |
2078 } |
2031 } |
2079 } |
2032 |
2080 |
2033 /** |
2081 /** |
2034 * Returns a cached <code>Locale</code> instance equivalent to |
2082 * Returns a cached <code>Locale</code> instance equivalent to |
2043 * @return an instance of <code>Locale</code> equivalent to |
2091 * @return an instance of <code>Locale</code> equivalent to |
2044 * the deserialized <code>Locale</code>. |
2092 * the deserialized <code>Locale</code>. |
2045 * @throws java.io.ObjectStreamException |
2093 * @throws java.io.ObjectStreamException |
2046 */ |
2094 */ |
2047 private Object readResolve() throws java.io.ObjectStreamException { |
2095 private Object readResolve() throws java.io.ObjectStreamException { |
2048 return getInstance(_baseLocale.getLanguage(), _baseLocale.getScript(), |
2096 return getInstance(baseLocale.getLanguage(), baseLocale.getScript(), |
2049 _baseLocale.getRegion(), _baseLocale.getVariant(), _extensions); |
2097 baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions); |
2050 } |
2098 } |
2051 |
2099 |
2052 private static volatile String[] isoLanguages = null; |
2100 private static volatile String[] isoLanguages = null; |
2053 |
2101 |
2054 private static volatile String[] isoCountries = null; |
2102 private static volatile String[] isoCountries = null; |
2055 |
2103 |
2056 private static String convertOldISOCodes(String language) { |
2104 private static String convertOldISOCodes(String language) { |
2057 // we accept both the old and the new ISO codes for the languages whose ISO |
2105 // we accept both the old and the new ISO codes for the languages whose ISO |
2058 // codes have changed, but we always store the OLD code, for backward compatibility |
2106 // codes have changed, but we always store the OLD code, for backward compatibility |
2059 language = AsciiUtil.toLowerString(language).intern(); |
2107 language = LocaleUtils.toLowerString(language).intern(); |
2060 if (language == "he") { |
2108 if (language == "he") { |
2061 return "iw"; |
2109 return "iw"; |
2062 } else if (language == "yi") { |
2110 } else if (language == "yi") { |
2063 return "ji"; |
2111 return "ji"; |
2064 } else if (language == "id") { |
2112 } else if (language == "id") { |
2066 } else { |
2114 } else { |
2067 return language; |
2115 return language; |
2068 } |
2116 } |
2069 } |
2117 } |
2070 |
2118 |
2071 private static LocaleExtensions getCompatibilityExtensions(String language, String script, String country, String variant) { |
2119 private static LocaleExtensions getCompatibilityExtensions(String language, |
2072 LocaleExtensions extensions = LocaleExtensions.EMPTY_EXTENSIONS; |
2120 String script, |
|
2121 String country, |
|
2122 String variant) { |
|
2123 LocaleExtensions extensions = null; |
2073 // Special cases for backward compatibility support |
2124 // Special cases for backward compatibility support |
2074 if (AsciiUtil.caseIgnoreMatch(language, "ja") |
2125 if (LocaleUtils.caseIgnoreMatch(language, "ja") |
2075 && script.length() == 0 |
2126 && script.length() == 0 |
2076 && AsciiUtil.caseIgnoreMatch(country, "JP") |
2127 && LocaleUtils.caseIgnoreMatch(country, "jp") |
2077 && AsciiUtil.caseIgnoreMatch(variant, "JP")) { |
2128 && "JP".equals(variant)) { |
2078 // ja_JP_JP -> u-ca-japanese (calendar = japanese) |
2129 // ja_JP_JP -> u-ca-japanese (calendar = japanese) |
2079 extensions = LocaleExtensions.CALENDAR_JAPANESE; |
2130 extensions = LocaleExtensions.CALENDAR_JAPANESE; |
2080 } else if (AsciiUtil.caseIgnoreMatch(language, "th") |
2131 } else if (LocaleUtils.caseIgnoreMatch(language, "th") |
2081 && script.length() == 0 |
2132 && script.length() == 0 |
2082 && AsciiUtil.caseIgnoreMatch(country, "TH") |
2133 && LocaleUtils.caseIgnoreMatch(country, "th") |
2083 && AsciiUtil.caseIgnoreMatch(variant, "TH")) { |
2134 && "TH".equals(variant)) { |
2084 // th_TH_TH -> u-nu-thai (numbersystem = thai) |
2135 // th_TH_TH -> u-nu-thai (numbersystem = thai) |
2085 extensions = LocaleExtensions.NUMBER_THAI; |
2136 extensions = LocaleExtensions.NUMBER_THAI; |
2086 } |
2137 } |
2087 return extensions; |
2138 return extensions; |
2088 } |
2139 } |
2194 * |
2245 * |
2195 * @see Locale#forLanguageTag |
2246 * @see Locale#forLanguageTag |
2196 * @since 1.7 |
2247 * @since 1.7 |
2197 */ |
2248 */ |
2198 public static final class Builder { |
2249 public static final class Builder { |
2199 private InternalLocaleBuilder _locbld; |
2250 private final InternalLocaleBuilder localeBuilder; |
2200 |
2251 |
2201 /** |
2252 /** |
2202 * Constructs an empty Builder. The default value of all |
2253 * Constructs an empty Builder. The default value of all |
2203 * fields, extensions, and private use information is the |
2254 * fields, extensions, and private use information is the |
2204 * empty string. |
2255 * empty string. |
2205 */ |
2256 */ |
2206 public Builder() { |
2257 public Builder() { |
2207 _locbld = new InternalLocaleBuilder(); |
2258 localeBuilder = new InternalLocaleBuilder(); |
2208 } |
2259 } |
2209 |
2260 |
2210 /** |
2261 /** |
2211 * Resets the <code>Builder</code> to match the provided |
2262 * Resets the <code>Builder</code> to match the provided |
2212 * <code>locale</code>. Existing state is discarded. |
2263 * <code>locale</code>. Existing state is discarded. |
2496 * {@link #setLanguageTag}.) |
2546 * {@link #setLanguageTag}.) |
2497 * |
2547 * |
2498 * @return A Locale. |
2548 * @return A Locale. |
2499 */ |
2549 */ |
2500 public Locale build() { |
2550 public Locale build() { |
2501 BaseLocale baseloc = _locbld.getBaseLocale(); |
2551 BaseLocale baseloc = localeBuilder.getBaseLocale(); |
2502 LocaleExtensions extensions = _locbld.getLocaleExtensions(); |
2552 LocaleExtensions extensions = localeBuilder.getLocaleExtensions(); |
2503 if (extensions.isEmpty() && baseloc.getVariant().length() > 0) { |
2553 if (extensions == null && baseloc.getVariant().length() > 0) { |
2504 extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(), |
2554 extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(), |
2505 baseloc.getRegion(), baseloc.getVariant()); |
2555 baseloc.getRegion(), baseloc.getVariant()); |
2506 } |
2556 } |
2507 return Locale.getInstance(baseloc, extensions); |
2557 return Locale.getInstance(baseloc, extensions); |
2508 } |
2558 } |