1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/rt/emul/compact/src/main/java/java/util/Locale.java Sat Sep 28 02:18:42 2013 +0200
1.3 @@ -0,0 +1,2560 @@
1.4 +/*
1.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
1.7 + *
1.8 + * This code is free software; you can redistribute it and/or modify it
1.9 + * under the terms of the GNU General Public License version 2 only, as
1.10 + * published by the Free Software Foundation. Oracle designates this
1.11 + * particular file as subject to the "Classpath" exception as provided
1.12 + * by Oracle in the LICENSE file that accompanied this code.
1.13 + *
1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
1.17 + * version 2 for more details (a copy is included in the LICENSE file that
1.18 + * accompanied this code).
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License version
1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1.23 + *
1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1.25 + * or visit www.oracle.com if you need additional information or have any
1.26 + * questions.
1.27 + */
1.28 +
1.29 +/*
1.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
1.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
1.32 + *
1.33 + * The original version of this source code and documentation
1.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
1.35 + * subsidiary of IBM. These materials are provided under terms
1.36 + * of a License Agreement between Taligent and Sun. This technology
1.37 + * is protected by multiple US and International patents.
1.38 + *
1.39 + * This notice and attribution to Taligent may not be removed.
1.40 + * Taligent is a registered trademark of Taligent, Inc.
1.41 + *
1.42 + */
1.43 +
1.44 +package java.util;
1.45 +
1.46 +import java.io.IOException;
1.47 +import java.io.ObjectInputStream;
1.48 +import java.io.ObjectOutputStream;
1.49 +import java.io.ObjectStreamField;
1.50 +import java.io.Serializable;
1.51 +import java.security.AccessController;
1.52 +import java.text.MessageFormat;
1.53 +import java.util.spi.LocaleNameProvider;
1.54 +
1.55 +import sun.security.action.GetPropertyAction;
1.56 +import sun.util.LocaleServiceProviderPool;
1.57 +import sun.util.locale.BaseLocale;
1.58 +import sun.util.locale.InternalLocaleBuilder;
1.59 +import sun.util.locale.LanguageTag;
1.60 +import sun.util.locale.LocaleExtensions;
1.61 +import sun.util.locale.LocaleObjectCache;
1.62 +import sun.util.locale.LocaleSyntaxException;
1.63 +import sun.util.locale.LocaleUtils;
1.64 +import sun.util.locale.ParseStatus;
1.65 +import sun.util.locale.UnicodeLocaleExtension;
1.66 +import sun.util.resources.LocaleData;
1.67 +import sun.util.resources.OpenListResourceBundle;
1.68 +
1.69 +/**
1.70 + * A <code>Locale</code> object represents a specific geographical, political,
1.71 + * or cultural region. An operation that requires a <code>Locale</code> to perform
1.72 + * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
1.73 + * to tailor information for the user. For example, displaying a number
1.74 + * is a locale-sensitive operation— the number should be formatted
1.75 + * according to the customs and conventions of the user's native country,
1.76 + * region, or culture.
1.77 + *
1.78 + * <p> The <code>Locale</code> class implements identifiers
1.79 + * interchangeable with BCP 47 (IETF BCP 47, "Tags for Identifying
1.80 + * Languages"), with support for the LDML (UTS#35, "Unicode Locale
1.81 + * Data Markup Language") BCP 47-compatible extensions for locale data
1.82 + * exchange.
1.83 + *
1.84 + * <p> A <code>Locale</code> object logically consists of the fields
1.85 + * described below.
1.86 + *
1.87 + * <dl>
1.88 + * <dt><a name="def_language"/><b>language</b></dt>
1.89 + *
1.90 + * <dd>ISO 639 alpha-2 or alpha-3 language code, or registered
1.91 + * language subtags up to 8 alpha letters (for future enhancements).
1.92 + * When a language has both an alpha-2 code and an alpha-3 code, the
1.93 + * alpha-2 code must be used. You can find a full list of valid
1.94 + * language codes in the IANA Language Subtag Registry (search for
1.95 + * "Type: language"). The language field is case insensitive, but
1.96 + * <code>Locale</code> always canonicalizes to lower case.</dd><br>
1.97 + *
1.98 + * <dd>Well-formed language values have the form
1.99 + * <code>[a-zA-Z]{2,8}</code>. Note that this is not the the full
1.100 + * BCP47 language production, since it excludes extlang. They are
1.101 + * not needed since modern three-letter language codes replace
1.102 + * them.</dd><br>
1.103 + *
1.104 + * <dd>Example: "en" (English), "ja" (Japanese), "kok" (Konkani)</dd><br>
1.105 + *
1.106 + * <dt><a name="def_script"/><b>script</b></dt>
1.107 + *
1.108 + * <dd>ISO 15924 alpha-4 script code. You can find a full list of
1.109 + * valid script codes in the IANA Language Subtag Registry (search
1.110 + * for "Type: script"). The script field is case insensitive, but
1.111 + * <code>Locale</code> always canonicalizes to title case (the first
1.112 + * letter is upper case and the rest of the letters are lower
1.113 + * case).</dd><br>
1.114 + *
1.115 + * <dd>Well-formed script values have the form
1.116 + * <code>[a-zA-Z]{4}</code></dd><br>
1.117 + *
1.118 + * <dd>Example: "Latn" (Latin), "Cyrl" (Cyrillic)</dd><br>
1.119 + *
1.120 + * <dt><a name="def_region"/><b>country (region)</b></dt>
1.121 + *
1.122 + * <dd>ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.
1.123 + * You can find a full list of valid country and region codes in the
1.124 + * IANA Language Subtag Registry (search for "Type: region"). The
1.125 + * country (region) field is case insensitive, but
1.126 + * <code>Locale</code> always canonicalizes to upper case.</dd><br>
1.127 + *
1.128 + * <dd>Well-formed country/region values have
1.129 + * the form <code>[a-zA-Z]{2} | [0-9]{3}</code></dd><br>
1.130 + *
1.131 + * <dd>Example: "US" (United States), "FR" (France), "029"
1.132 + * (Caribbean)</dd><br>
1.133 + *
1.134 + * <dt><a name="def_variant"/><b>variant</b></dt>
1.135 + *
1.136 + * <dd>Any arbitrary value used to indicate a variation of a
1.137 + * <code>Locale</code>. Where there are two or more variant values
1.138 + * each indicating its own semantics, these values should be ordered
1.139 + * by importance, with most important first, separated by
1.140 + * underscore('_'). The variant field is case sensitive.</dd><br>
1.141 + *
1.142 + * <dd>Note: IETF BCP 47 places syntactic restrictions on variant
1.143 + * subtags. Also BCP 47 subtags are strictly used to indicate
1.144 + * additional variations that define a language or its dialects that
1.145 + * are not covered by any combinations of language, script and
1.146 + * region subtags. You can find a full list of valid variant codes
1.147 + * in the IANA Language Subtag Registry (search for "Type: variant").
1.148 + *
1.149 + * <p>However, the variant field in <code>Locale</code> has
1.150 + * historically been used for any kind of variation, not just
1.151 + * language variations. For example, some supported variants
1.152 + * available in Java SE Runtime Environments indicate alternative
1.153 + * cultural behaviors such as calendar type or number script. In
1.154 + * BCP 47 this kind of information, which does not identify the
1.155 + * language, is supported by extension subtags or private use
1.156 + * subtags.</dd><br>
1.157 + *
1.158 + * <dd>Well-formed variant values have the form <code>SUBTAG
1.159 + * (('_'|'-') SUBTAG)*</code> where <code>SUBTAG =
1.160 + * [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}</code>. (Note: BCP 47 only
1.161 + * uses hyphen ('-') as a delimiter, this is more lenient).</dd><br>
1.162 + *
1.163 + * <dd>Example: "polyton" (Polytonic Greek), "POSIX"</dd><br>
1.164 + *
1.165 + * <dt><a name="def_extensions"/><b>extensions</b></dt>
1.166 + *
1.167 + * <dd>A map from single character keys to string values, indicating
1.168 + * extensions apart from language identification. The extensions in
1.169 + * <code>Locale</code> implement the semantics and syntax of BCP 47
1.170 + * extension subtags and private use subtags. The extensions are
1.171 + * case insensitive, but <code>Locale</code> canonicalizes all
1.172 + * extension keys and values to lower case. Note that extensions
1.173 + * cannot have empty values.</dd><br>
1.174 + *
1.175 + * <dd>Well-formed keys are single characters from the set
1.176 + * <code>[0-9a-zA-Z]</code>. Well-formed values have the form
1.177 + * <code>SUBTAG ('-' SUBTAG)*</code> where for the key 'x'
1.178 + * <code>SUBTAG = [0-9a-zA-Z]{1,8}</code> and for other keys
1.179 + * <code>SUBTAG = [0-9a-zA-Z]{2,8}</code> (that is, 'x' allows
1.180 + * single-character subtags).</dd><br>
1.181 + *
1.182 + * <dd>Example: key="u"/value="ca-japanese" (Japanese Calendar),
1.183 + * key="x"/value="java-1-7"</dd>
1.184 + * </dl>
1.185 + *
1.186 + * <b>Note:</b> Although BCP 47 requires field values to be registered
1.187 + * in the IANA Language Subtag Registry, the <code>Locale</code> class
1.188 + * does not provide any validation features. The <code>Builder</code>
1.189 + * only checks if an individual field satisfies the syntactic
1.190 + * requirement (is well-formed), but does not validate the value
1.191 + * itself. See {@link Builder} for details.
1.192 + *
1.193 + * <h4><a name="def_locale_extension">Unicode locale/language extension</h4>
1.194 + *
1.195 + * <p>UTS#35, "Unicode Locale Data Markup Language" defines optional
1.196 + * attributes and keywords to override or refine the default behavior
1.197 + * associated with a locale. A keyword is represented by a pair of
1.198 + * key and type. For example, "nu-thai" indicates that Thai local
1.199 + * digits (value:"thai") should be used for formatting numbers
1.200 + * (key:"nu").
1.201 + *
1.202 + * <p>The keywords are mapped to a BCP 47 extension value using the
1.203 + * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}). The above
1.204 + * example, "nu-thai", becomes the extension "u-nu-thai".code
1.205 + *
1.206 + * <p>Thus, when a <code>Locale</code> object contains Unicode locale
1.207 + * attributes and keywords,
1.208 + * <code>getExtension(UNICODE_LOCALE_EXTENSION)</code> will return a
1.209 + * String representing this information, for example, "nu-thai". The
1.210 + * <code>Locale</code> class also provides {@link
1.211 + * #getUnicodeLocaleAttributes}, {@link #getUnicodeLocaleKeys}, and
1.212 + * {@link #getUnicodeLocaleType} which allow you to access Unicode
1.213 + * locale attributes and key/type pairs directly. When represented as
1.214 + * a string, the Unicode Locale Extension lists attributes
1.215 + * alphabetically, followed by key/type sequences with keys listed
1.216 + * alphabetically (the order of subtags comprising a key's type is
1.217 + * fixed when the type is defined)
1.218 + *
1.219 + * <p>A well-formed locale key has the form
1.220 + * <code>[0-9a-zA-Z]{2}</code>. A well-formed locale type has the
1.221 + * form <code>"" | [0-9a-zA-Z]{3,8} ('-' [0-9a-zA-Z]{3,8})*</code> (it
1.222 + * can be empty, or a series of subtags 3-8 alphanums in length). A
1.223 + * well-formed locale attribute has the form
1.224 + * <code>[0-9a-zA-Z]{3,8}</code> (it is a single subtag with the same
1.225 + * form as a locale type subtag).
1.226 + *
1.227 + * <p>The Unicode locale extension specifies optional behavior in
1.228 + * locale-sensitive services. Although the LDML specification defines
1.229 + * various keys and values, actual locale-sensitive service
1.230 + * implementations in a Java Runtime Environment might not support any
1.231 + * particular Unicode locale attributes or key/type pairs.
1.232 + *
1.233 + * <h4>Creating a Locale</h4>
1.234 + *
1.235 + * <p>There are several different ways to create a <code>Locale</code>
1.236 + * object.
1.237 + *
1.238 + * <h5>Builder</h5>
1.239 + *
1.240 + * <p>Using {@link Builder} you can construct a <code>Locale</code> object
1.241 + * that conforms to BCP 47 syntax.
1.242 + *
1.243 + * <h5>Constructors</h5>
1.244 + *
1.245 + * <p>The <code>Locale</code> class provides three constructors:
1.246 + * <blockquote>
1.247 + * <pre>
1.248 + * {@link #Locale(String language)}
1.249 + * {@link #Locale(String language, String country)}
1.250 + * {@link #Locale(String language, String country, String variant)}
1.251 + * </pre>
1.252 + * </blockquote>
1.253 + * These constructors allow you to create a <code>Locale</code> object
1.254 + * with language, country and variant, but you cannot specify
1.255 + * script or extensions.
1.256 + *
1.257 + * <h5>Factory Methods</h5>
1.258 + *
1.259 + * <p>The method {@link #forLanguageTag} creates a <code>Locale</code>
1.260 + * object for a well-formed BCP 47 language tag.
1.261 + *
1.262 + * <h5>Locale Constants</h5>
1.263 + *
1.264 + * <p>The <code>Locale</code> class provides a number of convenient constants
1.265 + * that you can use to create <code>Locale</code> objects for commonly used
1.266 + * locales. For example, the following creates a <code>Locale</code> object
1.267 + * for the United States:
1.268 + * <blockquote>
1.269 + * <pre>
1.270 + * Locale.US
1.271 + * </pre>
1.272 + * </blockquote>
1.273 + *
1.274 + * <h4>Use of Locale</h4>
1.275 + *
1.276 + * <p>Once you've created a <code>Locale</code> you can query it for information
1.277 + * about itself. Use <code>getCountry</code> to get the country (or region)
1.278 + * code and <code>getLanguage</code> to get the language code.
1.279 + * You can use <code>getDisplayCountry</code> to get the
1.280 + * name of the country suitable for displaying to the user. Similarly,
1.281 + * you can use <code>getDisplayLanguage</code> to get the name of
1.282 + * the language suitable for displaying to the user. Interestingly,
1.283 + * the <code>getDisplayXXX</code> methods are themselves locale-sensitive
1.284 + * and have two versions: one that uses the default locale and one
1.285 + * that uses the locale specified as an argument.
1.286 + *
1.287 + * <p>The Java Platform provides a number of classes that perform locale-sensitive
1.288 + * operations. For example, the <code>NumberFormat</code> class formats
1.289 + * numbers, currency, and percentages in a locale-sensitive manner. Classes
1.290 + * such as <code>NumberFormat</code> have several convenience methods
1.291 + * for creating a default object of that type. For example, the
1.292 + * <code>NumberFormat</code> class provides these three convenience methods
1.293 + * for creating a default <code>NumberFormat</code> object:
1.294 + * <blockquote>
1.295 + * <pre>
1.296 + * NumberFormat.getInstance()
1.297 + * NumberFormat.getCurrencyInstance()
1.298 + * NumberFormat.getPercentInstance()
1.299 + * </pre>
1.300 + * </blockquote>
1.301 + * Each of these methods has two variants; one with an explicit locale
1.302 + * and one without; the latter uses the default locale:
1.303 + * <blockquote>
1.304 + * <pre>
1.305 + * NumberFormat.getInstance(myLocale)
1.306 + * NumberFormat.getCurrencyInstance(myLocale)
1.307 + * NumberFormat.getPercentInstance(myLocale)
1.308 + * </pre>
1.309 + * </blockquote>
1.310 + * A <code>Locale</code> is the mechanism for identifying the kind of object
1.311 + * (<code>NumberFormat</code>) that you would like to get. The locale is
1.312 + * <STRONG>just</STRONG> a mechanism for identifying objects,
1.313 + * <STRONG>not</STRONG> a container for the objects themselves.
1.314 + *
1.315 + * <h4>Compatibility</h4>
1.316 + *
1.317 + * <p>In order to maintain compatibility with existing usage, Locale's
1.318 + * constructors retain their behavior prior to the Java Runtime
1.319 + * Environment version 1.7. The same is largely true for the
1.320 + * <code>toString</code> method. Thus Locale objects can continue to
1.321 + * be used as they were. In particular, clients who parse the output
1.322 + * of toString into language, country, and variant fields can continue
1.323 + * to do so (although this is strongly discouraged), although the
1.324 + * variant field will have additional information in it if script or
1.325 + * extensions are present.
1.326 + *
1.327 + * <p>In addition, BCP 47 imposes syntax restrictions that are not
1.328 + * imposed by Locale's constructors. This means that conversions
1.329 + * between some Locales and BCP 47 language tags cannot be made without
1.330 + * losing information. Thus <code>toLanguageTag</code> cannot
1.331 + * represent the state of locales whose language, country, or variant
1.332 + * do not conform to BCP 47.
1.333 + *
1.334 + * <p>Because of these issues, it is recommended that clients migrate
1.335 + * away from constructing non-conforming locales and use the
1.336 + * <code>forLanguageTag</code> and <code>Locale.Builder</code> APIs instead.
1.337 + * Clients desiring a string representation of the complete locale can
1.338 + * then always rely on <code>toLanguageTag</code> for this purpose.
1.339 + *
1.340 + * <h5><a name="special_cases_constructor"/>Special cases</h5>
1.341 + *
1.342 + * <p>For compatibility reasons, two
1.343 + * non-conforming locales are treated as special cases. These are
1.344 + * <b><tt>ja_JP_JP</tt></b> and <b><tt>th_TH_TH</tt></b>. These are ill-formed
1.345 + * in BCP 47 since the variants are too short. To ease migration to BCP 47,
1.346 + * these are treated specially during construction. These two cases (and only
1.347 + * these) cause a constructor to generate an extension, all other values behave
1.348 + * exactly as they did prior to Java 7.
1.349 + *
1.350 + * <p>Java has used <tt>ja_JP_JP</tt> to represent Japanese as used in
1.351 + * Japan together with the Japanese Imperial calendar. This is now
1.352 + * representable using a Unicode locale extension, by specifying the
1.353 + * Unicode locale key <tt>ca</tt> (for "calendar") and type
1.354 + * <tt>japanese</tt>. When the Locale constructor is called with the
1.355 + * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is
1.356 + * automatically added.
1.357 + *
1.358 + * <p>Java has used <tt>th_TH_TH</tt> to represent Thai as used in
1.359 + * Thailand together with Thai digits. This is also now representable using
1.360 + * a Unicode locale extension, by specifying the Unicode locale key
1.361 + * <tt>nu</tt> (for "number") and value <tt>thai</tt>. When the Locale
1.362 + * constructor is called with the arguments "th", "TH", "TH", the
1.363 + * extension "u-nu-thai" is automatically added.
1.364 + *
1.365 + * <h5>Serialization</h5>
1.366 + *
1.367 + * <p>During serialization, writeObject writes all fields to the output
1.368 + * stream, including extensions.
1.369 + *
1.370 + * <p>During deserialization, readResolve adds extensions as described
1.371 + * in <a href="#special_cases_constructor">Special Cases</a>, only
1.372 + * for the two cases th_TH_TH and ja_JP_JP.
1.373 + *
1.374 + * <h5>Legacy language codes</h5>
1.375 + *
1.376 + * <p>Locale's constructor has always converted three language codes to
1.377 + * their earlier, obsoleted forms: <tt>he</tt> maps to <tt>iw</tt>,
1.378 + * <tt>yi</tt> maps to <tt>ji</tt>, and <tt>id</tt> maps to
1.379 + * <tt>in</tt>. This continues to be the case, in order to not break
1.380 + * backwards compatibility.
1.381 + *
1.382 + * <p>The APIs added in 1.7 map between the old and new language codes,
1.383 + * maintaining the old codes internal to Locale (so that
1.384 + * <code>getLanguage</code> and <code>toString</code> reflect the old
1.385 + * code), but using the new codes in the BCP 47 language tag APIs (so
1.386 + * that <code>toLanguageTag</code> reflects the new one). This
1.387 + * preserves the equivalence between Locales no matter which code or
1.388 + * API is used to construct them. Java's default resource bundle
1.389 + * lookup mechanism also implements this mapping, so that resources
1.390 + * can be named using either convention, see {@link ResourceBundle.Control}.
1.391 + *
1.392 + * <h5>Three-letter language/country(region) codes</h5>
1.393 + *
1.394 + * <p>The Locale constructors have always specified that the language
1.395 + * and the country param be two characters in length, although in
1.396 + * practice they have accepted any length. The specification has now
1.397 + * been relaxed to allow language codes of two to eight characters and
1.398 + * country (region) codes of two to three characters, and in
1.399 + * particular, three-letter language codes and three-digit region
1.400 + * codes as specified in the IANA Language Subtag Registry. For
1.401 + * compatibility, the implementation still does not impose a length
1.402 + * constraint.
1.403 + *
1.404 + * @see Builder
1.405 + * @see ResourceBundle
1.406 + * @see java.text.Format
1.407 + * @see java.text.NumberFormat
1.408 + * @see java.text.Collator
1.409 + * @author Mark Davis
1.410 + * @since 1.1
1.411 + */
1.412 +public final class Locale implements Cloneable, Serializable {
1.413 +
1.414 + static private final Cache LOCALECACHE = new Cache();
1.415 +
1.416 + /** Useful constant for language.
1.417 + */
1.418 + static public final Locale ENGLISH = createConstant("en", "");
1.419 +
1.420 + /** Useful constant for language.
1.421 + */
1.422 + static public final Locale FRENCH = createConstant("fr", "");
1.423 +
1.424 + /** Useful constant for language.
1.425 + */
1.426 + static public final Locale GERMAN = createConstant("de", "");
1.427 +
1.428 + /** Useful constant for language.
1.429 + */
1.430 + static public final Locale ITALIAN = createConstant("it", "");
1.431 +
1.432 + /** Useful constant for language.
1.433 + */
1.434 + static public final Locale JAPANESE = createConstant("ja", "");
1.435 +
1.436 + /** Useful constant for language.
1.437 + */
1.438 + static public final Locale KOREAN = createConstant("ko", "");
1.439 +
1.440 + /** Useful constant for language.
1.441 + */
1.442 + static public final Locale CHINESE = createConstant("zh", "");
1.443 +
1.444 + /** Useful constant for language.
1.445 + */
1.446 + static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
1.447 +
1.448 + /** Useful constant for language.
1.449 + */
1.450 + static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW");
1.451 +
1.452 + /** Useful constant for country.
1.453 + */
1.454 + static public final Locale FRANCE = createConstant("fr", "FR");
1.455 +
1.456 + /** Useful constant for country.
1.457 + */
1.458 + static public final Locale GERMANY = createConstant("de", "DE");
1.459 +
1.460 + /** Useful constant for country.
1.461 + */
1.462 + static public final Locale ITALY = createConstant("it", "IT");
1.463 +
1.464 + /** Useful constant for country.
1.465 + */
1.466 + static public final Locale JAPAN = createConstant("ja", "JP");
1.467 +
1.468 + /** Useful constant for country.
1.469 + */
1.470 + static public final Locale KOREA = createConstant("ko", "KR");
1.471 +
1.472 + /** Useful constant for country.
1.473 + */
1.474 + static public final Locale CHINA = SIMPLIFIED_CHINESE;
1.475 +
1.476 + /** Useful constant for country.
1.477 + */
1.478 + static public final Locale PRC = SIMPLIFIED_CHINESE;
1.479 +
1.480 + /** Useful constant for country.
1.481 + */
1.482 + static public final Locale TAIWAN = TRADITIONAL_CHINESE;
1.483 +
1.484 + /** Useful constant for country.
1.485 + */
1.486 + static public final Locale UK = createConstant("en", "GB");
1.487 +
1.488 + /** Useful constant for country.
1.489 + */
1.490 + static public final Locale US = createConstant("en", "US");
1.491 +
1.492 + /** Useful constant for country.
1.493 + */
1.494 + static public final Locale CANADA = createConstant("en", "CA");
1.495 +
1.496 + /** Useful constant for country.
1.497 + */
1.498 + static public final Locale CANADA_FRENCH = createConstant("fr", "CA");
1.499 +
1.500 + /**
1.501 + * Useful constant for the root locale. The root locale is the locale whose
1.502 + * language, country, and variant are empty ("") strings. This is regarded
1.503 + * as the base locale of all locales, and is used as the language/country
1.504 + * neutral locale for the locale sensitive operations.
1.505 + *
1.506 + * @since 1.6
1.507 + */
1.508 + static public final Locale ROOT = createConstant("", "");
1.509 +
1.510 + /**
1.511 + * The key for the private use extension ('x').
1.512 + *
1.513 + * @see #getExtension(char)
1.514 + * @see Builder#setExtension(char, String)
1.515 + * @since 1.7
1.516 + */
1.517 + static public final char PRIVATE_USE_EXTENSION = 'x';
1.518 +
1.519 + /**
1.520 + * The key for Unicode locale extension ('u').
1.521 + *
1.522 + * @see #getExtension(char)
1.523 + * @see Builder#setExtension(char, String)
1.524 + * @since 1.7
1.525 + */
1.526 + static public final char UNICODE_LOCALE_EXTENSION = 'u';
1.527 +
1.528 + /** serialization ID
1.529 + */
1.530 + static final long serialVersionUID = 9149081749638150636L;
1.531 +
1.532 + /**
1.533 + * Display types for retrieving localized names from the name providers.
1.534 + */
1.535 + private static final int DISPLAY_LANGUAGE = 0;
1.536 + private static final int DISPLAY_COUNTRY = 1;
1.537 + private static final int DISPLAY_VARIANT = 2;
1.538 + private static final int DISPLAY_SCRIPT = 3;
1.539 +
1.540 + /**
1.541 + * Private constructor used by getInstance method
1.542 + */
1.543 + private Locale(BaseLocale baseLocale, LocaleExtensions extensions) {
1.544 + this.baseLocale = baseLocale;
1.545 + this.localeExtensions = extensions;
1.546 + }
1.547 +
1.548 + /**
1.549 + * Construct a locale from language, country and variant.
1.550 + * This constructor normalizes the language value to lowercase and
1.551 + * the country value to uppercase.
1.552 + * <p>
1.553 + * <b>Note:</b>
1.554 + * <ul>
1.555 + * <li>ISO 639 is not a stable standard; some of the language codes it defines
1.556 + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
1.557 + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
1.558 + * API on Locale will return only the OLD codes.
1.559 + * <li>For backward compatibility reasons, this constructor does not make
1.560 + * any syntactic checks on the input.
1.561 + * <li>The two cases ("ja", "JP", "JP") and ("th", "TH", "TH") are handled specially,
1.562 + * see <a href="#special_cases_constructor">Special Cases</a> for more information.
1.563 + * </ul>
1.564 + *
1.565 + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
1.566 + * up to 8 characters in length. See the <code>Locale</code> class description about
1.567 + * valid language values.
1.568 + * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
1.569 + * See the <code>Locale</code> class description about valid country values.
1.570 + * @param variant Any arbitrary value used to indicate a variation of a <code>Locale</code>.
1.571 + * See the <code>Locale</code> class description for the details.
1.572 + * @exception NullPointerException thrown if any argument is null.
1.573 + */
1.574 + public Locale(String language, String country, String variant) {
1.575 + if (language== null || country == null || variant == null) {
1.576 + throw new NullPointerException();
1.577 + }
1.578 + baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant);
1.579 + localeExtensions = getCompatibilityExtensions(language, "", country, variant);
1.580 + }
1.581 +
1.582 + /**
1.583 + * Construct a locale from language and country.
1.584 + * This constructor normalizes the language value to lowercase and
1.585 + * the country value to uppercase.
1.586 + * <p>
1.587 + * <b>Note:</b>
1.588 + * <ul>
1.589 + * <li>ISO 639 is not a stable standard; some of the language codes it defines
1.590 + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
1.591 + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
1.592 + * API on Locale will return only the OLD codes.
1.593 + * <li>For backward compatibility reasons, this constructor does not make
1.594 + * any syntactic checks on the input.
1.595 + * </ul>
1.596 + *
1.597 + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
1.598 + * up to 8 characters in length. See the <code>Locale</code> class description about
1.599 + * valid language values.
1.600 + * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
1.601 + * See the <code>Locale</code> class description about valid country values.
1.602 + * @exception NullPointerException thrown if either argument is null.
1.603 + */
1.604 + public Locale(String language, String country) {
1.605 + this(language, country, "");
1.606 + }
1.607 +
1.608 + /**
1.609 + * Construct a locale from a language code.
1.610 + * This constructor normalizes the language value to lowercase.
1.611 + * <p>
1.612 + * <b>Note:</b>
1.613 + * <ul>
1.614 + * <li>ISO 639 is not a stable standard; some of the language codes it defines
1.615 + * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
1.616 + * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
1.617 + * API on Locale will return only the OLD codes.
1.618 + * <li>For backward compatibility reasons, this constructor does not make
1.619 + * any syntactic checks on the input.
1.620 + * </ul>
1.621 + *
1.622 + * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
1.623 + * up to 8 characters in length. See the <code>Locale</code> class description about
1.624 + * valid language values.
1.625 + * @exception NullPointerException thrown if argument is null.
1.626 + * @since 1.4
1.627 + */
1.628 + public Locale(String language) {
1.629 + this(language, "", "");
1.630 + }
1.631 +
1.632 + /**
1.633 + * This method must be called only for creating the Locale.*
1.634 + * constants due to making shortcuts.
1.635 + */
1.636 + private static Locale createConstant(String lang, String country) {
1.637 + BaseLocale base = BaseLocale.createInstance(lang, country);
1.638 + return getInstance(base, null);
1.639 + }
1.640 +
1.641 + /**
1.642 + * Returns a <code>Locale</code> constructed from the given
1.643 + * <code>language</code>, <code>country</code> and
1.644 + * <code>variant</code>. If the same <code>Locale</code> instance
1.645 + * is available in the cache, then that instance is
1.646 + * returned. Otherwise, a new <code>Locale</code> instance is
1.647 + * created and cached.
1.648 + *
1.649 + * @param language lowercase 2 to 8 language code.
1.650 + * @param country uppercase two-letter ISO-3166 code and numric-3 UN M.49 area code.
1.651 + * @param variant vendor and browser specific code. See class description.
1.652 + * @return the <code>Locale</code> instance requested
1.653 + * @exception NullPointerException if any argument is null.
1.654 + */
1.655 + static Locale getInstance(String language, String country, String variant) {
1.656 + return getInstance(language, "", country, variant, null);
1.657 + }
1.658 +
1.659 + static Locale getInstance(String language, String script, String country,
1.660 + String variant, LocaleExtensions extensions) {
1.661 + if (language== null || script == null || country == null || variant == null) {
1.662 + throw new NullPointerException();
1.663 + }
1.664 +
1.665 + if (extensions == null) {
1.666 + extensions = getCompatibilityExtensions(language, script, country, variant);
1.667 + }
1.668 +
1.669 + BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant);
1.670 + return getInstance(baseloc, extensions);
1.671 + }
1.672 +
1.673 + static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) {
1.674 + LocaleKey key = new LocaleKey(baseloc, extensions);
1.675 + return LOCALECACHE.get(key);
1.676 + }
1.677 +
1.678 + private static class Cache extends LocaleObjectCache<LocaleKey, Locale> {
1.679 + private Cache() {
1.680 + }
1.681 +
1.682 + @Override
1.683 + protected Locale createObject(LocaleKey key) {
1.684 + return new Locale(key.base, key.exts);
1.685 + }
1.686 + }
1.687 +
1.688 + private static final class LocaleKey {
1.689 + private final BaseLocale base;
1.690 + private final LocaleExtensions exts;
1.691 + private final int hash;
1.692 +
1.693 + private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) {
1.694 + base = baseLocale;
1.695 + exts = extensions;
1.696 +
1.697 + // Calculate the hash value here because it's always used.
1.698 + int h = base.hashCode();
1.699 + if (exts != null) {
1.700 + h ^= exts.hashCode();
1.701 + }
1.702 + hash = h;
1.703 + }
1.704 +
1.705 + @Override
1.706 + public boolean equals(Object obj) {
1.707 + if (this == obj) {
1.708 + return true;
1.709 + }
1.710 + if (!(obj instanceof LocaleKey)) {
1.711 + return false;
1.712 + }
1.713 + LocaleKey other = (LocaleKey)obj;
1.714 + if (hash != other.hash || !base.equals(other.base)) {
1.715 + return false;
1.716 + }
1.717 + if (exts == null) {
1.718 + return other.exts == null;
1.719 + }
1.720 + return exts.equals(other.exts);
1.721 + }
1.722 +
1.723 + @Override
1.724 + public int hashCode() {
1.725 + return hash;
1.726 + }
1.727 + }
1.728 +
1.729 + /**
1.730 + * Gets the current value of the default locale for this instance
1.731 + * of the Java Virtual Machine.
1.732 + * <p>
1.733 + * The Java Virtual Machine sets the default locale during startup
1.734 + * based on the host environment. It is used by many locale-sensitive
1.735 + * methods if no locale is explicitly specified.
1.736 + * It can be changed using the
1.737 + * {@link #setDefault(java.util.Locale) setDefault} method.
1.738 + *
1.739 + * @return the default locale for this instance of the Java Virtual Machine
1.740 + */
1.741 + public static Locale getDefault() {
1.742 + // do not synchronize this method - see 4071298
1.743 + // it's OK if more than one default locale happens to be created
1.744 + if (defaultLocale == null) {
1.745 + initDefault();
1.746 + }
1.747 + return defaultLocale;
1.748 + }
1.749 +
1.750 + /**
1.751 + * Gets the current value of the default locale for the specified Category
1.752 + * for this instance of the Java Virtual Machine.
1.753 + * <p>
1.754 + * The Java Virtual Machine sets the default locale during startup based
1.755 + * on the host environment. It is used by many locale-sensitive methods
1.756 + * if no locale is explicitly specified. It can be changed using the
1.757 + * setDefault(Locale.Category, Locale) method.
1.758 + *
1.759 + * @param category - the specified category to get the default locale
1.760 + * @throws NullPointerException - if category is null
1.761 + * @return the default locale for the specified Category for this instance
1.762 + * of the Java Virtual Machine
1.763 + * @see #setDefault(Locale.Category, Locale)
1.764 + * @since 1.7
1.765 + */
1.766 + public static Locale getDefault(Locale.Category category) {
1.767 + // do not synchronize this method - see 4071298
1.768 + // it's OK if more than one default locale happens to be created
1.769 + switch (category) {
1.770 + case DISPLAY:
1.771 + if (defaultDisplayLocale == null) {
1.772 + initDefault(category);
1.773 + }
1.774 + return defaultDisplayLocale;
1.775 + case FORMAT:
1.776 + if (defaultFormatLocale == null) {
1.777 + initDefault(category);
1.778 + }
1.779 + return defaultFormatLocale;
1.780 + default:
1.781 + assert false: "Unknown Category";
1.782 + }
1.783 + return getDefault();
1.784 + }
1.785 +
1.786 + private static void initDefault() {
1.787 + String language, region, script, country, variant;
1.788 + language = AccessController.doPrivileged(
1.789 + new GetPropertyAction("user.language", "en"));
1.790 + // for compatibility, check for old user.region property
1.791 + region = AccessController.doPrivileged(
1.792 + new GetPropertyAction("user.region"));
1.793 + if (region != null) {
1.794 + // region can be of form country, country_variant, or _variant
1.795 + int i = region.indexOf('_');
1.796 + if (i >= 0) {
1.797 + country = region.substring(0, i);
1.798 + variant = region.substring(i + 1);
1.799 + } else {
1.800 + country = region;
1.801 + variant = "";
1.802 + }
1.803 + script = "";
1.804 + } else {
1.805 + script = AccessController.doPrivileged(
1.806 + new GetPropertyAction("user.script", ""));
1.807 + country = AccessController.doPrivileged(
1.808 + new GetPropertyAction("user.country", ""));
1.809 + variant = AccessController.doPrivileged(
1.810 + new GetPropertyAction("user.variant", ""));
1.811 + }
1.812 + defaultLocale = getInstance(language, script, country, variant, null);
1.813 + }
1.814 +
1.815 + private static void initDefault(Locale.Category category) {
1.816 + // make sure defaultLocale is initialized
1.817 + if (defaultLocale == null) {
1.818 + initDefault();
1.819 + }
1.820 +
1.821 + Locale defaultCategoryLocale = getInstance(
1.822 + AccessController.doPrivileged(
1.823 + new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())),
1.824 + AccessController.doPrivileged(
1.825 + new GetPropertyAction(category.scriptKey, defaultLocale.getScript())),
1.826 + AccessController.doPrivileged(
1.827 + new GetPropertyAction(category.countryKey, defaultLocale.getCountry())),
1.828 + AccessController.doPrivileged(
1.829 + new GetPropertyAction(category.variantKey, defaultLocale.getVariant())),
1.830 + null);
1.831 +
1.832 + switch (category) {
1.833 + case DISPLAY:
1.834 + defaultDisplayLocale = defaultCategoryLocale;
1.835 + break;
1.836 + case FORMAT:
1.837 + defaultFormatLocale = defaultCategoryLocale;
1.838 + break;
1.839 + }
1.840 + }
1.841 +
1.842 + /**
1.843 + * Sets the default locale for this instance of the Java Virtual Machine.
1.844 + * This does not affect the host locale.
1.845 + * <p>
1.846 + * If there is a security manager, its <code>checkPermission</code>
1.847 + * method is called with a <code>PropertyPermission("user.language", "write")</code>
1.848 + * permission before the default locale is changed.
1.849 + * <p>
1.850 + * The Java Virtual Machine sets the default locale during startup
1.851 + * based on the host environment. It is used by many locale-sensitive
1.852 + * methods if no locale is explicitly specified.
1.853 + * <p>
1.854 + * Since changing the default locale may affect many different areas
1.855 + * of functionality, this method should only be used if the caller
1.856 + * is prepared to reinitialize locale-sensitive code running
1.857 + * within the same Java Virtual Machine.
1.858 + * <p>
1.859 + * By setting the default locale with this method, all of the default
1.860 + * locales for each Category are also set to the specified default locale.
1.861 + *
1.862 + * @throws SecurityException
1.863 + * if a security manager exists and its
1.864 + * <code>checkPermission</code> method doesn't allow the operation.
1.865 + * @throws NullPointerException if <code>newLocale</code> is null
1.866 + * @param newLocale the new default locale
1.867 + * @see SecurityManager#checkPermission
1.868 + * @see java.util.PropertyPermission
1.869 + */
1.870 + public static synchronized void setDefault(Locale newLocale) {
1.871 + setDefault(Category.DISPLAY, newLocale);
1.872 + setDefault(Category.FORMAT, newLocale);
1.873 + defaultLocale = newLocale;
1.874 + }
1.875 +
1.876 + /**
1.877 + * Sets the default locale for the specified Category for this instance
1.878 + * of the Java Virtual Machine. This does not affect the host locale.
1.879 + * <p>
1.880 + * If there is a security manager, its checkPermission method is called
1.881 + * with a PropertyPermission("user.language", "write") permission before
1.882 + * the default locale is changed.
1.883 + * <p>
1.884 + * The Java Virtual Machine sets the default locale during startup based
1.885 + * on the host environment. It is used by many locale-sensitive methods
1.886 + * if no locale is explicitly specified.
1.887 + * <p>
1.888 + * Since changing the default locale may affect many different areas of
1.889 + * functionality, this method should only be used if the caller is
1.890 + * prepared to reinitialize locale-sensitive code running within the
1.891 + * same Java Virtual Machine.
1.892 + * <p>
1.893 + *
1.894 + * @param category - the specified category to set the default locale
1.895 + * @param newLocale - the new default locale
1.896 + * @throws SecurityException - if a security manager exists and its
1.897 + * checkPermission method doesn't allow the operation.
1.898 + * @throws NullPointerException - if category and/or newLocale is null
1.899 + * @see SecurityManager#checkPermission(java.security.Permission)
1.900 + * @see PropertyPermission
1.901 + * @see #getDefault(Locale.Category)
1.902 + * @since 1.7
1.903 + */
1.904 + public static synchronized void setDefault(Locale.Category category,
1.905 + Locale newLocale) {
1.906 + if (category == null)
1.907 + throw new NullPointerException("Category cannot be NULL");
1.908 + if (newLocale == null)
1.909 + throw new NullPointerException("Can't set default locale to NULL");
1.910 +
1.911 + SecurityManager sm = System.getSecurityManager();
1.912 + if (sm != null) sm.checkPermission(new PropertyPermission
1.913 + ("user.language", "write"));
1.914 + switch (category) {
1.915 + case DISPLAY:
1.916 + defaultDisplayLocale = newLocale;
1.917 + break;
1.918 + case FORMAT:
1.919 + defaultFormatLocale = newLocale;
1.920 + break;
1.921 + default:
1.922 + assert false: "Unknown Category";
1.923 + }
1.924 + }
1.925 +
1.926 + /**
1.927 + * Returns an array of all installed locales.
1.928 + * The returned array represents the union of locales supported
1.929 + * by the Java runtime environment and by installed
1.930 + * {@link java.util.spi.LocaleServiceProvider LocaleServiceProvider}
1.931 + * implementations. It must contain at least a <code>Locale</code>
1.932 + * instance equal to {@link java.util.Locale#US Locale.US}.
1.933 + *
1.934 + * @return An array of installed locales.
1.935 + */
1.936 + public static Locale[] getAvailableLocales() {
1.937 + return LocaleServiceProviderPool.getAllAvailableLocales();
1.938 + }
1.939 +
1.940 + /**
1.941 + * Returns a list of all 2-letter country codes defined in ISO 3166.
1.942 + * Can be used to create Locales.
1.943 + * <p>
1.944 + * <b>Note:</b> The <code>Locale</code> class also supports other codes for
1.945 + * country (region), such as 3-letter numeric UN M.49 area codes.
1.946 + * Therefore, the list returned by this method does not contain ALL valid
1.947 + * codes that can be used to create Locales.
1.948 + */
1.949 + public static String[] getISOCountries() {
1.950 + if (isoCountries == null) {
1.951 + isoCountries = getISO2Table(LocaleISOData.isoCountryTable);
1.952 + }
1.953 + String[] result = new String[isoCountries.length];
1.954 + System.arraycopy(isoCountries, 0, result, 0, isoCountries.length);
1.955 + return result;
1.956 + }
1.957 +
1.958 + /**
1.959 + * Returns a list of all 2-letter language codes defined in ISO 639.
1.960 + * Can be used to create Locales.
1.961 + * <p>
1.962 + * <b>Note:</b>
1.963 + * <ul>
1.964 + * <li>ISO 639 is not a stable standard— some languages' codes have changed.
1.965 + * The list this function returns includes both the new and the old codes for the
1.966 + * languages whose codes have changed.
1.967 + * <li>The <code>Locale</code> class also supports language codes up to
1.968 + * 8 characters in length. Therefore, the list returned by this method does
1.969 + * not contain ALL valid codes that can be used to create Locales.
1.970 + * </ul>
1.971 + */
1.972 + public static String[] getISOLanguages() {
1.973 + if (isoLanguages == null) {
1.974 + isoLanguages = getISO2Table(LocaleISOData.isoLanguageTable);
1.975 + }
1.976 + String[] result = new String[isoLanguages.length];
1.977 + System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
1.978 + return result;
1.979 + }
1.980 +
1.981 + private static final String[] getISO2Table(String table) {
1.982 + int len = table.length() / 5;
1.983 + String[] isoTable = new String[len];
1.984 + for (int i = 0, j = 0; i < len; i++, j += 5) {
1.985 + isoTable[i] = table.substring(j, j + 2);
1.986 + }
1.987 + return isoTable;
1.988 + }
1.989 +
1.990 + /**
1.991 + * Returns the language code of this Locale.
1.992 + *
1.993 + * <p><b>Note:</b> ISO 639 is not a stable standard— some languages' codes have changed.
1.994 + * Locale's constructor recognizes both the new and the old codes for the languages
1.995 + * whose codes have changed, but this function always returns the old code. If you
1.996 + * want to check for a specific language whose code has changed, don't do
1.997 + * <pre>
1.998 + * if (locale.getLanguage().equals("he")) // BAD!
1.999 + * ...
1.1000 + * </pre>
1.1001 + * Instead, do
1.1002 + * <pre>
1.1003 + * if (locale.getLanguage().equals(new Locale("he").getLanguage()))
1.1004 + * ...
1.1005 + * </pre>
1.1006 + * @return The language code, or the empty string if none is defined.
1.1007 + * @see #getDisplayLanguage
1.1008 + */
1.1009 + public String getLanguage() {
1.1010 + return baseLocale.getLanguage();
1.1011 + }
1.1012 +
1.1013 + /**
1.1014 + * Returns the script for this locale, which should
1.1015 + * either be the empty string or an ISO 15924 4-letter script
1.1016 + * code. The first letter is uppercase and the rest are
1.1017 + * lowercase, for example, 'Latn', 'Cyrl'.
1.1018 + *
1.1019 + * @return The script code, or the empty string if none is defined.
1.1020 + * @see #getDisplayScript
1.1021 + * @since 1.7
1.1022 + */
1.1023 + public String getScript() {
1.1024 + return baseLocale.getScript();
1.1025 + }
1.1026 +
1.1027 + /**
1.1028 + * Returns the country/region code for this locale, which should
1.1029 + * either be the empty string, an uppercase ISO 3166 2-letter code,
1.1030 + * or a UN M.49 3-digit code.
1.1031 + *
1.1032 + * @return The country/region code, or the empty string if none is defined.
1.1033 + * @see #getDisplayCountry
1.1034 + */
1.1035 + public String getCountry() {
1.1036 + return baseLocale.getRegion();
1.1037 + }
1.1038 +
1.1039 + /**
1.1040 + * Returns the variant code for this locale.
1.1041 + *
1.1042 + * @return The variant code, or the empty string if none is defined.
1.1043 + * @see #getDisplayVariant
1.1044 + */
1.1045 + public String getVariant() {
1.1046 + return baseLocale.getVariant();
1.1047 + }
1.1048 +
1.1049 + /**
1.1050 + * Returns the extension (or private use) value associated with
1.1051 + * the specified key, or null if there is no extension
1.1052 + * associated with the key. To be well-formed, the key must be one
1.1053 + * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so
1.1054 + * for example 'z' and 'Z' represent the same extension.
1.1055 + *
1.1056 + * @param key the extension key
1.1057 + * @return The extension, or null if this locale defines no
1.1058 + * extension for the specified key.
1.1059 + * @throws IllegalArgumentException if key is not well-formed
1.1060 + * @see #PRIVATE_USE_EXTENSION
1.1061 + * @see #UNICODE_LOCALE_EXTENSION
1.1062 + * @since 1.7
1.1063 + */
1.1064 + public String getExtension(char key) {
1.1065 + if (!LocaleExtensions.isValidKey(key)) {
1.1066 + throw new IllegalArgumentException("Ill-formed extension key: " + key);
1.1067 + }
1.1068 + return (localeExtensions == null) ? null : localeExtensions.getExtensionValue(key);
1.1069 + }
1.1070 +
1.1071 + /**
1.1072 + * Returns the set of extension keys associated with this locale, or the
1.1073 + * empty set if it has no extensions. The returned set is unmodifiable.
1.1074 + * The keys will all be lower-case.
1.1075 + *
1.1076 + * @return The set of extension keys, or the empty set if this locale has
1.1077 + * no extensions.
1.1078 + * @since 1.7
1.1079 + */
1.1080 + public Set<Character> getExtensionKeys() {
1.1081 + if (localeExtensions == null) {
1.1082 + return Collections.emptySet();
1.1083 + }
1.1084 + return localeExtensions.getKeys();
1.1085 + }
1.1086 +
1.1087 + /**
1.1088 + * Returns the set of unicode locale attributes associated with
1.1089 + * this locale, or the empty set if it has no attributes. The
1.1090 + * returned set is unmodifiable.
1.1091 + *
1.1092 + * @return The set of attributes.
1.1093 + * @since 1.7
1.1094 + */
1.1095 + public Set<String> getUnicodeLocaleAttributes() {
1.1096 + if (localeExtensions == null) {
1.1097 + return Collections.emptySet();
1.1098 + }
1.1099 + return localeExtensions.getUnicodeLocaleAttributes();
1.1100 + }
1.1101 +
1.1102 + /**
1.1103 + * Returns the Unicode locale type associated with the specified Unicode locale key
1.1104 + * for this locale. Returns the empty string for keys that are defined with no type.
1.1105 + * Returns null if the key is not defined. Keys are case-insensitive. The key must
1.1106 + * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is
1.1107 + * thrown.
1.1108 + *
1.1109 + * @param key the Unicode locale key
1.1110 + * @return The Unicode locale type associated with the key, or null if the
1.1111 + * locale does not define the key.
1.1112 + * @throws IllegalArgumentException if the key is not well-formed
1.1113 + * @throws NullPointerException if <code>key</code> is null
1.1114 + * @since 1.7
1.1115 + */
1.1116 + public String getUnicodeLocaleType(String key) {
1.1117 + if (!UnicodeLocaleExtension.isKey(key)) {
1.1118 + throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
1.1119 + }
1.1120 + return (localeExtensions == null) ? null : localeExtensions.getUnicodeLocaleType(key);
1.1121 + }
1.1122 +
1.1123 + /**
1.1124 + * Returns the set of Unicode locale keys defined by this locale, or the empty set if
1.1125 + * this locale has none. The returned set is immutable. Keys are all lower case.
1.1126 + *
1.1127 + * @return The set of Unicode locale keys, or the empty set if this locale has
1.1128 + * no Unicode locale keywords.
1.1129 + * @since 1.7
1.1130 + */
1.1131 + public Set<String> getUnicodeLocaleKeys() {
1.1132 + if (localeExtensions == null) {
1.1133 + return Collections.emptySet();
1.1134 + }
1.1135 + return localeExtensions.getUnicodeLocaleKeys();
1.1136 + }
1.1137 +
1.1138 + /**
1.1139 + * Package locale method returning the Locale's BaseLocale,
1.1140 + * used by ResourceBundle
1.1141 + * @return base locale of this Locale
1.1142 + */
1.1143 + BaseLocale getBaseLocale() {
1.1144 + return baseLocale;
1.1145 + }
1.1146 +
1.1147 + /**
1.1148 + * Package private method returning the Locale's LocaleExtensions,
1.1149 + * used by ResourceBundle.
1.1150 + * @return locale exnteions of this Locale,
1.1151 + * or {@code null} if no extensions are defined
1.1152 + */
1.1153 + LocaleExtensions getLocaleExtensions() {
1.1154 + return localeExtensions;
1.1155 + }
1.1156 +
1.1157 + /**
1.1158 + * Returns a string representation of this <code>Locale</code>
1.1159 + * object, consisting of language, country, variant, script,
1.1160 + * and extensions as below:
1.1161 + * <p><blockquote>
1.1162 + * language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions
1.1163 + * </blockquote>
1.1164 + *
1.1165 + * Language is always lower case, country is always upper case, script is always title
1.1166 + * case, and extensions are always lower case. Extensions and private use subtags
1.1167 + * will be in canonical order as explained in {@link #toLanguageTag}.
1.1168 + *
1.1169 + * <p>When the locale has neither script nor extensions, the result is the same as in
1.1170 + * Java 6 and prior.
1.1171 + *
1.1172 + * <p>If both the language and country fields are missing, this function will return
1.1173 + * the empty string, even if the variant, script, or extensions field is present (you
1.1174 + * can't have a locale with just a variant, the variant must accompany a well-formed
1.1175 + * language or country code).
1.1176 + *
1.1177 + * <p>If script or extensions are present and variant is missing, no underscore is
1.1178 + * added before the "#".
1.1179 + *
1.1180 + * <p>This behavior is designed to support debugging and to be compatible with
1.1181 + * previous uses of <code>toString</code> that expected language, country, and variant
1.1182 + * fields only. To represent a Locale as a String for interchange purposes, use
1.1183 + * {@link #toLanguageTag}.
1.1184 + *
1.1185 + * <p>Examples: <ul><tt>
1.1186 + * <li>en
1.1187 + * <li>de_DE
1.1188 + * <li>_GB
1.1189 + * <li>en_US_WIN
1.1190 + * <li>de__POSIX
1.1191 + * <li>zh_CN_#Hans
1.1192 + * <li>zh_TW_#Hant-x-java
1.1193 + * <li>th_TH_TH_#u-nu-thai</tt></ul>
1.1194 + *
1.1195 + * @return A string representation of the Locale, for debugging.
1.1196 + * @see #getDisplayName
1.1197 + * @see #toLanguageTag
1.1198 + */
1.1199 + @Override
1.1200 + public final String toString() {
1.1201 + boolean l = (baseLocale.getLanguage().length() != 0);
1.1202 + boolean s = (baseLocale.getScript().length() != 0);
1.1203 + boolean r = (baseLocale.getRegion().length() != 0);
1.1204 + boolean v = (baseLocale.getVariant().length() != 0);
1.1205 + boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0);
1.1206 +
1.1207 + StringBuilder result = new StringBuilder(baseLocale.getLanguage());
1.1208 + if (r || (l && (v || s || e))) {
1.1209 + result.append('_')
1.1210 + .append(baseLocale.getRegion()); // This may just append '_'
1.1211 + }
1.1212 + if (v && (l || r)) {
1.1213 + result.append('_')
1.1214 + .append(baseLocale.getVariant());
1.1215 + }
1.1216 +
1.1217 + if (s && (l || r)) {
1.1218 + result.append("_#")
1.1219 + .append(baseLocale.getScript());
1.1220 + }
1.1221 +
1.1222 + if (e && (l || r)) {
1.1223 + result.append('_');
1.1224 + if (!s) {
1.1225 + result.append('#');
1.1226 + }
1.1227 + result.append(localeExtensions.getID());
1.1228 + }
1.1229 +
1.1230 + return result.toString();
1.1231 + }
1.1232 +
1.1233 + /**
1.1234 + * Returns a well-formed IETF BCP 47 language tag representing
1.1235 + * this locale.
1.1236 + *
1.1237 + * <p>If this <code>Locale</code> has a language, country, or
1.1238 + * variant that does not satisfy the IETF BCP 47 language tag
1.1239 + * syntax requirements, this method handles these fields as
1.1240 + * described below:
1.1241 + *
1.1242 + * <p><b>Language:</b> If language is empty, or not <a
1.1243 + * href="#def_language" >well-formed</a> (for example "a" or
1.1244 + * "e2"), it will be emitted as "und" (Undetermined).
1.1245 + *
1.1246 + * <p><b>Country:</b> If country is not <a
1.1247 + * href="#def_region">well-formed</a> (for example "12" or "USA"),
1.1248 + * it will be omitted.
1.1249 + *
1.1250 + * <p><b>Variant:</b> If variant <b>is</b> <a
1.1251 + * href="#def_variant">well-formed</a>, each sub-segment
1.1252 + * (delimited by '-' or '_') is emitted as a subtag. Otherwise:
1.1253 + * <ul>
1.1254 + *
1.1255 + * <li>if all sub-segments match <code>[0-9a-zA-Z]{1,8}</code>
1.1256 + * (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first
1.1257 + * ill-formed sub-segment and all following will be appended to
1.1258 + * the private use subtag. The first appended subtag will be
1.1259 + * "lvariant", followed by the sub-segments in order, separated by
1.1260 + * hyphen. For example, "x-lvariant-WIN",
1.1261 + * "Oracle-x-lvariant-JDK-Standard-Edition".
1.1262 + *
1.1263 + * <li>if any sub-segment does not match
1.1264 + * <code>[0-9a-zA-Z]{1,8}</code>, the variant will be truncated
1.1265 + * and the problematic sub-segment and all following sub-segments
1.1266 + * will be omitted. If the remainder is non-empty, it will be
1.1267 + * emitted as a private use subtag as above (even if the remainder
1.1268 + * turns out to be well-formed). For example,
1.1269 + * "Solaris_isjustthecoolestthing" is emitted as
1.1270 + * "x-lvariant-Solaris", not as "solaris".</li></ul>
1.1271 + *
1.1272 + * <p><b>Special Conversions:</b> Java supports some old locale
1.1273 + * representations, including deprecated ISO language codes,
1.1274 + * for compatibility. This method performs the following
1.1275 + * conversions:
1.1276 + * <ul>
1.1277 + *
1.1278 + * <li>Deprecated ISO language codes "iw", "ji", and "in" are
1.1279 + * converted to "he", "yi", and "id", respectively.
1.1280 + *
1.1281 + * <li>A locale with language "no", country "NO", and variant
1.1282 + * "NY", representing Norwegian Nynorsk (Norway), is converted
1.1283 + * to a language tag "nn-NO".</li></ul>
1.1284 + *
1.1285 + * <p><b>Note:</b> Although the language tag created by this
1.1286 + * method is well-formed (satisfies the syntax requirements
1.1287 + * defined by the IETF BCP 47 specification), it is not
1.1288 + * necessarily a valid BCP 47 language tag. For example,
1.1289 + * <pre>
1.1290 + * new Locale("xx", "YY").toLanguageTag();</pre>
1.1291 + *
1.1292 + * will return "xx-YY", but the language subtag "xx" and the
1.1293 + * region subtag "YY" are invalid because they are not registered
1.1294 + * in the IANA Language Subtag Registry.
1.1295 + *
1.1296 + * @return a BCP47 language tag representing the locale
1.1297 + * @see #forLanguageTag(String)
1.1298 + * @since 1.7
1.1299 + */
1.1300 + public String toLanguageTag() {
1.1301 + LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
1.1302 + StringBuilder buf = new StringBuilder();
1.1303 +
1.1304 + String subtag = tag.getLanguage();
1.1305 + if (subtag.length() > 0) {
1.1306 + buf.append(LanguageTag.canonicalizeLanguage(subtag));
1.1307 + }
1.1308 +
1.1309 + subtag = tag.getScript();
1.1310 + if (subtag.length() > 0) {
1.1311 + buf.append(LanguageTag.SEP);
1.1312 + buf.append(LanguageTag.canonicalizeScript(subtag));
1.1313 + }
1.1314 +
1.1315 + subtag = tag.getRegion();
1.1316 + if (subtag.length() > 0) {
1.1317 + buf.append(LanguageTag.SEP);
1.1318 + buf.append(LanguageTag.canonicalizeRegion(subtag));
1.1319 + }
1.1320 +
1.1321 + List<String>subtags = tag.getVariants();
1.1322 + for (String s : subtags) {
1.1323 + buf.append(LanguageTag.SEP);
1.1324 + // preserve casing
1.1325 + buf.append(s);
1.1326 + }
1.1327 +
1.1328 + subtags = tag.getExtensions();
1.1329 + for (String s : subtags) {
1.1330 + buf.append(LanguageTag.SEP);
1.1331 + buf.append(LanguageTag.canonicalizeExtension(s));
1.1332 + }
1.1333 +
1.1334 + subtag = tag.getPrivateuse();
1.1335 + if (subtag.length() > 0) {
1.1336 + if (buf.length() > 0) {
1.1337 + buf.append(LanguageTag.SEP);
1.1338 + }
1.1339 + buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
1.1340 + // preserve casing
1.1341 + buf.append(subtag);
1.1342 + }
1.1343 +
1.1344 + return buf.toString();
1.1345 + }
1.1346 +
1.1347 + /**
1.1348 + * Returns a locale for the specified IETF BCP 47 language tag string.
1.1349 + *
1.1350 + * <p>If the specified language tag contains any ill-formed subtags,
1.1351 + * the first such subtag and all following subtags are ignored. Compare
1.1352 + * to {@link Locale.Builder#setLanguageTag} which throws an exception
1.1353 + * in this case.
1.1354 + *
1.1355 + * <p>The following <b>conversions</b> are performed:<ul>
1.1356 + *
1.1357 + * <li>The language code "und" is mapped to language "".
1.1358 + *
1.1359 + * <li>The language codes "he", "yi", and "id" are mapped to "iw",
1.1360 + * "ji", and "in" respectively. (This is the same canonicalization
1.1361 + * that's done in Locale's constructors.)
1.1362 + *
1.1363 + * <li>The portion of a private use subtag prefixed by "lvariant",
1.1364 + * if any, is removed and appended to the variant field in the
1.1365 + * result locale (without case normalization). If it is then
1.1366 + * empty, the private use subtag is discarded:
1.1367 + *
1.1368 + * <pre>
1.1369 + * Locale loc;
1.1370 + * loc = Locale.forLanguageTag("en-US-x-lvariant-POSIX");
1.1371 + * loc.getVariant(); // returns "POSIX"
1.1372 + * loc.getExtension('x'); // returns null
1.1373 + *
1.1374 + * loc = Locale.forLanguageTag("de-POSIX-x-URP-lvariant-Abc-Def");
1.1375 + * loc.getVariant(); // returns "POSIX_Abc_Def"
1.1376 + * loc.getExtension('x'); // returns "urp"
1.1377 + * </pre>
1.1378 + *
1.1379 + * <li>When the languageTag argument contains an extlang subtag,
1.1380 + * the first such subtag is used as the language, and the primary
1.1381 + * language subtag and other extlang subtags are ignored:
1.1382 + *
1.1383 + * <pre>
1.1384 + * Locale.forLanguageTag("ar-aao").getLanguage(); // returns "aao"
1.1385 + * Locale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US"
1.1386 + * </pre>
1.1387 + *
1.1388 + * <li>Case is normalized except for variant tags, which are left
1.1389 + * unchanged. Language is normalized to lower case, script to
1.1390 + * title case, country to upper case, and extensions to lower
1.1391 + * case.
1.1392 + *
1.1393 + * <li>If, after processing, the locale would exactly match either
1.1394 + * ja_JP_JP or th_TH_TH with no extensions, the appropriate
1.1395 + * extensions are added as though the constructor had been called:
1.1396 + *
1.1397 + * <pre>
1.1398 + * Locale.forLanguageTag("ja-JP-x-lvariant-JP").toLanguageTag();
1.1399 + * // returns "ja-JP-u-ca-japanese-x-lvariant-JP"
1.1400 + * Locale.forLanguageTag("th-TH-x-lvariant-TH").toLanguageTag();
1.1401 + * // returns "th-TH-u-nu-thai-x-lvariant-TH"
1.1402 + * <pre></ul>
1.1403 + *
1.1404 + * <p>This implements the 'Language-Tag' production of BCP47, and
1.1405 + * so supports grandfathered (regular and irregular) as well as
1.1406 + * private use language tags. Stand alone private use tags are
1.1407 + * represented as empty language and extension 'x-whatever',
1.1408 + * and grandfathered tags are converted to their canonical replacements
1.1409 + * where they exist.
1.1410 + *
1.1411 + * <p>Grandfathered tags with canonical replacements are as follows:
1.1412 + *
1.1413 + * <table>
1.1414 + * <tbody align="center">
1.1415 + * <tr><th>grandfathered tag</th><th> </th><th>modern replacement</th></tr>
1.1416 + * <tr><td>art-lojban</td><td> </td><td>jbo</td></tr>
1.1417 + * <tr><td>i-ami</td><td> </td><td>ami</td></tr>
1.1418 + * <tr><td>i-bnn</td><td> </td><td>bnn</td></tr>
1.1419 + * <tr><td>i-hak</td><td> </td><td>hak</td></tr>
1.1420 + * <tr><td>i-klingon</td><td> </td><td>tlh</td></tr>
1.1421 + * <tr><td>i-lux</td><td> </td><td>lb</td></tr>
1.1422 + * <tr><td>i-navajo</td><td> </td><td>nv</td></tr>
1.1423 + * <tr><td>i-pwn</td><td> </td><td>pwn</td></tr>
1.1424 + * <tr><td>i-tao</td><td> </td><td>tao</td></tr>
1.1425 + * <tr><td>i-tay</td><td> </td><td>tay</td></tr>
1.1426 + * <tr><td>i-tsu</td><td> </td><td>tsu</td></tr>
1.1427 + * <tr><td>no-bok</td><td> </td><td>nb</td></tr>
1.1428 + * <tr><td>no-nyn</td><td> </td><td>nn</td></tr>
1.1429 + * <tr><td>sgn-BE-FR</td><td> </td><td>sfb</td></tr>
1.1430 + * <tr><td>sgn-BE-NL</td><td> </td><td>vgt</td></tr>
1.1431 + * <tr><td>sgn-CH-DE</td><td> </td><td>sgg</td></tr>
1.1432 + * <tr><td>zh-guoyu</td><td> </td><td>cmn</td></tr>
1.1433 + * <tr><td>zh-hakka</td><td> </td><td>hak</td></tr>
1.1434 + * <tr><td>zh-min-nan</td><td> </td><td>nan</td></tr>
1.1435 + * <tr><td>zh-xiang</td><td> </td><td>hsn</td></tr>
1.1436 + * </tbody>
1.1437 + * </table>
1.1438 + *
1.1439 + * <p>Grandfathered tags with no modern replacement will be
1.1440 + * converted as follows:
1.1441 + *
1.1442 + * <table>
1.1443 + * <tbody align="center">
1.1444 + * <tr><th>grandfathered tag</th><th> </th><th>converts to</th></tr>
1.1445 + * <tr><td>cel-gaulish</td><td> </td><td>xtg-x-cel-gaulish</td></tr>
1.1446 + * <tr><td>en-GB-oed</td><td> </td><td>en-GB-x-oed</td></tr>
1.1447 + * <tr><td>i-default</td><td> </td><td>en-x-i-default</td></tr>
1.1448 + * <tr><td>i-enochian</td><td> </td><td>und-x-i-enochian</td></tr>
1.1449 + * <tr><td>i-mingo</td><td> </td><td>see-x-i-mingo</td></tr>
1.1450 + * <tr><td>zh-min</td><td> </td><td>nan-x-zh-min</td></tr>
1.1451 + * </tbody>
1.1452 + * </table>
1.1453 + *
1.1454 + * <p>For a list of all grandfathered tags, see the
1.1455 + * IANA Language Subtag Registry (search for "Type: grandfathered").
1.1456 + *
1.1457 + * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>
1.1458 + * and <code>forLanguageTag</code> will round-trip.
1.1459 + *
1.1460 + * @param languageTag the language tag
1.1461 + * @return The locale that best represents the language tag.
1.1462 + * @throws NullPointerException if <code>languageTag</code> is <code>null</code>
1.1463 + * @see #toLanguageTag()
1.1464 + * @see java.util.Locale.Builder#setLanguageTag(String)
1.1465 + * @since 1.7
1.1466 + */
1.1467 + public static Locale forLanguageTag(String languageTag) {
1.1468 + LanguageTag tag = LanguageTag.parse(languageTag, null);
1.1469 + InternalLocaleBuilder bldr = new InternalLocaleBuilder();
1.1470 + bldr.setLanguageTag(tag);
1.1471 + BaseLocale base = bldr.getBaseLocale();
1.1472 + LocaleExtensions exts = bldr.getLocaleExtensions();
1.1473 + if (exts == null && base.getVariant().length() > 0) {
1.1474 + exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
1.1475 + base.getRegion(), base.getVariant());
1.1476 + }
1.1477 + return getInstance(base, exts);
1.1478 + }
1.1479 +
1.1480 + /**
1.1481 + * Returns a three-letter abbreviation of this locale's language.
1.1482 + * If the language matches an ISO 639-1 two-letter code, the
1.1483 + * corresponding ISO 639-2/T three-letter lowercase code is
1.1484 + * returned. The ISO 639-2 language codes can be found on-line,
1.1485 + * see "Codes for the Representation of Names of Languages Part 2:
1.1486 + * Alpha-3 Code". If the locale specifies a three-letter
1.1487 + * language, the language is returned as is. If the locale does
1.1488 + * not specify a language the empty string is returned.
1.1489 + *
1.1490 + * @return A three-letter abbreviation of this locale's language.
1.1491 + * @exception MissingResourceException Throws MissingResourceException if
1.1492 + * three-letter language abbreviation is not available for this locale.
1.1493 + */
1.1494 + public String getISO3Language() throws MissingResourceException {
1.1495 + String lang = baseLocale.getLanguage();
1.1496 + if (lang.length() == 3) {
1.1497 + return lang;
1.1498 + }
1.1499 +
1.1500 + String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
1.1501 + if (language3 == null) {
1.1502 + throw new MissingResourceException("Couldn't find 3-letter language code for "
1.1503 + + lang, "FormatData_" + toString(), "ShortLanguage");
1.1504 + }
1.1505 + return language3;
1.1506 + }
1.1507 +
1.1508 + /**
1.1509 + * Returns a three-letter abbreviation for this locale's country.
1.1510 + * If the country matches an ISO 3166-1 alpha-2 code, the
1.1511 + * corresponding ISO 3166-1 alpha-3 uppercase code is returned.
1.1512 + * If the locale doesn't specify a country, this will be the empty
1.1513 + * string.
1.1514 + *
1.1515 + * <p>The ISO 3166-1 codes can be found on-line.
1.1516 + *
1.1517 + * @return A three-letter abbreviation of this locale's country.
1.1518 + * @exception MissingResourceException Throws MissingResourceException if the
1.1519 + * three-letter country abbreviation is not available for this locale.
1.1520 + */
1.1521 + public String getISO3Country() throws MissingResourceException {
1.1522 + String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
1.1523 + if (country3 == null) {
1.1524 + throw new MissingResourceException("Couldn't find 3-letter country code for "
1.1525 + + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
1.1526 + }
1.1527 + return country3;
1.1528 + }
1.1529 +
1.1530 + private static final String getISO3Code(String iso2Code, String table) {
1.1531 + int codeLength = iso2Code.length();
1.1532 + if (codeLength == 0) {
1.1533 + return "";
1.1534 + }
1.1535 +
1.1536 + int tableLength = table.length();
1.1537 + int index = tableLength;
1.1538 + if (codeLength == 2) {
1.1539 + char c1 = iso2Code.charAt(0);
1.1540 + char c2 = iso2Code.charAt(1);
1.1541 + for (index = 0; index < tableLength; index += 5) {
1.1542 + if (table.charAt(index) == c1
1.1543 + && table.charAt(index + 1) == c2) {
1.1544 + break;
1.1545 + }
1.1546 + }
1.1547 + }
1.1548 + return index < tableLength ? table.substring(index + 2, index + 5) : null;
1.1549 + }
1.1550 +
1.1551 + /**
1.1552 + * Returns a name for the locale's language that is appropriate for display to the
1.1553 + * user.
1.1554 + * If possible, the name returned will be localized for the default locale.
1.1555 + * For example, if the locale is fr_FR and the default locale
1.1556 + * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
1.1557 + * the default locale is fr_FR, getDisplayLanguage() will return "anglais".
1.1558 + * If the name returned cannot be localized for the default locale,
1.1559 + * (say, we don't have a Japanese name for Croatian),
1.1560 + * this function falls back on the English name, and uses the ISO code as a last-resort
1.1561 + * value. If the locale doesn't specify a language, this function returns the empty string.
1.1562 + */
1.1563 + public final String getDisplayLanguage() {
1.1564 + return getDisplayLanguage(getDefault(Category.DISPLAY));
1.1565 + }
1.1566 +
1.1567 + /**
1.1568 + * Returns a name for the locale's language that is appropriate for display to the
1.1569 + * user.
1.1570 + * If possible, the name returned will be localized according to inLocale.
1.1571 + * For example, if the locale is fr_FR and inLocale
1.1572 + * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
1.1573 + * inLocale is fr_FR, getDisplayLanguage() will return "anglais".
1.1574 + * If the name returned cannot be localized according to inLocale,
1.1575 + * (say, we don't have a Japanese name for Croatian),
1.1576 + * this function falls back on the English name, and finally
1.1577 + * on the ISO code as a last-resort value. If the locale doesn't specify a language,
1.1578 + * this function returns the empty string.
1.1579 + *
1.1580 + * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1.1581 + */
1.1582 + public String getDisplayLanguage(Locale inLocale) {
1.1583 + return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE);
1.1584 + }
1.1585 +
1.1586 + /**
1.1587 + * Returns a name for the the locale's script that is appropriate for display to
1.1588 + * the user. If possible, the name will be localized for the default locale. Returns
1.1589 + * the empty string if this locale doesn't specify a script code.
1.1590 + *
1.1591 + * @return the display name of the script code for the current default locale
1.1592 + * @since 1.7
1.1593 + */
1.1594 + public String getDisplayScript() {
1.1595 + return getDisplayScript(getDefault());
1.1596 + }
1.1597 +
1.1598 + /**
1.1599 + * Returns a name for the locale's script that is appropriate
1.1600 + * for display to the user. If possible, the name will be
1.1601 + * localized for the given locale. Returns the empty string if
1.1602 + * this locale doesn't specify a script code.
1.1603 + *
1.1604 + * @return the display name of the script code for the current default locale
1.1605 + * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1.1606 + * @since 1.7
1.1607 + */
1.1608 + public String getDisplayScript(Locale inLocale) {
1.1609 + return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT);
1.1610 + }
1.1611 +
1.1612 + /**
1.1613 + * Returns a name for the locale's country that is appropriate for display to the
1.1614 + * user.
1.1615 + * If possible, the name returned will be localized for the default locale.
1.1616 + * For example, if the locale is fr_FR and the default locale
1.1617 + * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
1.1618 + * the default locale is fr_FR, getDisplayCountry() will return "Etats-Unis".
1.1619 + * If the name returned cannot be localized for the default locale,
1.1620 + * (say, we don't have a Japanese name for Croatia),
1.1621 + * this function falls back on the English name, and uses the ISO code as a last-resort
1.1622 + * value. If the locale doesn't specify a country, this function returns the empty string.
1.1623 + */
1.1624 + public final String getDisplayCountry() {
1.1625 + return getDisplayCountry(getDefault(Category.DISPLAY));
1.1626 + }
1.1627 +
1.1628 + /**
1.1629 + * Returns a name for the locale's country that is appropriate for display to the
1.1630 + * user.
1.1631 + * If possible, the name returned will be localized according to inLocale.
1.1632 + * For example, if the locale is fr_FR and inLocale
1.1633 + * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
1.1634 + * inLocale is fr_FR, getDisplayCountry() will return "Etats-Unis".
1.1635 + * If the name returned cannot be localized according to inLocale.
1.1636 + * (say, we don't have a Japanese name for Croatia),
1.1637 + * this function falls back on the English name, and finally
1.1638 + * on the ISO code as a last-resort value. If the locale doesn't specify a country,
1.1639 + * this function returns the empty string.
1.1640 + *
1.1641 + * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1.1642 + */
1.1643 + public String getDisplayCountry(Locale inLocale) {
1.1644 + return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY);
1.1645 + }
1.1646 +
1.1647 + private String getDisplayString(String code, Locale inLocale, int type) {
1.1648 + if (code.length() == 0) {
1.1649 + return "";
1.1650 + }
1.1651 +
1.1652 + if (inLocale == null) {
1.1653 + throw new NullPointerException();
1.1654 + }
1.1655 +
1.1656 + try {
1.1657 + OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1.1658 + String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
1.1659 + String result = null;
1.1660 +
1.1661 + // Check whether a provider can provide an implementation that's closer
1.1662 + // to the requested locale than what the Java runtime itself can provide.
1.1663 + LocaleServiceProviderPool pool =
1.1664 + LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
1.1665 + if (pool.hasProviders()) {
1.1666 + result = pool.getLocalizedObject(
1.1667 + LocaleNameGetter.INSTANCE,
1.1668 + inLocale, bundle, key,
1.1669 + type, code);
1.1670 + }
1.1671 +
1.1672 + if (result == null) {
1.1673 + result = bundle.getString(key);
1.1674 + }
1.1675 +
1.1676 + if (result != null) {
1.1677 + return result;
1.1678 + }
1.1679 + }
1.1680 + catch (Exception e) {
1.1681 + // just fall through
1.1682 + }
1.1683 + return code;
1.1684 + }
1.1685 +
1.1686 + /**
1.1687 + * Returns a name for the locale's variant code that is appropriate for display to the
1.1688 + * user. If possible, the name will be localized for the default locale. If the locale
1.1689 + * doesn't specify a variant code, this function returns the empty string.
1.1690 + */
1.1691 + public final String getDisplayVariant() {
1.1692 + return getDisplayVariant(getDefault(Category.DISPLAY));
1.1693 + }
1.1694 +
1.1695 + /**
1.1696 + * Returns a name for the locale's variant code that is appropriate for display to the
1.1697 + * user. If possible, the name will be localized for inLocale. If the locale
1.1698 + * doesn't specify a variant code, this function returns the empty string.
1.1699 + *
1.1700 + * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1.1701 + */
1.1702 + public String getDisplayVariant(Locale inLocale) {
1.1703 + if (baseLocale.getVariant().length() == 0)
1.1704 + return "";
1.1705 +
1.1706 + OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1.1707 +
1.1708 + String names[] = getDisplayVariantArray(bundle, inLocale);
1.1709 +
1.1710 + // Get the localized patterns for formatting a list, and use
1.1711 + // them to format the list.
1.1712 + String listPattern = null;
1.1713 + String listCompositionPattern = null;
1.1714 + try {
1.1715 + listPattern = bundle.getString("ListPattern");
1.1716 + listCompositionPattern = bundle.getString("ListCompositionPattern");
1.1717 + } catch (MissingResourceException e) {
1.1718 + }
1.1719 + return formatList(names, listPattern, listCompositionPattern);
1.1720 + }
1.1721 +
1.1722 + /**
1.1723 + * Returns a name for the locale that is appropriate for display to the
1.1724 + * user. This will be the values returned by getDisplayLanguage(),
1.1725 + * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled
1.1726 + * into a single string. The the non-empty values are used in order,
1.1727 + * with the second and subsequent names in parentheses. For example:
1.1728 + * <blockquote>
1.1729 + * language (script, country, variant)<br>
1.1730 + * language (country)<br>
1.1731 + * language (variant)<br>
1.1732 + * script (country)<br>
1.1733 + * country<br>
1.1734 + * </blockquote>
1.1735 + * depending on which fields are specified in the locale. If the
1.1736 + * language, sacript, country, and variant fields are all empty,
1.1737 + * this function returns the empty string.
1.1738 + */
1.1739 + public final String getDisplayName() {
1.1740 + return getDisplayName(getDefault(Category.DISPLAY));
1.1741 + }
1.1742 +
1.1743 + /**
1.1744 + * Returns a name for the locale that is appropriate for display
1.1745 + * to the user. This will be the values returned by
1.1746 + * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(),
1.1747 + * and getDisplayVariant() assembled into a single string.
1.1748 + * The non-empty values are used in order,
1.1749 + * with the second and subsequent names in parentheses. For example:
1.1750 + * <blockquote>
1.1751 + * language (script, country, variant)<br>
1.1752 + * language (country)<br>
1.1753 + * language (variant)<br>
1.1754 + * script (country)<br>
1.1755 + * country<br>
1.1756 + * </blockquote>
1.1757 + * depending on which fields are specified in the locale. If the
1.1758 + * language, script, country, and variant fields are all empty,
1.1759 + * this function returns the empty string.
1.1760 + *
1.1761 + * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1.1762 + */
1.1763 + public String getDisplayName(Locale inLocale) {
1.1764 + OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1.1765 +
1.1766 + String languageName = getDisplayLanguage(inLocale);
1.1767 + String scriptName = getDisplayScript(inLocale);
1.1768 + String countryName = getDisplayCountry(inLocale);
1.1769 + String[] variantNames = getDisplayVariantArray(bundle, inLocale);
1.1770 +
1.1771 + // Get the localized patterns for formatting a display name.
1.1772 + String displayNamePattern = null;
1.1773 + String listPattern = null;
1.1774 + String listCompositionPattern = null;
1.1775 + try {
1.1776 + displayNamePattern = bundle.getString("DisplayNamePattern");
1.1777 + listPattern = bundle.getString("ListPattern");
1.1778 + listCompositionPattern = bundle.getString("ListCompositionPattern");
1.1779 + } catch (MissingResourceException e) {
1.1780 + }
1.1781 +
1.1782 + // The display name consists of a main name, followed by qualifiers.
1.1783 + // Typically, the format is "MainName (Qualifier, Qualifier)" but this
1.1784 + // depends on what pattern is stored in the display locale.
1.1785 + String mainName = null;
1.1786 + String[] qualifierNames = null;
1.1787 +
1.1788 + // The main name is the language, or if there is no language, the script,
1.1789 + // then if no script, the country. If there is no language/script/country
1.1790 + // (an anomalous situation) then the display name is simply the variant's
1.1791 + // display name.
1.1792 + if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
1.1793 + if (variantNames.length == 0) {
1.1794 + return "";
1.1795 + } else {
1.1796 + return formatList(variantNames, listPattern, listCompositionPattern);
1.1797 + }
1.1798 + }
1.1799 + ArrayList<String> names = new ArrayList<>(4);
1.1800 + if (languageName.length() != 0) {
1.1801 + names.add(languageName);
1.1802 + }
1.1803 + if (scriptName.length() != 0) {
1.1804 + names.add(scriptName);
1.1805 + }
1.1806 + if (countryName.length() != 0) {
1.1807 + names.add(countryName);
1.1808 + }
1.1809 + if (variantNames.length != 0) {
1.1810 + for (String var : variantNames) {
1.1811 + names.add(var);
1.1812 + }
1.1813 + }
1.1814 +
1.1815 + // The first one in the main name
1.1816 + mainName = names.get(0);
1.1817 +
1.1818 + // Others are qualifiers
1.1819 + int numNames = names.size();
1.1820 + qualifierNames = (numNames > 1) ?
1.1821 + names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
1.1822 +
1.1823 + // Create an array whose first element is the number of remaining
1.1824 + // elements. This serves as a selector into a ChoiceFormat pattern from
1.1825 + // the resource. The second and third elements are the main name and
1.1826 + // the qualifier; if there are no qualifiers, the third element is
1.1827 + // unused by the format pattern.
1.1828 + Object[] displayNames = {
1.1829 + new Integer(qualifierNames.length != 0 ? 2 : 1),
1.1830 + mainName,
1.1831 + // We could also just call formatList() and have it handle the empty
1.1832 + // list case, but this is more efficient, and we want it to be
1.1833 + // efficient since all the language-only locales will not have any
1.1834 + // qualifiers.
1.1835 + qualifierNames.length != 0 ? formatList(qualifierNames, listPattern, listCompositionPattern) : null
1.1836 + };
1.1837 +
1.1838 + if (displayNamePattern != null) {
1.1839 + return new MessageFormat(displayNamePattern).format(displayNames);
1.1840 + }
1.1841 + else {
1.1842 + // If we cannot get the message format pattern, then we use a simple
1.1843 + // hard-coded pattern. This should not occur in practice unless the
1.1844 + // installation is missing some core files (FormatData etc.).
1.1845 + StringBuilder result = new StringBuilder();
1.1846 + result.append((String)displayNames[1]);
1.1847 + if (displayNames.length > 2) {
1.1848 + result.append(" (");
1.1849 + result.append((String)displayNames[2]);
1.1850 + result.append(')');
1.1851 + }
1.1852 + return result.toString();
1.1853 + }
1.1854 + }
1.1855 +
1.1856 + /**
1.1857 + * Overrides Cloneable.
1.1858 + */
1.1859 + public Object clone()
1.1860 + {
1.1861 + try {
1.1862 + Locale that = (Locale)super.clone();
1.1863 + return that;
1.1864 + } catch (CloneNotSupportedException e) {
1.1865 + throw new InternalError();
1.1866 + }
1.1867 + }
1.1868 +
1.1869 + /**
1.1870 + * Override hashCode.
1.1871 + * Since Locales are often used in hashtables, caches the value
1.1872 + * for speed.
1.1873 + */
1.1874 + @Override
1.1875 + public int hashCode() {
1.1876 + int hc = hashCodeValue;
1.1877 + if (hc == 0) {
1.1878 + hc = baseLocale.hashCode();
1.1879 + if (localeExtensions != null) {
1.1880 + hc ^= localeExtensions.hashCode();
1.1881 + }
1.1882 + hashCodeValue = hc;
1.1883 + }
1.1884 + return hc;
1.1885 + }
1.1886 +
1.1887 + // Overrides
1.1888 +
1.1889 + /**
1.1890 + * Returns true if this Locale is equal to another object. A Locale is
1.1891 + * deemed equal to another Locale with identical language, script, country,
1.1892 + * variant and extensions, and unequal to all other objects.
1.1893 + *
1.1894 + * @return true if this Locale is equal to the specified object.
1.1895 + */
1.1896 + @Override
1.1897 + public boolean equals(Object obj) {
1.1898 + if (this == obj) // quick check
1.1899 + return true;
1.1900 + if (!(obj instanceof Locale))
1.1901 + return false;
1.1902 + BaseLocale otherBase = ((Locale)obj).baseLocale;
1.1903 + if (!baseLocale.equals(otherBase)) {
1.1904 + return false;
1.1905 + }
1.1906 + if (localeExtensions == null) {
1.1907 + return ((Locale)obj).localeExtensions == null;
1.1908 + }
1.1909 + return localeExtensions.equals(((Locale)obj).localeExtensions);
1.1910 + }
1.1911 +
1.1912 + // ================= privates =====================================
1.1913 +
1.1914 + private transient BaseLocale baseLocale;
1.1915 + private transient LocaleExtensions localeExtensions;
1.1916 +
1.1917 + /**
1.1918 + * Calculated hashcode
1.1919 + */
1.1920 + private transient volatile int hashCodeValue = 0;
1.1921 +
1.1922 + private static Locale defaultLocale = null;
1.1923 + private static Locale defaultDisplayLocale = null;
1.1924 + private static Locale defaultFormatLocale = null;
1.1925 +
1.1926 + /**
1.1927 + * Return an array of the display names of the variant.
1.1928 + * @param bundle the ResourceBundle to use to get the display names
1.1929 + * @return an array of display names, possible of zero length.
1.1930 + */
1.1931 + private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) {
1.1932 + // Split the variant name into tokens separated by '_'.
1.1933 + StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
1.1934 + String[] names = new String[tokenizer.countTokens()];
1.1935 +
1.1936 + // For each variant token, lookup the display name. If
1.1937 + // not found, use the variant name itself.
1.1938 + for (int i=0; i<names.length; ++i) {
1.1939 + names[i] = getDisplayString(tokenizer.nextToken(),
1.1940 + inLocale, DISPLAY_VARIANT);
1.1941 + }
1.1942 +
1.1943 + return names;
1.1944 + }
1.1945 +
1.1946 + /**
1.1947 + * Format a list using given pattern strings.
1.1948 + * If either of the patterns is null, then a the list is
1.1949 + * formatted by concatenation with the delimiter ','.
1.1950 + * @param stringList the list of strings to be formatted.
1.1951 + * @param listPattern should create a MessageFormat taking 0-3 arguments
1.1952 + * and formatting them into a list.
1.1953 + * @param listCompositionPattern should take 2 arguments
1.1954 + * and is used by composeList.
1.1955 + * @return a string representing the list.
1.1956 + */
1.1957 + private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
1.1958 + // If we have no list patterns, compose the list in a simple,
1.1959 + // non-localized way.
1.1960 + if (listPattern == null || listCompositionPattern == null) {
1.1961 + StringBuffer result = new StringBuffer();
1.1962 + for (int i=0; i<stringList.length; ++i) {
1.1963 + if (i>0) result.append(',');
1.1964 + result.append(stringList[i]);
1.1965 + }
1.1966 + return result.toString();
1.1967 + }
1.1968 +
1.1969 + // Compose the list down to three elements if necessary
1.1970 + if (stringList.length > 3) {
1.1971 + MessageFormat format = new MessageFormat(listCompositionPattern);
1.1972 + stringList = composeList(format, stringList);
1.1973 + }
1.1974 +
1.1975 + // Rebuild the argument list with the list length as the first element
1.1976 + Object[] args = new Object[stringList.length + 1];
1.1977 + System.arraycopy(stringList, 0, args, 1, stringList.length);
1.1978 + args[0] = new Integer(stringList.length);
1.1979 +
1.1980 + // Format it using the pattern in the resource
1.1981 + MessageFormat format = new MessageFormat(listPattern);
1.1982 + return format.format(args);
1.1983 + }
1.1984 +
1.1985 + /**
1.1986 + * Given a list of strings, return a list shortened to three elements.
1.1987 + * Shorten it by applying the given format to the first two elements
1.1988 + * recursively.
1.1989 + * @param format a format which takes two arguments
1.1990 + * @param list a list of strings
1.1991 + * @return if the list is three elements or shorter, the same list;
1.1992 + * otherwise, a new list of three elements.
1.1993 + */
1.1994 + private static String[] composeList(MessageFormat format, String[] list) {
1.1995 + if (list.length <= 3) return list;
1.1996 +
1.1997 + // Use the given format to compose the first two elements into one
1.1998 + String[] listItems = { list[0], list[1] };
1.1999 + String newItem = format.format(listItems);
1.2000 +
1.2001 + // Form a new list one element shorter
1.2002 + String[] newList = new String[list.length-1];
1.2003 + System.arraycopy(list, 2, newList, 1, newList.length-1);
1.2004 + newList[0] = newItem;
1.2005 +
1.2006 + // Recurse
1.2007 + return composeList(format, newList);
1.2008 + }
1.2009 +
1.2010 + /**
1.2011 + * @serialField language String
1.2012 + * language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
1.2013 + * @serialField country String
1.2014 + * country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
1.2015 + * @serialField variant String
1.2016 + * variant subtags separated by LOWLINE characters. (See <a href="java/util/Locale.html#getVariant()">getVariant()</a>)
1.2017 + * @serialField hashcode int
1.2018 + * deprecated, for forward compatibility only
1.2019 + * @serialField script String
1.2020 + * script subtag in title case (See <a href="java/util/Locale.html#getScript()">getScript()</a>)
1.2021 + * @serialField extensions String
1.2022 + * canonical representation of extensions, that is,
1.2023 + * BCP47 extensions in alphabetical order followed by
1.2024 + * BCP47 private use subtags, all in lower case letters
1.2025 + * separated by HYPHEN-MINUS characters.
1.2026 + * (See <a href="java/util/Locale.html#getExtensionKeys()">getExtensionKeys()</a>,
1.2027 + * <a href="java/util/Locale.html#getExtension(char)">getExtension(char)</a>)
1.2028 + */
1.2029 + private static final ObjectStreamField[] serialPersistentFields = {
1.2030 + new ObjectStreamField("language", String.class),
1.2031 + new ObjectStreamField("country", String.class),
1.2032 + new ObjectStreamField("variant", String.class),
1.2033 + new ObjectStreamField("hashcode", int.class),
1.2034 + new ObjectStreamField("script", String.class),
1.2035 + new ObjectStreamField("extensions", String.class),
1.2036 + };
1.2037 +
1.2038 + /**
1.2039 + * Serializes this <code>Locale</code> to the specified <code>ObjectOutputStream</code>.
1.2040 + * @param out the <code>ObjectOutputStream</code> to write
1.2041 + * @throws IOException
1.2042 + * @since 1.7
1.2043 + */
1.2044 + private void writeObject(ObjectOutputStream out) throws IOException {
1.2045 + ObjectOutputStream.PutField fields = out.putFields();
1.2046 + fields.put("language", baseLocale.getLanguage());
1.2047 + fields.put("script", baseLocale.getScript());
1.2048 + fields.put("country", baseLocale.getRegion());
1.2049 + fields.put("variant", baseLocale.getVariant());
1.2050 + fields.put("extensions", localeExtensions == null ? "" : localeExtensions.getID());
1.2051 + fields.put("hashcode", -1); // place holder just for backward support
1.2052 + out.writeFields();
1.2053 + }
1.2054 +
1.2055 + /**
1.2056 + * Deserializes this <code>Locale</code>.
1.2057 + * @param in the <code>ObjectInputStream</code> to read
1.2058 + * @throws IOException
1.2059 + * @throws ClassNotFoundException
1.2060 + * @throws IllformdLocaleException
1.2061 + * @since 1.7
1.2062 + */
1.2063 + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1.2064 + ObjectInputStream.GetField fields = in.readFields();
1.2065 + String language = (String)fields.get("language", "");
1.2066 + String script = (String)fields.get("script", "");
1.2067 + String country = (String)fields.get("country", "");
1.2068 + String variant = (String)fields.get("variant", "");
1.2069 + String extStr = (String)fields.get("extensions", "");
1.2070 + baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
1.2071 + if (extStr.length() > 0) {
1.2072 + try {
1.2073 + InternalLocaleBuilder bldr = new InternalLocaleBuilder();
1.2074 + bldr.setExtensions(extStr);
1.2075 + localeExtensions = bldr.getLocaleExtensions();
1.2076 + } catch (LocaleSyntaxException e) {
1.2077 + throw new IllformedLocaleException(e.getMessage());
1.2078 + }
1.2079 + } else {
1.2080 + localeExtensions = null;
1.2081 + }
1.2082 + }
1.2083 +
1.2084 + /**
1.2085 + * Returns a cached <code>Locale</code> instance equivalent to
1.2086 + * the deserialized <code>Locale</code>. When serialized
1.2087 + * language, country and variant fields read from the object data stream
1.2088 + * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
1.2089 + * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>
1.2090 + * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
1.2091 + * type is "thai"). See <a href="Locale.html#special_cases_constructor"/>Special Cases</a>
1.2092 + * for more information.
1.2093 + *
1.2094 + * @return an instance of <code>Locale</code> equivalent to
1.2095 + * the deserialized <code>Locale</code>.
1.2096 + * @throws java.io.ObjectStreamException
1.2097 + */
1.2098 + private Object readResolve() throws java.io.ObjectStreamException {
1.2099 + return getInstance(baseLocale.getLanguage(), baseLocale.getScript(),
1.2100 + baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions);
1.2101 + }
1.2102 +
1.2103 + private static volatile String[] isoLanguages = null;
1.2104 +
1.2105 + private static volatile String[] isoCountries = null;
1.2106 +
1.2107 + private static String convertOldISOCodes(String language) {
1.2108 + // we accept both the old and the new ISO codes for the languages whose ISO
1.2109 + // codes have changed, but we always store the OLD code, for backward compatibility
1.2110 + language = LocaleUtils.toLowerString(language).intern();
1.2111 + if (language == "he") {
1.2112 + return "iw";
1.2113 + } else if (language == "yi") {
1.2114 + return "ji";
1.2115 + } else if (language == "id") {
1.2116 + return "in";
1.2117 + } else {
1.2118 + return language;
1.2119 + }
1.2120 + }
1.2121 +
1.2122 + private static LocaleExtensions getCompatibilityExtensions(String language,
1.2123 + String script,
1.2124 + String country,
1.2125 + String variant) {
1.2126 + LocaleExtensions extensions = null;
1.2127 + // Special cases for backward compatibility support
1.2128 + if (LocaleUtils.caseIgnoreMatch(language, "ja")
1.2129 + && script.length() == 0
1.2130 + && LocaleUtils.caseIgnoreMatch(country, "jp")
1.2131 + && "JP".equals(variant)) {
1.2132 + // ja_JP_JP -> u-ca-japanese (calendar = japanese)
1.2133 + extensions = LocaleExtensions.CALENDAR_JAPANESE;
1.2134 + } else if (LocaleUtils.caseIgnoreMatch(language, "th")
1.2135 + && script.length() == 0
1.2136 + && LocaleUtils.caseIgnoreMatch(country, "th")
1.2137 + && "TH".equals(variant)) {
1.2138 + // th_TH_TH -> u-nu-thai (numbersystem = thai)
1.2139 + extensions = LocaleExtensions.NUMBER_THAI;
1.2140 + }
1.2141 + return extensions;
1.2142 + }
1.2143 +
1.2144 + /**
1.2145 + * Obtains a localized locale names from a LocaleNameProvider
1.2146 + * implementation.
1.2147 + */
1.2148 + private static class LocaleNameGetter
1.2149 + implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
1.2150 + private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
1.2151 +
1.2152 + public String getObject(LocaleNameProvider localeNameProvider,
1.2153 + Locale locale,
1.2154 + String key,
1.2155 + Object... params) {
1.2156 + assert params.length == 2;
1.2157 + int type = (Integer)params[0];
1.2158 + String code = (String)params[1];
1.2159 +
1.2160 + switch(type) {
1.2161 + case DISPLAY_LANGUAGE:
1.2162 + return localeNameProvider.getDisplayLanguage(code, locale);
1.2163 + case DISPLAY_COUNTRY:
1.2164 + return localeNameProvider.getDisplayCountry(code, locale);
1.2165 + case DISPLAY_VARIANT:
1.2166 + return localeNameProvider.getDisplayVariant(code, locale);
1.2167 + case DISPLAY_SCRIPT:
1.2168 + return localeNameProvider.getDisplayScript(code, locale);
1.2169 + default:
1.2170 + assert false; // shouldn't happen
1.2171 + }
1.2172 +
1.2173 + return null;
1.2174 + }
1.2175 + }
1.2176 +
1.2177 + /**
1.2178 + * Enum for locale categories. These locale categories are used to get/set
1.2179 + * the default locale for the specific functionality represented by the
1.2180 + * category.
1.2181 + *
1.2182 + * @see #getDefault(Locale.Category)
1.2183 + * @see #setDefault(Locale.Category, Locale)
1.2184 + * @since 1.7
1.2185 + */
1.2186 + public enum Category {
1.2187 +
1.2188 + /**
1.2189 + * Category used to represent the default locale for
1.2190 + * displaying user interfaces.
1.2191 + */
1.2192 + DISPLAY("user.language.display",
1.2193 + "user.script.display",
1.2194 + "user.country.display",
1.2195 + "user.variant.display"),
1.2196 +
1.2197 + /**
1.2198 + * Category used to represent the default locale for
1.2199 + * formatting dates, numbers, and/or currencies.
1.2200 + */
1.2201 + FORMAT("user.language.format",
1.2202 + "user.script.format",
1.2203 + "user.country.format",
1.2204 + "user.variant.format");
1.2205 +
1.2206 + Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
1.2207 + this.languageKey = languageKey;
1.2208 + this.scriptKey = scriptKey;
1.2209 + this.countryKey = countryKey;
1.2210 + this.variantKey = variantKey;
1.2211 + }
1.2212 +
1.2213 + final String languageKey;
1.2214 + final String scriptKey;
1.2215 + final String countryKey;
1.2216 + final String variantKey;
1.2217 + }
1.2218 +
1.2219 + /**
1.2220 + * <code>Builder</code> is used to build instances of <code>Locale</code>
1.2221 + * from values configured by the setters. Unlike the <code>Locale</code>
1.2222 + * constructors, the <code>Builder</code> checks if a value configured by a
1.2223 + * setter satisfies the syntax requirements defined by the <code>Locale</code>
1.2224 + * class. A <code>Locale</code> object created by a <code>Builder</code> is
1.2225 + * well-formed and can be transformed to a well-formed IETF BCP 47 language tag
1.2226 + * without losing information.
1.2227 + *
1.2228 + * <p><b>Note:</b> The <code>Locale</code> class does not provide any
1.2229 + * syntactic restrictions on variant, while BCP 47 requires each variant
1.2230 + * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3
1.2231 + * alphanumerics. The method <code>setVariant</code> throws
1.2232 + * <code>IllformedLocaleException</code> for a variant that does not satisfy
1.2233 + * this restriction. If it is necessary to support such a variant, use a
1.2234 + * Locale constructor. However, keep in mind that a <code>Locale</code>
1.2235 + * object created this way might lose the variant information when
1.2236 + * transformed to a BCP 47 language tag.
1.2237 + *
1.2238 + * <p>The following example shows how to create a <code>Locale</code> object
1.2239 + * with the <code>Builder</code>.
1.2240 + * <blockquote>
1.2241 + * <pre>
1.2242 + * Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
1.2243 + * </pre>
1.2244 + * </blockquote>
1.2245 + *
1.2246 + * <p>Builders can be reused; <code>clear()</code> resets all
1.2247 + * fields to their default values.
1.2248 + *
1.2249 + * @see Locale#forLanguageTag
1.2250 + * @since 1.7
1.2251 + */
1.2252 + public static final class Builder {
1.2253 + private final InternalLocaleBuilder localeBuilder;
1.2254 +
1.2255 + /**
1.2256 + * Constructs an empty Builder. The default value of all
1.2257 + * fields, extensions, and private use information is the
1.2258 + * empty string.
1.2259 + */
1.2260 + public Builder() {
1.2261 + localeBuilder = new InternalLocaleBuilder();
1.2262 + }
1.2263 +
1.2264 + /**
1.2265 + * Resets the <code>Builder</code> to match the provided
1.2266 + * <code>locale</code>. Existing state is discarded.
1.2267 + *
1.2268 + * <p>All fields of the locale must be well-formed, see {@link Locale}.
1.2269 + *
1.2270 + * <p>Locales with any ill-formed fields cause
1.2271 + * <code>IllformedLocaleException</code> to be thrown, except for the
1.2272 + * following three cases which are accepted for compatibility
1.2273 + * reasons:<ul>
1.2274 + * <li>Locale("ja", "JP", "JP") is treated as "ja-JP-u-ca-japanese"
1.2275 + * <li>Locale("th", "TH", "TH") is treated as "th-TH-u-nu-thai"
1.2276 + * <li>Locale("no", "NO", "NY") is treated as "nn-NO"</ul>
1.2277 + *
1.2278 + * @param locale the locale
1.2279 + * @return This builder.
1.2280 + * @throws IllformedLocaleException if <code>locale</code> has
1.2281 + * any ill-formed fields.
1.2282 + * @throws NullPointerException if <code>locale</code> is null.
1.2283 + */
1.2284 + public Builder setLocale(Locale locale) {
1.2285 + try {
1.2286 + localeBuilder.setLocale(locale.baseLocale, locale.localeExtensions);
1.2287 + } catch (LocaleSyntaxException e) {
1.2288 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.2289 + }
1.2290 + return this;
1.2291 + }
1.2292 +
1.2293 + /**
1.2294 + * Resets the Builder to match the provided IETF BCP 47
1.2295 + * language tag. Discards the existing state. Null and the
1.2296 + * empty string cause the builder to be reset, like {@link
1.2297 + * #clear}. Grandfathered tags (see {@link
1.2298 + * Locale#forLanguageTag}) are converted to their canonical
1.2299 + * form before being processed. Otherwise, the language tag
1.2300 + * must be well-formed (see {@link Locale}) or an exception is
1.2301 + * thrown (unlike <code>Locale.forLanguageTag</code>, which
1.2302 + * just discards ill-formed and following portions of the
1.2303 + * tag).
1.2304 + *
1.2305 + * @param languageTag the language tag
1.2306 + * @return This builder.
1.2307 + * @throws IllformedLocaleException if <code>languageTag</code> is ill-formed
1.2308 + * @see Locale#forLanguageTag(String)
1.2309 + */
1.2310 + public Builder setLanguageTag(String languageTag) {
1.2311 + ParseStatus sts = new ParseStatus();
1.2312 + LanguageTag tag = LanguageTag.parse(languageTag, sts);
1.2313 + if (sts.isError()) {
1.2314 + throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex());
1.2315 + }
1.2316 + localeBuilder.setLanguageTag(tag);
1.2317 + return this;
1.2318 + }
1.2319 +
1.2320 + /**
1.2321 + * Sets the language. If <code>language</code> is the empty string or
1.2322 + * null, the language in this <code>Builder</code> is removed. Otherwise,
1.2323 + * the language must be <a href="./Locale.html#def_language">well-formed</a>
1.2324 + * or an exception is thrown.
1.2325 + *
1.2326 + * <p>The typical language value is a two or three-letter language
1.2327 + * code as defined in ISO639.
1.2328 + *
1.2329 + * @param language the language
1.2330 + * @return This builder.
1.2331 + * @throws IllformedLocaleException if <code>language</code> is ill-formed
1.2332 + */
1.2333 + public Builder setLanguage(String language) {
1.2334 + try {
1.2335 + localeBuilder.setLanguage(language);
1.2336 + } catch (LocaleSyntaxException e) {
1.2337 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.2338 + }
1.2339 + return this;
1.2340 + }
1.2341 +
1.2342 + /**
1.2343 + * Sets the script. If <code>script</code> is null or the empty string,
1.2344 + * the script in this <code>Builder</code> is removed.
1.2345 + * Otherwise, the script must be <a href="./Locale.html#def_script">well-formed</a> or an
1.2346 + * exception is thrown.
1.2347 + *
1.2348 + * <p>The typical script value is a four-letter script code as defined by ISO 15924.
1.2349 + *
1.2350 + * @param script the script
1.2351 + * @return This builder.
1.2352 + * @throws IllformedLocaleException if <code>script</code> is ill-formed
1.2353 + */
1.2354 + public Builder setScript(String script) {
1.2355 + try {
1.2356 + localeBuilder.setScript(script);
1.2357 + } catch (LocaleSyntaxException e) {
1.2358 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.2359 + }
1.2360 + return this;
1.2361 + }
1.2362 +
1.2363 + /**
1.2364 + * Sets the region. If region is null or the empty string, the region
1.2365 + * in this <code>Builder</code> is removed. Otherwise,
1.2366 + * the region must be <a href="./Locale.html#def_region">well-formed</a> or an
1.2367 + * exception is thrown.
1.2368 + *
1.2369 + * <p>The typical region value is a two-letter ISO 3166 code or a
1.2370 + * three-digit UN M.49 area code.
1.2371 + *
1.2372 + * <p>The country value in the <code>Locale</code> created by the
1.2373 + * <code>Builder</code> is always normalized to upper case.
1.2374 + *
1.2375 + * @param region the region
1.2376 + * @return This builder.
1.2377 + * @throws IllformedLocaleException if <code>region</code> is ill-formed
1.2378 + */
1.2379 + public Builder setRegion(String region) {
1.2380 + try {
1.2381 + localeBuilder.setRegion(region);
1.2382 + } catch (LocaleSyntaxException e) {
1.2383 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.2384 + }
1.2385 + return this;
1.2386 + }
1.2387 +
1.2388 + /**
1.2389 + * Sets the variant. If variant is null or the empty string, the
1.2390 + * variant in this <code>Builder</code> is removed. Otherwise, it
1.2391 + * must consist of one or more <a href="./Locale.html#def_variant">well-formed</a>
1.2392 + * subtags, or an exception is thrown.
1.2393 + *
1.2394 + * <p><b>Note:</b> This method checks if <code>variant</code>
1.2395 + * satisfies the IETF BCP 47 variant subtag's syntax requirements,
1.2396 + * and normalizes the value to lowercase letters. However,
1.2397 + * the <code>Locale</code> class does not impose any syntactic
1.2398 + * restriction on variant, and the variant value in
1.2399 + * <code>Locale</code> is case sensitive. To set such a variant,
1.2400 + * use a Locale constructor.
1.2401 + *
1.2402 + * @param variant the variant
1.2403 + * @return This builder.
1.2404 + * @throws IllformedLocaleException if <code>variant</code> is ill-formed
1.2405 + */
1.2406 + public Builder setVariant(String variant) {
1.2407 + try {
1.2408 + localeBuilder.setVariant(variant);
1.2409 + } catch (LocaleSyntaxException e) {
1.2410 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.2411 + }
1.2412 + return this;
1.2413 + }
1.2414 +
1.2415 + /**
1.2416 + * Sets the extension for the given key. If the value is null or the
1.2417 + * empty string, the extension is removed. Otherwise, the extension
1.2418 + * must be <a href="./Locale.html#def_extensions">well-formed</a> or an exception
1.2419 + * is thrown.
1.2420 + *
1.2421 + * <p><b>Note:</b> The key {@link Locale#UNICODE_LOCALE_EXTENSION
1.2422 + * UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension.
1.2423 + * Setting a value for this key replaces any existing Unicode locale key/type
1.2424 + * pairs with those defined in the extension.
1.2425 + *
1.2426 + * <p><b>Note:</b> The key {@link Locale#PRIVATE_USE_EXTENSION
1.2427 + * PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be
1.2428 + * well-formed, the value for this key needs only to have subtags of one to
1.2429 + * eight alphanumeric characters, not two to eight as in the general case.
1.2430 + *
1.2431 + * @param key the extension key
1.2432 + * @param value the extension value
1.2433 + * @return This builder.
1.2434 + * @throws IllformedLocaleException if <code>key</code> is illegal
1.2435 + * or <code>value</code> is ill-formed
1.2436 + * @see #setUnicodeLocaleKeyword(String, String)
1.2437 + */
1.2438 + public Builder setExtension(char key, String value) {
1.2439 + try {
1.2440 + localeBuilder.setExtension(key, value);
1.2441 + } catch (LocaleSyntaxException e) {
1.2442 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.2443 + }
1.2444 + return this;
1.2445 + }
1.2446 +
1.2447 + /**
1.2448 + * Sets the Unicode locale keyword type for the given key. If the type
1.2449 + * is null, the Unicode keyword is removed. Otherwise, the key must be
1.2450 + * non-null and both key and type must be <a
1.2451 + * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
1.2452 + * is thrown.
1.2453 + *
1.2454 + * <p>Keys and types are converted to lower case.
1.2455 + *
1.2456 + * <p><b>Note</b>:Setting the 'u' extension via {@link #setExtension}
1.2457 + * replaces all Unicode locale keywords with those defined in the
1.2458 + * extension.
1.2459 + *
1.2460 + * @param key the Unicode locale key
1.2461 + * @param type the Unicode locale type
1.2462 + * @return This builder.
1.2463 + * @throws IllformedLocaleException if <code>key</code> or <code>type</code>
1.2464 + * is ill-formed
1.2465 + * @throws NullPointerException if <code>key</code> is null
1.2466 + * @see #setExtension(char, String)
1.2467 + */
1.2468 + public Builder setUnicodeLocaleKeyword(String key, String type) {
1.2469 + try {
1.2470 + localeBuilder.setUnicodeLocaleKeyword(key, type);
1.2471 + } catch (LocaleSyntaxException e) {
1.2472 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.2473 + }
1.2474 + return this;
1.2475 + }
1.2476 +
1.2477 + /**
1.2478 + * Adds a unicode locale attribute, if not already present, otherwise
1.2479 + * has no effect. The attribute must not be null and must be <a
1.2480 + * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
1.2481 + * is thrown.
1.2482 + *
1.2483 + * @param attribute the attribute
1.2484 + * @return This builder.
1.2485 + * @throws NullPointerException if <code>attribute</code> is null
1.2486 + * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
1.2487 + * @see #setExtension(char, String)
1.2488 + */
1.2489 + public Builder addUnicodeLocaleAttribute(String attribute) {
1.2490 + try {
1.2491 + localeBuilder.addUnicodeLocaleAttribute(attribute);
1.2492 + } catch (LocaleSyntaxException e) {
1.2493 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.2494 + }
1.2495 + return this;
1.2496 + }
1.2497 +
1.2498 + /**
1.2499 + * Removes a unicode locale attribute, if present, otherwise has no
1.2500 + * effect. The attribute must not be null and must be <a
1.2501 + * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
1.2502 + * is thrown.
1.2503 + *
1.2504 + * <p>Attribute comparision for removal is case-insensitive.
1.2505 + *
1.2506 + * @param attribute the attribute
1.2507 + * @return This builder.
1.2508 + * @throws NullPointerException if <code>attribute</code> is null
1.2509 + * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
1.2510 + * @see #setExtension(char, String)
1.2511 + */
1.2512 + public Builder removeUnicodeLocaleAttribute(String attribute) {
1.2513 + try {
1.2514 + localeBuilder.removeUnicodeLocaleAttribute(attribute);
1.2515 + } catch (LocaleSyntaxException e) {
1.2516 + throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
1.2517 + }
1.2518 + return this;
1.2519 + }
1.2520 +
1.2521 + /**
1.2522 + * Resets the builder to its initial, empty state.
1.2523 + *
1.2524 + * @return This builder.
1.2525 + */
1.2526 + public Builder clear() {
1.2527 + localeBuilder.clear();
1.2528 + return this;
1.2529 + }
1.2530 +
1.2531 + /**
1.2532 + * Resets the extensions to their initial, empty state.
1.2533 + * Language, script, region and variant are unchanged.
1.2534 + *
1.2535 + * @return This builder.
1.2536 + * @see #setExtension(char, String)
1.2537 + */
1.2538 + public Builder clearExtensions() {
1.2539 + localeBuilder.clearExtensions();
1.2540 + return this;
1.2541 + }
1.2542 +
1.2543 + /**
1.2544 + * Returns an instance of <code>Locale</code> created from the fields set
1.2545 + * on this builder.
1.2546 + *
1.2547 + * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
1.2548 + * when constructing a Locale. (Grandfathered tags are handled in
1.2549 + * {@link #setLanguageTag}.)
1.2550 + *
1.2551 + * @return A Locale.
1.2552 + */
1.2553 + public Locale build() {
1.2554 + BaseLocale baseloc = localeBuilder.getBaseLocale();
1.2555 + LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
1.2556 + if (extensions == null && baseloc.getVariant().length() > 0) {
1.2557 + extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
1.2558 + baseloc.getRegion(), baseloc.getVariant());
1.2559 + }
1.2560 + return Locale.getInstance(baseloc, extensions);
1.2561 + }
1.2562 + }
1.2563 +}