1.1 --- a/rt/emul/compact/src/main/java/java/util/Locale.java Sat Sep 28 02:18:42 2013 +0200
1.2 +++ b/rt/emul/compact/src/main/java/java/util/Locale.java Sat Sep 28 02:45:17 2013 +0200
1.3 @@ -45,23 +45,6 @@
1.4 import java.io.ObjectOutputStream;
1.5 import java.io.ObjectStreamField;
1.6 import java.io.Serializable;
1.7 -import java.security.AccessController;
1.8 -import java.text.MessageFormat;
1.9 -import java.util.spi.LocaleNameProvider;
1.10 -
1.11 -import sun.security.action.GetPropertyAction;
1.12 -import sun.util.LocaleServiceProviderPool;
1.13 -import sun.util.locale.BaseLocale;
1.14 -import sun.util.locale.InternalLocaleBuilder;
1.15 -import sun.util.locale.LanguageTag;
1.16 -import sun.util.locale.LocaleExtensions;
1.17 -import sun.util.locale.LocaleObjectCache;
1.18 -import sun.util.locale.LocaleSyntaxException;
1.19 -import sun.util.locale.LocaleUtils;
1.20 -import sun.util.locale.ParseStatus;
1.21 -import sun.util.locale.UnicodeLocaleExtension;
1.22 -import sun.util.resources.LocaleData;
1.23 -import sun.util.resources.OpenListResourceBundle;
1.24
1.25 /**
1.26 * A <code>Locale</code> object represents a specific geographical, political,
1.27 @@ -408,8 +391,6 @@
1.28 */
1.29 public final class Locale implements Cloneable, Serializable {
1.30
1.31 - static private final Cache LOCALECACHE = new Cache();
1.32 -
1.33 /** Useful constant for language.
1.34 */
1.35 static public final Locale ENGLISH = createConstant("en", "");
1.36 @@ -533,14 +514,10 @@
1.37 private static final int DISPLAY_COUNTRY = 1;
1.38 private static final int DISPLAY_VARIANT = 2;
1.39 private static final int DISPLAY_SCRIPT = 3;
1.40 + private String language;
1.41 + private String country;
1.42 + private String variant;
1.43
1.44 - /**
1.45 - * Private constructor used by getInstance method
1.46 - */
1.47 - private Locale(BaseLocale baseLocale, LocaleExtensions extensions) {
1.48 - this.baseLocale = baseLocale;
1.49 - this.localeExtensions = extensions;
1.50 - }
1.51
1.52 /**
1.53 * Construct a locale from language, country and variant.
1.54 @@ -572,8 +549,9 @@
1.55 if (language== null || country == null || variant == null) {
1.56 throw new NullPointerException();
1.57 }
1.58 - baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant);
1.59 - localeExtensions = getCompatibilityExtensions(language, "", country, variant);
1.60 + this.language = language;
1.61 + this.country = country;
1.62 + this.variant = variant;
1.63 }
1.64
1.65 /**
1.66 @@ -631,96 +609,7 @@
1.67 * constants due to making shortcuts.
1.68 */
1.69 private static Locale createConstant(String lang, String country) {
1.70 - BaseLocale base = BaseLocale.createInstance(lang, country);
1.71 - return getInstance(base, null);
1.72 - }
1.73 -
1.74 - /**
1.75 - * Returns a <code>Locale</code> constructed from the given
1.76 - * <code>language</code>, <code>country</code> and
1.77 - * <code>variant</code>. If the same <code>Locale</code> instance
1.78 - * is available in the cache, then that instance is
1.79 - * returned. Otherwise, a new <code>Locale</code> instance is
1.80 - * created and cached.
1.81 - *
1.82 - * @param language lowercase 2 to 8 language code.
1.83 - * @param country uppercase two-letter ISO-3166 code and numric-3 UN M.49 area code.
1.84 - * @param variant vendor and browser specific code. See class description.
1.85 - * @return the <code>Locale</code> instance requested
1.86 - * @exception NullPointerException if any argument is null.
1.87 - */
1.88 - static Locale getInstance(String language, String country, String variant) {
1.89 - return getInstance(language, "", country, variant, null);
1.90 - }
1.91 -
1.92 - static Locale getInstance(String language, String script, String country,
1.93 - String variant, LocaleExtensions extensions) {
1.94 - if (language== null || script == null || country == null || variant == null) {
1.95 - throw new NullPointerException();
1.96 - }
1.97 -
1.98 - if (extensions == null) {
1.99 - extensions = getCompatibilityExtensions(language, script, country, variant);
1.100 - }
1.101 -
1.102 - BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant);
1.103 - return getInstance(baseloc, extensions);
1.104 - }
1.105 -
1.106 - static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) {
1.107 - LocaleKey key = new LocaleKey(baseloc, extensions);
1.108 - return LOCALECACHE.get(key);
1.109 - }
1.110 -
1.111 - private static class Cache extends LocaleObjectCache<LocaleKey, Locale> {
1.112 - private Cache() {
1.113 - }
1.114 -
1.115 - @Override
1.116 - protected Locale createObject(LocaleKey key) {
1.117 - return new Locale(key.base, key.exts);
1.118 - }
1.119 - }
1.120 -
1.121 - private static final class LocaleKey {
1.122 - private final BaseLocale base;
1.123 - private final LocaleExtensions exts;
1.124 - private final int hash;
1.125 -
1.126 - private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) {
1.127 - base = baseLocale;
1.128 - exts = extensions;
1.129 -
1.130 - // Calculate the hash value here because it's always used.
1.131 - int h = base.hashCode();
1.132 - if (exts != null) {
1.133 - h ^= exts.hashCode();
1.134 - }
1.135 - hash = h;
1.136 - }
1.137 -
1.138 - @Override
1.139 - public boolean equals(Object obj) {
1.140 - if (this == obj) {
1.141 - return true;
1.142 - }
1.143 - if (!(obj instanceof LocaleKey)) {
1.144 - return false;
1.145 - }
1.146 - LocaleKey other = (LocaleKey)obj;
1.147 - if (hash != other.hash || !base.equals(other.base)) {
1.148 - return false;
1.149 - }
1.150 - if (exts == null) {
1.151 - return other.exts == null;
1.152 - }
1.153 - return exts.equals(other.exts);
1.154 - }
1.155 -
1.156 - @Override
1.157 - public int hashCode() {
1.158 - return hash;
1.159 - }
1.160 + return new Locale(lang, country);
1.161 }
1.162
1.163 /**
1.164 @@ -736,104 +625,7 @@
1.165 * @return the default locale for this instance of the Java Virtual Machine
1.166 */
1.167 public static Locale getDefault() {
1.168 - // do not synchronize this method - see 4071298
1.169 - // it's OK if more than one default locale happens to be created
1.170 - if (defaultLocale == null) {
1.171 - initDefault();
1.172 - }
1.173 - return defaultLocale;
1.174 - }
1.175 -
1.176 - /**
1.177 - * Gets the current value of the default locale for the specified Category
1.178 - * for this instance of the Java Virtual Machine.
1.179 - * <p>
1.180 - * The Java Virtual Machine sets the default locale during startup based
1.181 - * on the host environment. It is used by many locale-sensitive methods
1.182 - * if no locale is explicitly specified. It can be changed using the
1.183 - * setDefault(Locale.Category, Locale) method.
1.184 - *
1.185 - * @param category - the specified category to get the default locale
1.186 - * @throws NullPointerException - if category is null
1.187 - * @return the default locale for the specified Category for this instance
1.188 - * of the Java Virtual Machine
1.189 - * @see #setDefault(Locale.Category, Locale)
1.190 - * @since 1.7
1.191 - */
1.192 - public static Locale getDefault(Locale.Category category) {
1.193 - // do not synchronize this method - see 4071298
1.194 - // it's OK if more than one default locale happens to be created
1.195 - switch (category) {
1.196 - case DISPLAY:
1.197 - if (defaultDisplayLocale == null) {
1.198 - initDefault(category);
1.199 - }
1.200 - return defaultDisplayLocale;
1.201 - case FORMAT:
1.202 - if (defaultFormatLocale == null) {
1.203 - initDefault(category);
1.204 - }
1.205 - return defaultFormatLocale;
1.206 - default:
1.207 - assert false: "Unknown Category";
1.208 - }
1.209 - return getDefault();
1.210 - }
1.211 -
1.212 - private static void initDefault() {
1.213 - String language, region, script, country, variant;
1.214 - language = AccessController.doPrivileged(
1.215 - new GetPropertyAction("user.language", "en"));
1.216 - // for compatibility, check for old user.region property
1.217 - region = AccessController.doPrivileged(
1.218 - new GetPropertyAction("user.region"));
1.219 - if (region != null) {
1.220 - // region can be of form country, country_variant, or _variant
1.221 - int i = region.indexOf('_');
1.222 - if (i >= 0) {
1.223 - country = region.substring(0, i);
1.224 - variant = region.substring(i + 1);
1.225 - } else {
1.226 - country = region;
1.227 - variant = "";
1.228 - }
1.229 - script = "";
1.230 - } else {
1.231 - script = AccessController.doPrivileged(
1.232 - new GetPropertyAction("user.script", ""));
1.233 - country = AccessController.doPrivileged(
1.234 - new GetPropertyAction("user.country", ""));
1.235 - variant = AccessController.doPrivileged(
1.236 - new GetPropertyAction("user.variant", ""));
1.237 - }
1.238 - defaultLocale = getInstance(language, script, country, variant, null);
1.239 - }
1.240 -
1.241 - private static void initDefault(Locale.Category category) {
1.242 - // make sure defaultLocale is initialized
1.243 - if (defaultLocale == null) {
1.244 - initDefault();
1.245 - }
1.246 -
1.247 - Locale defaultCategoryLocale = getInstance(
1.248 - AccessController.doPrivileged(
1.249 - new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())),
1.250 - AccessController.doPrivileged(
1.251 - new GetPropertyAction(category.scriptKey, defaultLocale.getScript())),
1.252 - AccessController.doPrivileged(
1.253 - new GetPropertyAction(category.countryKey, defaultLocale.getCountry())),
1.254 - AccessController.doPrivileged(
1.255 - new GetPropertyAction(category.variantKey, defaultLocale.getVariant())),
1.256 - null);
1.257 -
1.258 - switch (category) {
1.259 - case DISPLAY:
1.260 - defaultDisplayLocale = defaultCategoryLocale;
1.261 - break;
1.262 - case FORMAT:
1.263 - defaultFormatLocale = defaultCategoryLocale;
1.264 - break;
1.265 - }
1.266 + return Locale.US;
1.267 }
1.268
1.269 /**
1.270 @@ -864,60 +656,8 @@
1.271 * @see SecurityManager#checkPermission
1.272 * @see java.util.PropertyPermission
1.273 */
1.274 - public static synchronized void setDefault(Locale newLocale) {
1.275 - setDefault(Category.DISPLAY, newLocale);
1.276 - setDefault(Category.FORMAT, newLocale);
1.277 - defaultLocale = newLocale;
1.278 - }
1.279 -
1.280 - /**
1.281 - * Sets the default locale for the specified Category for this instance
1.282 - * of the Java Virtual Machine. This does not affect the host locale.
1.283 - * <p>
1.284 - * If there is a security manager, its checkPermission method is called
1.285 - * with a PropertyPermission("user.language", "write") permission before
1.286 - * the default locale is changed.
1.287 - * <p>
1.288 - * The Java Virtual Machine sets the default locale during startup based
1.289 - * on the host environment. It is used by many locale-sensitive methods
1.290 - * if no locale is explicitly specified.
1.291 - * <p>
1.292 - * Since changing the default locale may affect many different areas of
1.293 - * functionality, this method should only be used if the caller is
1.294 - * prepared to reinitialize locale-sensitive code running within the
1.295 - * same Java Virtual Machine.
1.296 - * <p>
1.297 - *
1.298 - * @param category - the specified category to set the default locale
1.299 - * @param newLocale - the new default locale
1.300 - * @throws SecurityException - if a security manager exists and its
1.301 - * checkPermission method doesn't allow the operation.
1.302 - * @throws NullPointerException - if category and/or newLocale is null
1.303 - * @see SecurityManager#checkPermission(java.security.Permission)
1.304 - * @see PropertyPermission
1.305 - * @see #getDefault(Locale.Category)
1.306 - * @since 1.7
1.307 - */
1.308 - public static synchronized void setDefault(Locale.Category category,
1.309 - Locale newLocale) {
1.310 - if (category == null)
1.311 - throw new NullPointerException("Category cannot be NULL");
1.312 - if (newLocale == null)
1.313 - throw new NullPointerException("Can't set default locale to NULL");
1.314 -
1.315 - SecurityManager sm = System.getSecurityManager();
1.316 - if (sm != null) sm.checkPermission(new PropertyPermission
1.317 - ("user.language", "write"));
1.318 - switch (category) {
1.319 - case DISPLAY:
1.320 - defaultDisplayLocale = newLocale;
1.321 - break;
1.322 - case FORMAT:
1.323 - defaultFormatLocale = newLocale;
1.324 - break;
1.325 - default:
1.326 - assert false: "Unknown Category";
1.327 - }
1.328 + public static void setDefault(Locale newLocale) {
1.329 + throw new SecurityException();
1.330 }
1.331
1.332 /**
1.333 @@ -931,57 +671,7 @@
1.334 * @return An array of installed locales.
1.335 */
1.336 public static Locale[] getAvailableLocales() {
1.337 - return LocaleServiceProviderPool.getAllAvailableLocales();
1.338 - }
1.339 -
1.340 - /**
1.341 - * Returns a list of all 2-letter country codes defined in ISO 3166.
1.342 - * Can be used to create Locales.
1.343 - * <p>
1.344 - * <b>Note:</b> The <code>Locale</code> class also supports other codes for
1.345 - * country (region), such as 3-letter numeric UN M.49 area codes.
1.346 - * Therefore, the list returned by this method does not contain ALL valid
1.347 - * codes that can be used to create Locales.
1.348 - */
1.349 - public static String[] getISOCountries() {
1.350 - if (isoCountries == null) {
1.351 - isoCountries = getISO2Table(LocaleISOData.isoCountryTable);
1.352 - }
1.353 - String[] result = new String[isoCountries.length];
1.354 - System.arraycopy(isoCountries, 0, result, 0, isoCountries.length);
1.355 - return result;
1.356 - }
1.357 -
1.358 - /**
1.359 - * Returns a list of all 2-letter language codes defined in ISO 639.
1.360 - * Can be used to create Locales.
1.361 - * <p>
1.362 - * <b>Note:</b>
1.363 - * <ul>
1.364 - * <li>ISO 639 is not a stable standard— some languages' codes have changed.
1.365 - * The list this function returns includes both the new and the old codes for the
1.366 - * languages whose codes have changed.
1.367 - * <li>The <code>Locale</code> class also supports language codes up to
1.368 - * 8 characters in length. Therefore, the list returned by this method does
1.369 - * not contain ALL valid codes that can be used to create Locales.
1.370 - * </ul>
1.371 - */
1.372 - public static String[] getISOLanguages() {
1.373 - if (isoLanguages == null) {
1.374 - isoLanguages = getISO2Table(LocaleISOData.isoLanguageTable);
1.375 - }
1.376 - String[] result = new String[isoLanguages.length];
1.377 - System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
1.378 - return result;
1.379 - }
1.380 -
1.381 - private static final String[] getISO2Table(String table) {
1.382 - int len = table.length() / 5;
1.383 - String[] isoTable = new String[len];
1.384 - for (int i = 0, j = 0; i < len; i++, j += 5) {
1.385 - isoTable[i] = table.substring(j, j + 2);
1.386 - }
1.387 - return isoTable;
1.388 + return new Locale[] { Locale.US };
1.389 }
1.390
1.391 /**
1.392 @@ -1004,7 +694,7 @@
1.393 * @see #getDisplayLanguage
1.394 */
1.395 public String getLanguage() {
1.396 - return baseLocale.getLanguage();
1.397 + return language;
1.398 }
1.399
1.400 /**
1.401 @@ -1018,7 +708,7 @@
1.402 * @since 1.7
1.403 */
1.404 public String getScript() {
1.405 - return baseLocale.getScript();
1.406 + return "";
1.407 }
1.408
1.409 /**
1.410 @@ -1030,7 +720,7 @@
1.411 * @see #getDisplayCountry
1.412 */
1.413 public String getCountry() {
1.414 - return baseLocale.getRegion();
1.415 + return country;
1.416 }
1.417
1.418 /**
1.419 @@ -1040,7 +730,11 @@
1.420 * @see #getDisplayVariant
1.421 */
1.422 public String getVariant() {
1.423 - return baseLocale.getVariant();
1.424 + return variant;
1.425 + }
1.426 +
1.427 + String getRegion() {
1.428 + return getCountry();
1.429 }
1.430
1.431 /**
1.432 @@ -1059,10 +753,7 @@
1.433 * @since 1.7
1.434 */
1.435 public String getExtension(char key) {
1.436 - if (!LocaleExtensions.isValidKey(key)) {
1.437 - throw new IllegalArgumentException("Ill-formed extension key: " + key);
1.438 - }
1.439 - return (localeExtensions == null) ? null : localeExtensions.getExtensionValue(key);
1.440 + return null;
1.441 }
1.442
1.443 /**
1.444 @@ -1075,10 +766,7 @@
1.445 * @since 1.7
1.446 */
1.447 public Set<Character> getExtensionKeys() {
1.448 - if (localeExtensions == null) {
1.449 - return Collections.emptySet();
1.450 - }
1.451 - return localeExtensions.getKeys();
1.452 + return Collections.emptySet();
1.453 }
1.454
1.455 /**
1.456 @@ -1090,10 +778,7 @@
1.457 * @since 1.7
1.458 */
1.459 public Set<String> getUnicodeLocaleAttributes() {
1.460 - if (localeExtensions == null) {
1.461 - return Collections.emptySet();
1.462 - }
1.463 - return localeExtensions.getUnicodeLocaleAttributes();
1.464 + return Collections.emptySet();
1.465 }
1.466
1.467 /**
1.468 @@ -1111,10 +796,7 @@
1.469 * @since 1.7
1.470 */
1.471 public String getUnicodeLocaleType(String key) {
1.472 - if (!UnicodeLocaleExtension.isKey(key)) {
1.473 - throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
1.474 - }
1.475 - return (localeExtensions == null) ? null : localeExtensions.getUnicodeLocaleType(key);
1.476 + return null;
1.477 }
1.478
1.479 /**
1.480 @@ -1126,32 +808,10 @@
1.481 * @since 1.7
1.482 */
1.483 public Set<String> getUnicodeLocaleKeys() {
1.484 - if (localeExtensions == null) {
1.485 - return Collections.emptySet();
1.486 - }
1.487 - return localeExtensions.getUnicodeLocaleKeys();
1.488 + return Collections.emptySet();
1.489 }
1.490
1.491 /**
1.492 - * Package locale method returning the Locale's BaseLocale,
1.493 - * used by ResourceBundle
1.494 - * @return base locale of this Locale
1.495 - */
1.496 - BaseLocale getBaseLocale() {
1.497 - return baseLocale;
1.498 - }
1.499 -
1.500 - /**
1.501 - * Package private method returning the Locale's LocaleExtensions,
1.502 - * used by ResourceBundle.
1.503 - * @return locale exnteions of this Locale,
1.504 - * or {@code null} if no extensions are defined
1.505 - */
1.506 - LocaleExtensions getLocaleExtensions() {
1.507 - return localeExtensions;
1.508 - }
1.509 -
1.510 - /**
1.511 * Returns a string representation of this <code>Locale</code>
1.512 * object, consisting of language, country, variant, script,
1.513 * and extensions as below:
1.514 @@ -1195,11 +855,12 @@
1.515 */
1.516 @Override
1.517 public final String toString() {
1.518 + Locale baseLocale = this;
1.519 boolean l = (baseLocale.getLanguage().length() != 0);
1.520 boolean s = (baseLocale.getScript().length() != 0);
1.521 boolean r = (baseLocale.getRegion().length() != 0);
1.522 boolean v = (baseLocale.getVariant().length() != 0);
1.523 - boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0);
1.524 + boolean e = false; //(localeExtensions != null && localeExtensions.getID().length() != 0);
1.525
1.526 StringBuilder result = new StringBuilder(baseLocale.getLanguage());
1.527 if (r || (l && (v || s || e))) {
1.528 @@ -1221,635 +882,13 @@
1.529 if (!s) {
1.530 result.append('#');
1.531 }
1.532 - result.append(localeExtensions.getID());
1.533 +// result.append(localeExtensions.getID());
1.534 }
1.535
1.536 return result.toString();
1.537 }
1.538
1.539 - /**
1.540 - * Returns a well-formed IETF BCP 47 language tag representing
1.541 - * this locale.
1.542 - *
1.543 - * <p>If this <code>Locale</code> has a language, country, or
1.544 - * variant that does not satisfy the IETF BCP 47 language tag
1.545 - * syntax requirements, this method handles these fields as
1.546 - * described below:
1.547 - *
1.548 - * <p><b>Language:</b> If language is empty, or not <a
1.549 - * href="#def_language" >well-formed</a> (for example "a" or
1.550 - * "e2"), it will be emitted as "und" (Undetermined).
1.551 - *
1.552 - * <p><b>Country:</b> If country is not <a
1.553 - * href="#def_region">well-formed</a> (for example "12" or "USA"),
1.554 - * it will be omitted.
1.555 - *
1.556 - * <p><b>Variant:</b> If variant <b>is</b> <a
1.557 - * href="#def_variant">well-formed</a>, each sub-segment
1.558 - * (delimited by '-' or '_') is emitted as a subtag. Otherwise:
1.559 - * <ul>
1.560 - *
1.561 - * <li>if all sub-segments match <code>[0-9a-zA-Z]{1,8}</code>
1.562 - * (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first
1.563 - * ill-formed sub-segment and all following will be appended to
1.564 - * the private use subtag. The first appended subtag will be
1.565 - * "lvariant", followed by the sub-segments in order, separated by
1.566 - * hyphen. For example, "x-lvariant-WIN",
1.567 - * "Oracle-x-lvariant-JDK-Standard-Edition".
1.568 - *
1.569 - * <li>if any sub-segment does not match
1.570 - * <code>[0-9a-zA-Z]{1,8}</code>, the variant will be truncated
1.571 - * and the problematic sub-segment and all following sub-segments
1.572 - * will be omitted. If the remainder is non-empty, it will be
1.573 - * emitted as a private use subtag as above (even if the remainder
1.574 - * turns out to be well-formed). For example,
1.575 - * "Solaris_isjustthecoolestthing" is emitted as
1.576 - * "x-lvariant-Solaris", not as "solaris".</li></ul>
1.577 - *
1.578 - * <p><b>Special Conversions:</b> Java supports some old locale
1.579 - * representations, including deprecated ISO language codes,
1.580 - * for compatibility. This method performs the following
1.581 - * conversions:
1.582 - * <ul>
1.583 - *
1.584 - * <li>Deprecated ISO language codes "iw", "ji", and "in" are
1.585 - * converted to "he", "yi", and "id", respectively.
1.586 - *
1.587 - * <li>A locale with language "no", country "NO", and variant
1.588 - * "NY", representing Norwegian Nynorsk (Norway), is converted
1.589 - * to a language tag "nn-NO".</li></ul>
1.590 - *
1.591 - * <p><b>Note:</b> Although the language tag created by this
1.592 - * method is well-formed (satisfies the syntax requirements
1.593 - * defined by the IETF BCP 47 specification), it is not
1.594 - * necessarily a valid BCP 47 language tag. For example,
1.595 - * <pre>
1.596 - * new Locale("xx", "YY").toLanguageTag();</pre>
1.597 - *
1.598 - * will return "xx-YY", but the language subtag "xx" and the
1.599 - * region subtag "YY" are invalid because they are not registered
1.600 - * in the IANA Language Subtag Registry.
1.601 - *
1.602 - * @return a BCP47 language tag representing the locale
1.603 - * @see #forLanguageTag(String)
1.604 - * @since 1.7
1.605 - */
1.606 - public String toLanguageTag() {
1.607 - LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
1.608 - StringBuilder buf = new StringBuilder();
1.609 -
1.610 - String subtag = tag.getLanguage();
1.611 - if (subtag.length() > 0) {
1.612 - buf.append(LanguageTag.canonicalizeLanguage(subtag));
1.613 - }
1.614 -
1.615 - subtag = tag.getScript();
1.616 - if (subtag.length() > 0) {
1.617 - buf.append(LanguageTag.SEP);
1.618 - buf.append(LanguageTag.canonicalizeScript(subtag));
1.619 - }
1.620 -
1.621 - subtag = tag.getRegion();
1.622 - if (subtag.length() > 0) {
1.623 - buf.append(LanguageTag.SEP);
1.624 - buf.append(LanguageTag.canonicalizeRegion(subtag));
1.625 - }
1.626 -
1.627 - List<String>subtags = tag.getVariants();
1.628 - for (String s : subtags) {
1.629 - buf.append(LanguageTag.SEP);
1.630 - // preserve casing
1.631 - buf.append(s);
1.632 - }
1.633 -
1.634 - subtags = tag.getExtensions();
1.635 - for (String s : subtags) {
1.636 - buf.append(LanguageTag.SEP);
1.637 - buf.append(LanguageTag.canonicalizeExtension(s));
1.638 - }
1.639 -
1.640 - subtag = tag.getPrivateuse();
1.641 - if (subtag.length() > 0) {
1.642 - if (buf.length() > 0) {
1.643 - buf.append(LanguageTag.SEP);
1.644 - }
1.645 - buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
1.646 - // preserve casing
1.647 - buf.append(subtag);
1.648 - }
1.649 -
1.650 - return buf.toString();
1.651 - }
1.652 -
1.653 - /**
1.654 - * Returns a locale for the specified IETF BCP 47 language tag string.
1.655 - *
1.656 - * <p>If the specified language tag contains any ill-formed subtags,
1.657 - * the first such subtag and all following subtags are ignored. Compare
1.658 - * to {@link Locale.Builder#setLanguageTag} which throws an exception
1.659 - * in this case.
1.660 - *
1.661 - * <p>The following <b>conversions</b> are performed:<ul>
1.662 - *
1.663 - * <li>The language code "und" is mapped to language "".
1.664 - *
1.665 - * <li>The language codes "he", "yi", and "id" are mapped to "iw",
1.666 - * "ji", and "in" respectively. (This is the same canonicalization
1.667 - * that's done in Locale's constructors.)
1.668 - *
1.669 - * <li>The portion of a private use subtag prefixed by "lvariant",
1.670 - * if any, is removed and appended to the variant field in the
1.671 - * result locale (without case normalization). If it is then
1.672 - * empty, the private use subtag is discarded:
1.673 - *
1.674 - * <pre>
1.675 - * Locale loc;
1.676 - * loc = Locale.forLanguageTag("en-US-x-lvariant-POSIX");
1.677 - * loc.getVariant(); // returns "POSIX"
1.678 - * loc.getExtension('x'); // returns null
1.679 - *
1.680 - * loc = Locale.forLanguageTag("de-POSIX-x-URP-lvariant-Abc-Def");
1.681 - * loc.getVariant(); // returns "POSIX_Abc_Def"
1.682 - * loc.getExtension('x'); // returns "urp"
1.683 - * </pre>
1.684 - *
1.685 - * <li>When the languageTag argument contains an extlang subtag,
1.686 - * the first such subtag is used as the language, and the primary
1.687 - * language subtag and other extlang subtags are ignored:
1.688 - *
1.689 - * <pre>
1.690 - * Locale.forLanguageTag("ar-aao").getLanguage(); // returns "aao"
1.691 - * Locale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US"
1.692 - * </pre>
1.693 - *
1.694 - * <li>Case is normalized except for variant tags, which are left
1.695 - * unchanged. Language is normalized to lower case, script to
1.696 - * title case, country to upper case, and extensions to lower
1.697 - * case.
1.698 - *
1.699 - * <li>If, after processing, the locale would exactly match either
1.700 - * ja_JP_JP or th_TH_TH with no extensions, the appropriate
1.701 - * extensions are added as though the constructor had been called:
1.702 - *
1.703 - * <pre>
1.704 - * Locale.forLanguageTag("ja-JP-x-lvariant-JP").toLanguageTag();
1.705 - * // returns "ja-JP-u-ca-japanese-x-lvariant-JP"
1.706 - * Locale.forLanguageTag("th-TH-x-lvariant-TH").toLanguageTag();
1.707 - * // returns "th-TH-u-nu-thai-x-lvariant-TH"
1.708 - * <pre></ul>
1.709 - *
1.710 - * <p>This implements the 'Language-Tag' production of BCP47, and
1.711 - * so supports grandfathered (regular and irregular) as well as
1.712 - * private use language tags. Stand alone private use tags are
1.713 - * represented as empty language and extension 'x-whatever',
1.714 - * and grandfathered tags are converted to their canonical replacements
1.715 - * where they exist.
1.716 - *
1.717 - * <p>Grandfathered tags with canonical replacements are as follows:
1.718 - *
1.719 - * <table>
1.720 - * <tbody align="center">
1.721 - * <tr><th>grandfathered tag</th><th> </th><th>modern replacement</th></tr>
1.722 - * <tr><td>art-lojban</td><td> </td><td>jbo</td></tr>
1.723 - * <tr><td>i-ami</td><td> </td><td>ami</td></tr>
1.724 - * <tr><td>i-bnn</td><td> </td><td>bnn</td></tr>
1.725 - * <tr><td>i-hak</td><td> </td><td>hak</td></tr>
1.726 - * <tr><td>i-klingon</td><td> </td><td>tlh</td></tr>
1.727 - * <tr><td>i-lux</td><td> </td><td>lb</td></tr>
1.728 - * <tr><td>i-navajo</td><td> </td><td>nv</td></tr>
1.729 - * <tr><td>i-pwn</td><td> </td><td>pwn</td></tr>
1.730 - * <tr><td>i-tao</td><td> </td><td>tao</td></tr>
1.731 - * <tr><td>i-tay</td><td> </td><td>tay</td></tr>
1.732 - * <tr><td>i-tsu</td><td> </td><td>tsu</td></tr>
1.733 - * <tr><td>no-bok</td><td> </td><td>nb</td></tr>
1.734 - * <tr><td>no-nyn</td><td> </td><td>nn</td></tr>
1.735 - * <tr><td>sgn-BE-FR</td><td> </td><td>sfb</td></tr>
1.736 - * <tr><td>sgn-BE-NL</td><td> </td><td>vgt</td></tr>
1.737 - * <tr><td>sgn-CH-DE</td><td> </td><td>sgg</td></tr>
1.738 - * <tr><td>zh-guoyu</td><td> </td><td>cmn</td></tr>
1.739 - * <tr><td>zh-hakka</td><td> </td><td>hak</td></tr>
1.740 - * <tr><td>zh-min-nan</td><td> </td><td>nan</td></tr>
1.741 - * <tr><td>zh-xiang</td><td> </td><td>hsn</td></tr>
1.742 - * </tbody>
1.743 - * </table>
1.744 - *
1.745 - * <p>Grandfathered tags with no modern replacement will be
1.746 - * converted as follows:
1.747 - *
1.748 - * <table>
1.749 - * <tbody align="center">
1.750 - * <tr><th>grandfathered tag</th><th> </th><th>converts to</th></tr>
1.751 - * <tr><td>cel-gaulish</td><td> </td><td>xtg-x-cel-gaulish</td></tr>
1.752 - * <tr><td>en-GB-oed</td><td> </td><td>en-GB-x-oed</td></tr>
1.753 - * <tr><td>i-default</td><td> </td><td>en-x-i-default</td></tr>
1.754 - * <tr><td>i-enochian</td><td> </td><td>und-x-i-enochian</td></tr>
1.755 - * <tr><td>i-mingo</td><td> </td><td>see-x-i-mingo</td></tr>
1.756 - * <tr><td>zh-min</td><td> </td><td>nan-x-zh-min</td></tr>
1.757 - * </tbody>
1.758 - * </table>
1.759 - *
1.760 - * <p>For a list of all grandfathered tags, see the
1.761 - * IANA Language Subtag Registry (search for "Type: grandfathered").
1.762 - *
1.763 - * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>
1.764 - * and <code>forLanguageTag</code> will round-trip.
1.765 - *
1.766 - * @param languageTag the language tag
1.767 - * @return The locale that best represents the language tag.
1.768 - * @throws NullPointerException if <code>languageTag</code> is <code>null</code>
1.769 - * @see #toLanguageTag()
1.770 - * @see java.util.Locale.Builder#setLanguageTag(String)
1.771 - * @since 1.7
1.772 - */
1.773 - public static Locale forLanguageTag(String languageTag) {
1.774 - LanguageTag tag = LanguageTag.parse(languageTag, null);
1.775 - InternalLocaleBuilder bldr = new InternalLocaleBuilder();
1.776 - bldr.setLanguageTag(tag);
1.777 - BaseLocale base = bldr.getBaseLocale();
1.778 - LocaleExtensions exts = bldr.getLocaleExtensions();
1.779 - if (exts == null && base.getVariant().length() > 0) {
1.780 - exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
1.781 - base.getRegion(), base.getVariant());
1.782 - }
1.783 - return getInstance(base, exts);
1.784 - }
1.785 -
1.786 - /**
1.787 - * Returns a three-letter abbreviation of this locale's language.
1.788 - * If the language matches an ISO 639-1 two-letter code, the
1.789 - * corresponding ISO 639-2/T three-letter lowercase code is
1.790 - * returned. The ISO 639-2 language codes can be found on-line,
1.791 - * see "Codes for the Representation of Names of Languages Part 2:
1.792 - * Alpha-3 Code". If the locale specifies a three-letter
1.793 - * language, the language is returned as is. If the locale does
1.794 - * not specify a language the empty string is returned.
1.795 - *
1.796 - * @return A three-letter abbreviation of this locale's language.
1.797 - * @exception MissingResourceException Throws MissingResourceException if
1.798 - * three-letter language abbreviation is not available for this locale.
1.799 - */
1.800 - public String getISO3Language() throws MissingResourceException {
1.801 - String lang = baseLocale.getLanguage();
1.802 - if (lang.length() == 3) {
1.803 - return lang;
1.804 - }
1.805 -
1.806 - String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
1.807 - if (language3 == null) {
1.808 - throw new MissingResourceException("Couldn't find 3-letter language code for "
1.809 - + lang, "FormatData_" + toString(), "ShortLanguage");
1.810 - }
1.811 - return language3;
1.812 - }
1.813 -
1.814 - /**
1.815 - * Returns a three-letter abbreviation for this locale's country.
1.816 - * If the country matches an ISO 3166-1 alpha-2 code, the
1.817 - * corresponding ISO 3166-1 alpha-3 uppercase code is returned.
1.818 - * If the locale doesn't specify a country, this will be the empty
1.819 - * string.
1.820 - *
1.821 - * <p>The ISO 3166-1 codes can be found on-line.
1.822 - *
1.823 - * @return A three-letter abbreviation of this locale's country.
1.824 - * @exception MissingResourceException Throws MissingResourceException if the
1.825 - * three-letter country abbreviation is not available for this locale.
1.826 - */
1.827 - public String getISO3Country() throws MissingResourceException {
1.828 - String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
1.829 - if (country3 == null) {
1.830 - throw new MissingResourceException("Couldn't find 3-letter country code for "
1.831 - + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
1.832 - }
1.833 - return country3;
1.834 - }
1.835 -
1.836 - private static final String getISO3Code(String iso2Code, String table) {
1.837 - int codeLength = iso2Code.length();
1.838 - if (codeLength == 0) {
1.839 - return "";
1.840 - }
1.841 -
1.842 - int tableLength = table.length();
1.843 - int index = tableLength;
1.844 - if (codeLength == 2) {
1.845 - char c1 = iso2Code.charAt(0);
1.846 - char c2 = iso2Code.charAt(1);
1.847 - for (index = 0; index < tableLength; index += 5) {
1.848 - if (table.charAt(index) == c1
1.849 - && table.charAt(index + 1) == c2) {
1.850 - break;
1.851 - }
1.852 - }
1.853 - }
1.854 - return index < tableLength ? table.substring(index + 2, index + 5) : null;
1.855 - }
1.856 -
1.857 - /**
1.858 - * Returns a name for the locale's language that is appropriate for display to the
1.859 - * user.
1.860 - * If possible, the name returned will be localized for the default locale.
1.861 - * For example, if the locale is fr_FR and the default locale
1.862 - * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
1.863 - * the default locale is fr_FR, getDisplayLanguage() will return "anglais".
1.864 - * If the name returned cannot be localized for the default locale,
1.865 - * (say, we don't have a Japanese name for Croatian),
1.866 - * this function falls back on the English name, and uses the ISO code as a last-resort
1.867 - * value. If the locale doesn't specify a language, this function returns the empty string.
1.868 - */
1.869 - public final String getDisplayLanguage() {
1.870 - return getDisplayLanguage(getDefault(Category.DISPLAY));
1.871 - }
1.872 -
1.873 - /**
1.874 - * Returns a name for the locale's language that is appropriate for display to the
1.875 - * user.
1.876 - * If possible, the name returned will be localized according to inLocale.
1.877 - * For example, if the locale is fr_FR and inLocale
1.878 - * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
1.879 - * inLocale is fr_FR, getDisplayLanguage() will return "anglais".
1.880 - * If the name returned cannot be localized according to inLocale,
1.881 - * (say, we don't have a Japanese name for Croatian),
1.882 - * this function falls back on the English name, and finally
1.883 - * on the ISO code as a last-resort value. If the locale doesn't specify a language,
1.884 - * this function returns the empty string.
1.885 - *
1.886 - * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1.887 - */
1.888 - public String getDisplayLanguage(Locale inLocale) {
1.889 - return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE);
1.890 - }
1.891 -
1.892 - /**
1.893 - * Returns a name for the the locale's script that is appropriate for display to
1.894 - * the user. If possible, the name will be localized for the default locale. Returns
1.895 - * the empty string if this locale doesn't specify a script code.
1.896 - *
1.897 - * @return the display name of the script code for the current default locale
1.898 - * @since 1.7
1.899 - */
1.900 - public String getDisplayScript() {
1.901 - return getDisplayScript(getDefault());
1.902 - }
1.903 -
1.904 - /**
1.905 - * Returns a name for the locale's script that is appropriate
1.906 - * for display to the user. If possible, the name will be
1.907 - * localized for the given locale. Returns the empty string if
1.908 - * this locale doesn't specify a script code.
1.909 - *
1.910 - * @return the display name of the script code for the current default locale
1.911 - * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1.912 - * @since 1.7
1.913 - */
1.914 - public String getDisplayScript(Locale inLocale) {
1.915 - return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT);
1.916 - }
1.917 -
1.918 - /**
1.919 - * Returns a name for the locale's country that is appropriate for display to the
1.920 - * user.
1.921 - * If possible, the name returned will be localized for the default locale.
1.922 - * For example, if the locale is fr_FR and the default locale
1.923 - * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
1.924 - * the default locale is fr_FR, getDisplayCountry() will return "Etats-Unis".
1.925 - * If the name returned cannot be localized for the default locale,
1.926 - * (say, we don't have a Japanese name for Croatia),
1.927 - * this function falls back on the English name, and uses the ISO code as a last-resort
1.928 - * value. If the locale doesn't specify a country, this function returns the empty string.
1.929 - */
1.930 - public final String getDisplayCountry() {
1.931 - return getDisplayCountry(getDefault(Category.DISPLAY));
1.932 - }
1.933 -
1.934 - /**
1.935 - * Returns a name for the locale's country that is appropriate for display to the
1.936 - * user.
1.937 - * If possible, the name returned will be localized according to inLocale.
1.938 - * For example, if the locale is fr_FR and inLocale
1.939 - * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
1.940 - * inLocale is fr_FR, getDisplayCountry() will return "Etats-Unis".
1.941 - * If the name returned cannot be localized according to inLocale.
1.942 - * (say, we don't have a Japanese name for Croatia),
1.943 - * this function falls back on the English name, and finally
1.944 - * on the ISO code as a last-resort value. If the locale doesn't specify a country,
1.945 - * this function returns the empty string.
1.946 - *
1.947 - * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1.948 - */
1.949 - public String getDisplayCountry(Locale inLocale) {
1.950 - return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY);
1.951 - }
1.952 -
1.953 - private String getDisplayString(String code, Locale inLocale, int type) {
1.954 - if (code.length() == 0) {
1.955 - return "";
1.956 - }
1.957 -
1.958 - if (inLocale == null) {
1.959 - throw new NullPointerException();
1.960 - }
1.961 -
1.962 - try {
1.963 - OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1.964 - String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
1.965 - String result = null;
1.966 -
1.967 - // Check whether a provider can provide an implementation that's closer
1.968 - // to the requested locale than what the Java runtime itself can provide.
1.969 - LocaleServiceProviderPool pool =
1.970 - LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
1.971 - if (pool.hasProviders()) {
1.972 - result = pool.getLocalizedObject(
1.973 - LocaleNameGetter.INSTANCE,
1.974 - inLocale, bundle, key,
1.975 - type, code);
1.976 - }
1.977 -
1.978 - if (result == null) {
1.979 - result = bundle.getString(key);
1.980 - }
1.981 -
1.982 - if (result != null) {
1.983 - return result;
1.984 - }
1.985 - }
1.986 - catch (Exception e) {
1.987 - // just fall through
1.988 - }
1.989 - return code;
1.990 - }
1.991 -
1.992 - /**
1.993 - * Returns a name for the locale's variant code that is appropriate for display to the
1.994 - * user. If possible, the name will be localized for the default locale. If the locale
1.995 - * doesn't specify a variant code, this function returns the empty string.
1.996 - */
1.997 - public final String getDisplayVariant() {
1.998 - return getDisplayVariant(getDefault(Category.DISPLAY));
1.999 - }
1.1000 -
1.1001 - /**
1.1002 - * Returns a name for the locale's variant code that is appropriate for display to the
1.1003 - * user. If possible, the name will be localized for inLocale. If the locale
1.1004 - * doesn't specify a variant code, this function returns the empty string.
1.1005 - *
1.1006 - * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1.1007 - */
1.1008 - public String getDisplayVariant(Locale inLocale) {
1.1009 - if (baseLocale.getVariant().length() == 0)
1.1010 - return "";
1.1011 -
1.1012 - OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1.1013 -
1.1014 - String names[] = getDisplayVariantArray(bundle, inLocale);
1.1015 -
1.1016 - // Get the localized patterns for formatting a list, and use
1.1017 - // them to format the list.
1.1018 - String listPattern = null;
1.1019 - String listCompositionPattern = null;
1.1020 - try {
1.1021 - listPattern = bundle.getString("ListPattern");
1.1022 - listCompositionPattern = bundle.getString("ListCompositionPattern");
1.1023 - } catch (MissingResourceException e) {
1.1024 - }
1.1025 - return formatList(names, listPattern, listCompositionPattern);
1.1026 - }
1.1027 -
1.1028 - /**
1.1029 - * Returns a name for the locale that is appropriate for display to the
1.1030 - * user. This will be the values returned by getDisplayLanguage(),
1.1031 - * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled
1.1032 - * into a single string. The the non-empty values are used in order,
1.1033 - * with the second and subsequent names in parentheses. For example:
1.1034 - * <blockquote>
1.1035 - * language (script, country, variant)<br>
1.1036 - * language (country)<br>
1.1037 - * language (variant)<br>
1.1038 - * script (country)<br>
1.1039 - * country<br>
1.1040 - * </blockquote>
1.1041 - * depending on which fields are specified in the locale. If the
1.1042 - * language, sacript, country, and variant fields are all empty,
1.1043 - * this function returns the empty string.
1.1044 - */
1.1045 - public final String getDisplayName() {
1.1046 - return getDisplayName(getDefault(Category.DISPLAY));
1.1047 - }
1.1048 -
1.1049 - /**
1.1050 - * Returns a name for the locale that is appropriate for display
1.1051 - * to the user. This will be the values returned by
1.1052 - * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(),
1.1053 - * and getDisplayVariant() assembled into a single string.
1.1054 - * The non-empty values are used in order,
1.1055 - * with the second and subsequent names in parentheses. For example:
1.1056 - * <blockquote>
1.1057 - * language (script, country, variant)<br>
1.1058 - * language (country)<br>
1.1059 - * language (variant)<br>
1.1060 - * script (country)<br>
1.1061 - * country<br>
1.1062 - * </blockquote>
1.1063 - * depending on which fields are specified in the locale. If the
1.1064 - * language, script, country, and variant fields are all empty,
1.1065 - * this function returns the empty string.
1.1066 - *
1.1067 - * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1.1068 - */
1.1069 - public String getDisplayName(Locale inLocale) {
1.1070 - OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1.1071 -
1.1072 - String languageName = getDisplayLanguage(inLocale);
1.1073 - String scriptName = getDisplayScript(inLocale);
1.1074 - String countryName = getDisplayCountry(inLocale);
1.1075 - String[] variantNames = getDisplayVariantArray(bundle, inLocale);
1.1076 -
1.1077 - // Get the localized patterns for formatting a display name.
1.1078 - String displayNamePattern = null;
1.1079 - String listPattern = null;
1.1080 - String listCompositionPattern = null;
1.1081 - try {
1.1082 - displayNamePattern = bundle.getString("DisplayNamePattern");
1.1083 - listPattern = bundle.getString("ListPattern");
1.1084 - listCompositionPattern = bundle.getString("ListCompositionPattern");
1.1085 - } catch (MissingResourceException e) {
1.1086 - }
1.1087 -
1.1088 - // The display name consists of a main name, followed by qualifiers.
1.1089 - // Typically, the format is "MainName (Qualifier, Qualifier)" but this
1.1090 - // depends on what pattern is stored in the display locale.
1.1091 - String mainName = null;
1.1092 - String[] qualifierNames = null;
1.1093 -
1.1094 - // The main name is the language, or if there is no language, the script,
1.1095 - // then if no script, the country. If there is no language/script/country
1.1096 - // (an anomalous situation) then the display name is simply the variant's
1.1097 - // display name.
1.1098 - if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
1.1099 - if (variantNames.length == 0) {
1.1100 - return "";
1.1101 - } else {
1.1102 - return formatList(variantNames, listPattern, listCompositionPattern);
1.1103 - }
1.1104 - }
1.1105 - ArrayList<String> names = new ArrayList<>(4);
1.1106 - if (languageName.length() != 0) {
1.1107 - names.add(languageName);
1.1108 - }
1.1109 - if (scriptName.length() != 0) {
1.1110 - names.add(scriptName);
1.1111 - }
1.1112 - if (countryName.length() != 0) {
1.1113 - names.add(countryName);
1.1114 - }
1.1115 - if (variantNames.length != 0) {
1.1116 - for (String var : variantNames) {
1.1117 - names.add(var);
1.1118 - }
1.1119 - }
1.1120 -
1.1121 - // The first one in the main name
1.1122 - mainName = names.get(0);
1.1123 -
1.1124 - // Others are qualifiers
1.1125 - int numNames = names.size();
1.1126 - qualifierNames = (numNames > 1) ?
1.1127 - names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
1.1128 -
1.1129 - // Create an array whose first element is the number of remaining
1.1130 - // elements. This serves as a selector into a ChoiceFormat pattern from
1.1131 - // the resource. The second and third elements are the main name and
1.1132 - // the qualifier; if there are no qualifiers, the third element is
1.1133 - // unused by the format pattern.
1.1134 - Object[] displayNames = {
1.1135 - new Integer(qualifierNames.length != 0 ? 2 : 1),
1.1136 - mainName,
1.1137 - // We could also just call formatList() and have it handle the empty
1.1138 - // list case, but this is more efficient, and we want it to be
1.1139 - // efficient since all the language-only locales will not have any
1.1140 - // qualifiers.
1.1141 - qualifierNames.length != 0 ? formatList(qualifierNames, listPattern, listCompositionPattern) : null
1.1142 - };
1.1143 -
1.1144 - if (displayNamePattern != null) {
1.1145 - return new MessageFormat(displayNamePattern).format(displayNames);
1.1146 - }
1.1147 - else {
1.1148 - // If we cannot get the message format pattern, then we use a simple
1.1149 - // hard-coded pattern. This should not occur in practice unless the
1.1150 - // installation is missing some core files (FormatData etc.).
1.1151 - StringBuilder result = new StringBuilder();
1.1152 - result.append((String)displayNames[1]);
1.1153 - if (displayNames.length > 2) {
1.1154 - result.append(" (");
1.1155 - result.append((String)displayNames[2]);
1.1156 - result.append(')');
1.1157 - }
1.1158 - return result.toString();
1.1159 - }
1.1160 - }
1.1161 -
1.1162 +
1.1163 /**
1.1164 * Overrides Cloneable.
1.1165 */
1.1166 @@ -1870,691 +909,34 @@
1.1167 */
1.1168 @Override
1.1169 public int hashCode() {
1.1170 - int hc = hashCodeValue;
1.1171 - if (hc == 0) {
1.1172 - hc = baseLocale.hashCode();
1.1173 - if (localeExtensions != null) {
1.1174 - hc ^= localeExtensions.hashCode();
1.1175 - }
1.1176 - hashCodeValue = hc;
1.1177 - }
1.1178 - return hc;
1.1179 + int hash = 3;
1.1180 + hash = 43 * hash + Objects.hashCode(this.language);
1.1181 + hash = 43 * hash + Objects.hashCode(this.country);
1.1182 + hash = 43 * hash + Objects.hashCode(this.variant);
1.1183 + return hash;
1.1184 }
1.1185
1.1186 // Overrides
1.1187 -
1.1188 - /**
1.1189 - * Returns true if this Locale is equal to another object. A Locale is
1.1190 - * deemed equal to another Locale with identical language, script, country,
1.1191 - * variant and extensions, and unequal to all other objects.
1.1192 - *
1.1193 - * @return true if this Locale is equal to the specified object.
1.1194 - */
1.1195 @Override
1.1196 public boolean equals(Object obj) {
1.1197 - if (this == obj) // quick check
1.1198 - return true;
1.1199 - if (!(obj instanceof Locale))
1.1200 - return false;
1.1201 - BaseLocale otherBase = ((Locale)obj).baseLocale;
1.1202 - if (!baseLocale.equals(otherBase)) {
1.1203 + if (obj == null) {
1.1204 return false;
1.1205 }
1.1206 - if (localeExtensions == null) {
1.1207 - return ((Locale)obj).localeExtensions == null;
1.1208 + if (getClass() != obj.getClass()) {
1.1209 + return false;
1.1210 }
1.1211 - return localeExtensions.equals(((Locale)obj).localeExtensions);
1.1212 + final Locale other = (Locale) obj;
1.1213 + if (!Objects.equals(this.language, other.language)) {
1.1214 + return false;
1.1215 + }
1.1216 + if (!Objects.equals(this.country, other.country)) {
1.1217 + return false;
1.1218 + }
1.1219 + if (!Objects.equals(this.variant, other.variant)) {
1.1220 + return false;
1.1221 + }
1.1222 + return true;
1.1223 }
1.1224
1.1225 - // ================= privates =====================================
1.1226
1.1227 - private transient BaseLocale baseLocale;
1.1228 - private transient LocaleExtensions localeExtensions;
1.1229 -
1.1230 - /**
1.1231 - * Calculated hashcode
1.1232 - */
1.1233 - private transient volatile int hashCodeValue = 0;
1.1234 -
1.1235 - private static Locale defaultLocale = null;
1.1236 - private static Locale defaultDisplayLocale = null;
1.1237 - private static Locale defaultFormatLocale = null;
1.1238 -
1.1239 - /**
1.1240 - * Return an array of the display names of the variant.
1.1241 - * @param bundle the ResourceBundle to use to get the display names
1.1242 - * @return an array of display names, possible of zero length.
1.1243 - */
1.1244 - private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) {
1.1245 - // Split the variant name into tokens separated by '_'.
1.1246 - StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
1.1247 - String[] names = new String[tokenizer.countTokens()];
1.1248 -
1.1249 - // For each variant token, lookup the display name. If
1.1250 - // not found, use the variant name itself.
1.1251 - for (int i=0; i<names.length; ++i) {
1.1252 - names[i] = getDisplayString(tokenizer.nextToken(),
1.1253 - inLocale, DISPLAY_VARIANT);
1.1254 - }
1.1255 -
1.1256 - return names;
1.1257 - }
1.1258 -
1.1259 - /**
1.1260 - * Format a list using given pattern strings.
1.1261 - * If either of the patterns is null, then a the list is
1.1262 - * formatted by concatenation with the delimiter ','.
1.1263 - * @param stringList the list of strings to be formatted.
1.1264 - * @param listPattern should create a MessageFormat taking 0-3 arguments
1.1265 - * and formatting them into a list.
1.1266 - * @param listCompositionPattern should take 2 arguments
1.1267 - * and is used by composeList.
1.1268 - * @return a string representing the list.
1.1269 - */
1.1270 - private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
1.1271 - // If we have no list patterns, compose the list in a simple,
1.1272 - // non-localized way.
1.1273 - if (listPattern == null || listCompositionPattern == null) {
1.1274 - StringBuffer result = new StringBuffer();
1.1275 - for (int i=0; i<stringList.length; ++i) {
1.1276 - if (i>0) result.append(',');
1.1277 - result.append(stringList[i]);
1.1278 - }
1.1279 - return result.toString();
1.1280 - }
1.1281 -
1.1282 - // Compose the list down to three elements if necessary
1.1283 - if (stringList.length > 3) {
1.1284 - MessageFormat format = new MessageFormat(listCompositionPattern);
1.1285 - stringList = composeList(format, stringList);
1.1286 - }
1.1287 -
1.1288 - // Rebuild the argument list with the list length as the first element
1.1289 - Object[] args = new Object[stringList.length + 1];
1.1290 - System.arraycopy(stringList, 0, args, 1, stringList.length);
1.1291 - args[0] = new Integer(stringList.length);
1.1292 -
1.1293 - // Format it using the pattern in the resource
1.1294 - MessageFormat format = new MessageFormat(listPattern);
1.1295 - return format.format(args);
1.1296 - }
1.1297 -
1.1298 - /**
1.1299 - * Given a list of strings, return a list shortened to three elements.
1.1300 - * Shorten it by applying the given format to the first two elements
1.1301 - * recursively.
1.1302 - * @param format a format which takes two arguments
1.1303 - * @param list a list of strings
1.1304 - * @return if the list is three elements or shorter, the same list;
1.1305 - * otherwise, a new list of three elements.
1.1306 - */
1.1307 - private static String[] composeList(MessageFormat format, String[] list) {
1.1308 - if (list.length <= 3) return list;
1.1309 -
1.1310 - // Use the given format to compose the first two elements into one
1.1311 - String[] listItems = { list[0], list[1] };
1.1312 - String newItem = format.format(listItems);
1.1313 -
1.1314 - // Form a new list one element shorter
1.1315 - String[] newList = new String[list.length-1];
1.1316 - System.arraycopy(list, 2, newList, 1, newList.length-1);
1.1317 - newList[0] = newItem;
1.1318 -
1.1319 - // Recurse
1.1320 - return composeList(format, newList);
1.1321 - }
1.1322 -
1.1323 - /**
1.1324 - * @serialField language String
1.1325 - * language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
1.1326 - * @serialField country String
1.1327 - * country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
1.1328 - * @serialField variant String
1.1329 - * variant subtags separated by LOWLINE characters. (See <a href="java/util/Locale.html#getVariant()">getVariant()</a>)
1.1330 - * @serialField hashcode int
1.1331 - * deprecated, for forward compatibility only
1.1332 - * @serialField script String
1.1333 - * script subtag in title case (See <a href="java/util/Locale.html#getScript()">getScript()</a>)
1.1334 - * @serialField extensions String
1.1335 - * canonical representation of extensions, that is,
1.1336 - * BCP47 extensions in alphabetical order followed by
1.1337 - * BCP47 private use subtags, all in lower case letters
1.1338 - * separated by HYPHEN-MINUS characters.
1.1339 - * (See <a href="java/util/Locale.html#getExtensionKeys()">getExtensionKeys()</a>,
1.1340 - * <a href="java/util/Locale.html#getExtension(char)">getExtension(char)</a>)
1.1341 - */
1.1342 - private static final ObjectStreamField[] serialPersistentFields = {
1.1343 - new ObjectStreamField("language", String.class),
1.1344 - new ObjectStreamField("country", String.class),
1.1345 - new ObjectStreamField("variant", String.class),
1.1346 - new ObjectStreamField("hashcode", int.class),
1.1347 - new ObjectStreamField("script", String.class),
1.1348 - new ObjectStreamField("extensions", String.class),
1.1349 - };
1.1350 -
1.1351 - /**
1.1352 - * Serializes this <code>Locale</code> to the specified <code>ObjectOutputStream</code>.
1.1353 - * @param out the <code>ObjectOutputStream</code> to write
1.1354 - * @throws IOException
1.1355 - * @since 1.7
1.1356 - */
1.1357 - private void writeObject(ObjectOutputStream out) throws IOException {
1.1358 - ObjectOutputStream.PutField fields = out.putFields();
1.1359 - fields.put("language", baseLocale.getLanguage());
1.1360 - fields.put("script", baseLocale.getScript());
1.1361 - fields.put("country", baseLocale.getRegion());
1.1362 - fields.put("variant", baseLocale.getVariant());
1.1363 - fields.put("extensions", localeExtensions == null ? "" : localeExtensions.getID());
1.1364 - fields.put("hashcode", -1); // place holder just for backward support
1.1365 - out.writeFields();
1.1366 - }
1.1367 -
1.1368 - /**
1.1369 - * Deserializes this <code>Locale</code>.
1.1370 - * @param in the <code>ObjectInputStream</code> to read
1.1371 - * @throws IOException
1.1372 - * @throws ClassNotFoundException
1.1373 - * @throws IllformdLocaleException
1.1374 - * @since 1.7
1.1375 - */
1.1376 - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1.1377 - ObjectInputStream.GetField fields = in.readFields();
1.1378 - String language = (String)fields.get("language", "");
1.1379 - String script = (String)fields.get("script", "");
1.1380 - String country = (String)fields.get("country", "");
1.1381 - String variant = (String)fields.get("variant", "");
1.1382 - String extStr = (String)fields.get("extensions", "");
1.1383 - baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
1.1384 - if (extStr.length() > 0) {
1.1385 - try {
1.1386 - InternalLocaleBuilder bldr = new InternalLocaleBuilder();
1.1387 - bldr.setExtensions(extStr);
1.1388 - localeExtensions = bldr.getLocaleExtensions();
1.1389 - } catch (LocaleSyntaxException e) {
1.1390 - throw new IllformedLocaleException(e.getMessage());
1.1391 - }
1.1392 - } else {
1.1393 - localeExtensions = null;
1.1394 - }
1.1395 - }
1.1396 -
1.1397 - /**
1.1398 - * Returns a cached <code>Locale</code> instance equivalent to
1.1399 - * the deserialized <code>Locale</code>. When serialized
1.1400 - * language, country and variant fields read from the object data stream
1.1401 - * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
1.1402 - * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>
1.1403 - * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
1.1404 - * type is "thai"). See <a href="Locale.html#special_cases_constructor"/>Special Cases</a>
1.1405 - * for more information.
1.1406 - *
1.1407 - * @return an instance of <code>Locale</code> equivalent to
1.1408 - * the deserialized <code>Locale</code>.
1.1409 - * @throws java.io.ObjectStreamException
1.1410 - */
1.1411 - private Object readResolve() throws java.io.ObjectStreamException {
1.1412 - return getInstance(baseLocale.getLanguage(), baseLocale.getScript(),
1.1413 - baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions);
1.1414 - }
1.1415 -
1.1416 - private static volatile String[] isoLanguages = null;
1.1417 -
1.1418 - private static volatile String[] isoCountries = null;
1.1419 -
1.1420 - private static String convertOldISOCodes(String language) {
1.1421 - // we accept both the old and the new ISO codes for the languages whose ISO
1.1422 - // codes have changed, but we always store the OLD code, for backward compatibility
1.1423 - language = LocaleUtils.toLowerString(language).intern();
1.1424 - if (language == "he") {
1.1425 - return "iw";
1.1426 - } else if (language == "yi") {
1.1427 - return "ji";
1.1428 - } else if (language == "id") {
1.1429 - return "in";
1.1430 - } else {
1.1431 - return language;
1.1432 - }
1.1433 - }
1.1434 -
1.1435 - private static LocaleExtensions getCompatibilityExtensions(String language,
1.1436 - String script,
1.1437 - String country,
1.1438 - String variant) {
1.1439 - LocaleExtensions extensions = null;
1.1440 - // Special cases for backward compatibility support
1.1441 - if (LocaleUtils.caseIgnoreMatch(language, "ja")
1.1442 - && script.length() == 0
1.1443 - && LocaleUtils.caseIgnoreMatch(country, "jp")
1.1444 - && "JP".equals(variant)) {
1.1445 - // ja_JP_JP -> u-ca-japanese (calendar = japanese)
1.1446 - extensions = LocaleExtensions.CALENDAR_JAPANESE;
1.1447 - } else if (LocaleUtils.caseIgnoreMatch(language, "th")
1.1448 - && script.length() == 0
1.1449 - && LocaleUtils.caseIgnoreMatch(country, "th")
1.1450 - && "TH".equals(variant)) {
1.1451 - // th_TH_TH -> u-nu-thai (numbersystem = thai)
1.1452 - extensions = LocaleExtensions.NUMBER_THAI;
1.1453 - }
1.1454 - return extensions;
1.1455 - }
1.1456 -
1.1457 - /**
1.1458 - * Obtains a localized locale names from a LocaleNameProvider
1.1459 - * implementation.
1.1460 - */
1.1461 - private static class LocaleNameGetter
1.1462 - implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
1.1463 - private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
1.1464 -
1.1465 - public String getObject(LocaleNameProvider localeNameProvider,
1.1466 - Locale locale,
1.1467 - String key,
1.1468 - Object... params) {
1.1469 - assert params.length == 2;
1.1470 - int type = (Integer)params[0];
1.1471 - String code = (String)params[1];
1.1472 -
1.1473 - switch(type) {
1.1474 - case DISPLAY_LANGUAGE:
1.1475 - return localeNameProvider.getDisplayLanguage(code, locale);
1.1476 - case DISPLAY_COUNTRY:
1.1477 - return localeNameProvider.getDisplayCountry(code, locale);
1.1478 - case DISPLAY_VARIANT:
1.1479 - return localeNameProvider.getDisplayVariant(code, locale);
1.1480 - case DISPLAY_SCRIPT:
1.1481 - return localeNameProvider.getDisplayScript(code, locale);
1.1482 - default:
1.1483 - assert false; // shouldn't happen
1.1484 - }
1.1485 -
1.1486 - return null;
1.1487 - }
1.1488 - }
1.1489 -
1.1490 - /**
1.1491 - * Enum for locale categories. These locale categories are used to get/set
1.1492 - * the default locale for the specific functionality represented by the
1.1493 - * category.
1.1494 - *
1.1495 - * @see #getDefault(Locale.Category)
1.1496 - * @see #setDefault(Locale.Category, Locale)
1.1497 - * @since 1.7
1.1498 - */
1.1499 - public enum Category {
1.1500 -
1.1501 - /**
1.1502 - * Category used to represent the default locale for
1.1503 - * displaying user interfaces.
1.1504 - */
1.1505 - DISPLAY("user.language.display",
1.1506 - "user.script.display",
1.1507 - "user.country.display",
1.1508 - "user.variant.display"),
1.1509 -
1.1510 - /**
1.1511 - * Category used to represent the default locale for
1.1512 - * formatting dates, numbers, and/or currencies.
1.1513 - */
1.1514 - FORMAT("user.language.format",
1.1515 - "user.script.format",
1.1516 - "user.country.format",
1.1517 - "user.variant.format");
1.1518 -
1.1519 - Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
1.1520 - this.languageKey = languageKey;
1.1521 - this.scriptKey = scriptKey;
1.1522 - this.countryKey = countryKey;
1.1523 - this.variantKey = variantKey;
1.1524 - }
1.1525 -
1.1526 - final String languageKey;
1.1527 - final String scriptKey;
1.1528 - final String countryKey;
1.1529 - final String variantKey;
1.1530 - }
1.1531 -
1.1532 - /**
1.1533 - * <code>Builder</code> is used to build instances of <code>Locale</code>
1.1534 - * from values configured by the setters. Unlike the <code>Locale</code>
1.1535 - * constructors, the <code>Builder</code> checks if a value configured by a
1.1536 - * setter satisfies the syntax requirements defined by the <code>Locale</code>
1.1537 - * class. A <code>Locale</code> object created by a <code>Builder</code> is
1.1538 - * well-formed and can be transformed to a well-formed IETF BCP 47 language tag
1.1539 - * without losing information.
1.1540 - *
1.1541 - * <p><b>Note:</b> The <code>Locale</code> class does not provide any
1.1542 - * syntactic restrictions on variant, while BCP 47 requires each variant
1.1543 - * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3
1.1544 - * alphanumerics. The method <code>setVariant</code> throws
1.1545 - * <code>IllformedLocaleException</code> for a variant that does not satisfy
1.1546 - * this restriction. If it is necessary to support such a variant, use a
1.1547 - * Locale constructor. However, keep in mind that a <code>Locale</code>
1.1548 - * object created this way might lose the variant information when
1.1549 - * transformed to a BCP 47 language tag.
1.1550 - *
1.1551 - * <p>The following example shows how to create a <code>Locale</code> object
1.1552 - * with the <code>Builder</code>.
1.1553 - * <blockquote>
1.1554 - * <pre>
1.1555 - * Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
1.1556 - * </pre>
1.1557 - * </blockquote>
1.1558 - *
1.1559 - * <p>Builders can be reused; <code>clear()</code> resets all
1.1560 - * fields to their default values.
1.1561 - *
1.1562 - * @see Locale#forLanguageTag
1.1563 - * @since 1.7
1.1564 - */
1.1565 - public static final class Builder {
1.1566 - private final InternalLocaleBuilder localeBuilder;
1.1567 -
1.1568 - /**
1.1569 - * Constructs an empty Builder. The default value of all
1.1570 - * fields, extensions, and private use information is the
1.1571 - * empty string.
1.1572 - */
1.1573 - public Builder() {
1.1574 - localeBuilder = new InternalLocaleBuilder();
1.1575 - }
1.1576 -
1.1577 - /**
1.1578 - * Resets the <code>Builder</code> to match the provided
1.1579 - * <code>locale</code>. Existing state is discarded.
1.1580 - *
1.1581 - * <p>All fields of the locale must be well-formed, see {@link Locale}.
1.1582 - *
1.1583 - * <p>Locales with any ill-formed fields cause
1.1584 - * <code>IllformedLocaleException</code> to be thrown, except for the
1.1585 - * following three cases which are accepted for compatibility
1.1586 - * reasons:<ul>
1.1587 - * <li>Locale("ja", "JP", "JP") is treated as "ja-JP-u-ca-japanese"
1.1588 - * <li>Locale("th", "TH", "TH") is treated as "th-TH-u-nu-thai"
1.1589 - * <li>Locale("no", "NO", "NY") is treated as "nn-NO"</ul>
1.1590 - *
1.1591 - * @param locale the locale
1.1592 - * @return This builder.
1.1593 - * @throws IllformedLocaleException if <code>locale</code> has
1.1594 - * any ill-formed fields.
1.1595 - * @throws NullPointerException if <code>locale</code> is null.
1.1596 - */
1.1597 - public Builder setLocale(Locale locale) {
1.1598 - try {
1.1599 - localeBuilder.setLocale(locale.baseLocale, locale.localeExtensions);
1.1600 - } catch (LocaleSyntaxException e) {
1.1601 - throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.1602 - }
1.1603 - return this;
1.1604 - }
1.1605 -
1.1606 - /**
1.1607 - * Resets the Builder to match the provided IETF BCP 47
1.1608 - * language tag. Discards the existing state. Null and the
1.1609 - * empty string cause the builder to be reset, like {@link
1.1610 - * #clear}. Grandfathered tags (see {@link
1.1611 - * Locale#forLanguageTag}) are converted to their canonical
1.1612 - * form before being processed. Otherwise, the language tag
1.1613 - * must be well-formed (see {@link Locale}) or an exception is
1.1614 - * thrown (unlike <code>Locale.forLanguageTag</code>, which
1.1615 - * just discards ill-formed and following portions of the
1.1616 - * tag).
1.1617 - *
1.1618 - * @param languageTag the language tag
1.1619 - * @return This builder.
1.1620 - * @throws IllformedLocaleException if <code>languageTag</code> is ill-formed
1.1621 - * @see Locale#forLanguageTag(String)
1.1622 - */
1.1623 - public Builder setLanguageTag(String languageTag) {
1.1624 - ParseStatus sts = new ParseStatus();
1.1625 - LanguageTag tag = LanguageTag.parse(languageTag, sts);
1.1626 - if (sts.isError()) {
1.1627 - throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex());
1.1628 - }
1.1629 - localeBuilder.setLanguageTag(tag);
1.1630 - return this;
1.1631 - }
1.1632 -
1.1633 - /**
1.1634 - * Sets the language. If <code>language</code> is the empty string or
1.1635 - * null, the language in this <code>Builder</code> is removed. Otherwise,
1.1636 - * the language must be <a href="./Locale.html#def_language">well-formed</a>
1.1637 - * or an exception is thrown.
1.1638 - *
1.1639 - * <p>The typical language value is a two or three-letter language
1.1640 - * code as defined in ISO639.
1.1641 - *
1.1642 - * @param language the language
1.1643 - * @return This builder.
1.1644 - * @throws IllformedLocaleException if <code>language</code> is ill-formed
1.1645 - */
1.1646 - public Builder setLanguage(String language) {
1.1647 - try {
1.1648 - localeBuilder.setLanguage(language);
1.1649 - } catch (LocaleSyntaxException e) {
1.1650 - throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.1651 - }
1.1652 - return this;
1.1653 - }
1.1654 -
1.1655 - /**
1.1656 - * Sets the script. If <code>script</code> is null or the empty string,
1.1657 - * the script in this <code>Builder</code> is removed.
1.1658 - * Otherwise, the script must be <a href="./Locale.html#def_script">well-formed</a> or an
1.1659 - * exception is thrown.
1.1660 - *
1.1661 - * <p>The typical script value is a four-letter script code as defined by ISO 15924.
1.1662 - *
1.1663 - * @param script the script
1.1664 - * @return This builder.
1.1665 - * @throws IllformedLocaleException if <code>script</code> is ill-formed
1.1666 - */
1.1667 - public Builder setScript(String script) {
1.1668 - try {
1.1669 - localeBuilder.setScript(script);
1.1670 - } catch (LocaleSyntaxException e) {
1.1671 - throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.1672 - }
1.1673 - return this;
1.1674 - }
1.1675 -
1.1676 - /**
1.1677 - * Sets the region. If region is null or the empty string, the region
1.1678 - * in this <code>Builder</code> is removed. Otherwise,
1.1679 - * the region must be <a href="./Locale.html#def_region">well-formed</a> or an
1.1680 - * exception is thrown.
1.1681 - *
1.1682 - * <p>The typical region value is a two-letter ISO 3166 code or a
1.1683 - * three-digit UN M.49 area code.
1.1684 - *
1.1685 - * <p>The country value in the <code>Locale</code> created by the
1.1686 - * <code>Builder</code> is always normalized to upper case.
1.1687 - *
1.1688 - * @param region the region
1.1689 - * @return This builder.
1.1690 - * @throws IllformedLocaleException if <code>region</code> is ill-formed
1.1691 - */
1.1692 - public Builder setRegion(String region) {
1.1693 - try {
1.1694 - localeBuilder.setRegion(region);
1.1695 - } catch (LocaleSyntaxException e) {
1.1696 - throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.1697 - }
1.1698 - return this;
1.1699 - }
1.1700 -
1.1701 - /**
1.1702 - * Sets the variant. If variant is null or the empty string, the
1.1703 - * variant in this <code>Builder</code> is removed. Otherwise, it
1.1704 - * must consist of one or more <a href="./Locale.html#def_variant">well-formed</a>
1.1705 - * subtags, or an exception is thrown.
1.1706 - *
1.1707 - * <p><b>Note:</b> This method checks if <code>variant</code>
1.1708 - * satisfies the IETF BCP 47 variant subtag's syntax requirements,
1.1709 - * and normalizes the value to lowercase letters. However,
1.1710 - * the <code>Locale</code> class does not impose any syntactic
1.1711 - * restriction on variant, and the variant value in
1.1712 - * <code>Locale</code> is case sensitive. To set such a variant,
1.1713 - * use a Locale constructor.
1.1714 - *
1.1715 - * @param variant the variant
1.1716 - * @return This builder.
1.1717 - * @throws IllformedLocaleException if <code>variant</code> is ill-formed
1.1718 - */
1.1719 - public Builder setVariant(String variant) {
1.1720 - try {
1.1721 - localeBuilder.setVariant(variant);
1.1722 - } catch (LocaleSyntaxException e) {
1.1723 - throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.1724 - }
1.1725 - return this;
1.1726 - }
1.1727 -
1.1728 - /**
1.1729 - * Sets the extension for the given key. If the value is null or the
1.1730 - * empty string, the extension is removed. Otherwise, the extension
1.1731 - * must be <a href="./Locale.html#def_extensions">well-formed</a> or an exception
1.1732 - * is thrown.
1.1733 - *
1.1734 - * <p><b>Note:</b> The key {@link Locale#UNICODE_LOCALE_EXTENSION
1.1735 - * UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension.
1.1736 - * Setting a value for this key replaces any existing Unicode locale key/type
1.1737 - * pairs with those defined in the extension.
1.1738 - *
1.1739 - * <p><b>Note:</b> The key {@link Locale#PRIVATE_USE_EXTENSION
1.1740 - * PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be
1.1741 - * well-formed, the value for this key needs only to have subtags of one to
1.1742 - * eight alphanumeric characters, not two to eight as in the general case.
1.1743 - *
1.1744 - * @param key the extension key
1.1745 - * @param value the extension value
1.1746 - * @return This builder.
1.1747 - * @throws IllformedLocaleException if <code>key</code> is illegal
1.1748 - * or <code>value</code> is ill-formed
1.1749 - * @see #setUnicodeLocaleKeyword(String, String)
1.1750 - */
1.1751 - public Builder setExtension(char key, String value) {
1.1752 - try {
1.1753 - localeBuilder.setExtension(key, value);
1.1754 - } catch (LocaleSyntaxException e) {
1.1755 - throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.1756 - }
1.1757 - return this;
1.1758 - }
1.1759 -
1.1760 - /**
1.1761 - * Sets the Unicode locale keyword type for the given key. If the type
1.1762 - * is null, the Unicode keyword is removed. Otherwise, the key must be
1.1763 - * non-null and both key and type must be <a
1.1764 - * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
1.1765 - * is thrown.
1.1766 - *
1.1767 - * <p>Keys and types are converted to lower case.
1.1768 - *
1.1769 - * <p><b>Note</b>:Setting the 'u' extension via {@link #setExtension}
1.1770 - * replaces all Unicode locale keywords with those defined in the
1.1771 - * extension.
1.1772 - *
1.1773 - * @param key the Unicode locale key
1.1774 - * @param type the Unicode locale type
1.1775 - * @return This builder.
1.1776 - * @throws IllformedLocaleException if <code>key</code> or <code>type</code>
1.1777 - * is ill-formed
1.1778 - * @throws NullPointerException if <code>key</code> is null
1.1779 - * @see #setExtension(char, String)
1.1780 - */
1.1781 - public Builder setUnicodeLocaleKeyword(String key, String type) {
1.1782 - try {
1.1783 - localeBuilder.setUnicodeLocaleKeyword(key, type);
1.1784 - } catch (LocaleSyntaxException e) {
1.1785 - throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.1786 - }
1.1787 - return this;
1.1788 - }
1.1789 -
1.1790 - /**
1.1791 - * Adds a unicode locale attribute, if not already present, otherwise
1.1792 - * has no effect. The attribute must not be null and must be <a
1.1793 - * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
1.1794 - * is thrown.
1.1795 - *
1.1796 - * @param attribute the attribute
1.1797 - * @return This builder.
1.1798 - * @throws NullPointerException if <code>attribute</code> is null
1.1799 - * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
1.1800 - * @see #setExtension(char, String)
1.1801 - */
1.1802 - public Builder addUnicodeLocaleAttribute(String attribute) {
1.1803 - try {
1.1804 - localeBuilder.addUnicodeLocaleAttribute(attribute);
1.1805 - } catch (LocaleSyntaxException e) {
1.1806 - throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.1807 - }
1.1808 - return this;
1.1809 - }
1.1810 -
1.1811 - /**
1.1812 - * Removes a unicode locale attribute, if present, otherwise has no
1.1813 - * effect. The attribute must not be null and must be <a
1.1814 - * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
1.1815 - * is thrown.
1.1816 - *
1.1817 - * <p>Attribute comparision for removal is case-insensitive.
1.1818 - *
1.1819 - * @param attribute the attribute
1.1820 - * @return This builder.
1.1821 - * @throws NullPointerException if <code>attribute</code> is null
1.1822 - * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
1.1823 - * @see #setExtension(char, String)
1.1824 - */
1.1825 - public Builder removeUnicodeLocaleAttribute(String attribute) {
1.1826 - try {
1.1827 - localeBuilder.removeUnicodeLocaleAttribute(attribute);
1.1828 - } catch (LocaleSyntaxException e) {
1.1829 - throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.1830 - }
1.1831 - return this;
1.1832 - }
1.1833 -
1.1834 - /**
1.1835 - * Resets the builder to its initial, empty state.
1.1836 - *
1.1837 - * @return This builder.
1.1838 - */
1.1839 - public Builder clear() {
1.1840 - localeBuilder.clear();
1.1841 - return this;
1.1842 - }
1.1843 -
1.1844 - /**
1.1845 - * Resets the extensions to their initial, empty state.
1.1846 - * Language, script, region and variant are unchanged.
1.1847 - *
1.1848 - * @return This builder.
1.1849 - * @see #setExtension(char, String)
1.1850 - */
1.1851 - public Builder clearExtensions() {
1.1852 - localeBuilder.clearExtensions();
1.1853 - return this;
1.1854 - }
1.1855 -
1.1856 - /**
1.1857 - * Returns an instance of <code>Locale</code> created from the fields set
1.1858 - * on this builder.
1.1859 - *
1.1860 - * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
1.1861 - * when constructing a Locale. (Grandfathered tags are handled in
1.1862 - * {@link #setLanguageTag}.)
1.1863 - *
1.1864 - * @return A Locale.
1.1865 - */
1.1866 - public Locale build() {
1.1867 - BaseLocale baseloc = localeBuilder.getBaseLocale();
1.1868 - LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
1.1869 - if (extensions == null && baseloc.getVariant().length() > 0) {
1.1870 - extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
1.1871 - baseloc.getRegion(), baseloc.getVariant());
1.1872 - }
1.1873 - return Locale.getInstance(baseloc, extensions);
1.1874 - }
1.1875 - }
1.1876 }