Print this page
rev 5615 : 6336885: RFE: Locale Data Deployment Enhancements
4609153: Provide locale data for Indic locales
5104387: Support for gl_ES locale (galician language)
6337471: desktop/system locale preferences support
7056139: (cal) SPI support for locale-dependent Calendar parameters
7058206: Provide CalendarData SPI for week params and display field value names
7073852: Support multiple scripts for digits and decimal symbols per locale
7079560: [Fmt-Da] Context dependent month names support in SimpleDateFormat
7171324: getAvailableLocales() of locale sensitive services should return the actual availability of locales
7151414: (cal) Support calendar type identification
7168528: LocaleServiceProvider needs to be aware of Locale extensions
7171372: (cal) locale's default Calendar should be created if unknown calendar is specified
Summary: JEP 127: Improve Locale Data Packaging and Adopt Unicode CLDR Data (part 1 w/o Jigsaw. by Naoto Sato and Masayoshi Okutsu)
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/java/util/Locale.java
+++ new/src/share/classes/java/util/Locale.java
1 1 /*
2 - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
2 + * Copyright (c) 1996, 2012, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 /*
27 27 * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28 28 * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29 29 *
30 30 * The original version of this source code and documentation
31 31 * is copyrighted and owned by Taligent, Inc., a wholly-owned
32 32 * subsidiary of IBM. These materials are provided under terms
33 33 * of a License Agreement between Taligent and Sun. This technology
34 34 * is protected by multiple US and International patents.
35 35 *
36 36 * This notice and attribution to Taligent may not be removed.
37 37 * Taligent is a registered trademark of Taligent, Inc.
38 38 *
39 39 */
40 40
41 41 package java.util;
42 42
↓ open down ↓ |
30 lines elided |
↑ open up ↑ |
43 43 import java.io.IOException;
44 44 import java.io.ObjectInputStream;
45 45 import java.io.ObjectOutputStream;
46 46 import java.io.ObjectStreamField;
47 47 import java.io.Serializable;
48 48 import java.security.AccessController;
49 49 import java.text.MessageFormat;
50 50 import java.util.spi.LocaleNameProvider;
51 51
52 52 import sun.security.action.GetPropertyAction;
53 -import sun.util.LocaleServiceProviderPool;
53 +import sun.util.locale.provider.LocaleServiceProviderPool;
54 54 import sun.util.locale.BaseLocale;
55 55 import sun.util.locale.InternalLocaleBuilder;
56 56 import sun.util.locale.LanguageTag;
57 57 import sun.util.locale.LocaleExtensions;
58 58 import sun.util.locale.LocaleObjectCache;
59 59 import sun.util.locale.LocaleSyntaxException;
60 60 import sun.util.locale.LocaleUtils;
61 61 import sun.util.locale.ParseStatus;
62 -import sun.util.locale.UnicodeLocaleExtension;
63 -import sun.util.resources.LocaleData;
62 +import sun.util.locale.provider.LocaleProviderAdapter;
64 63 import sun.util.resources.OpenListResourceBundle;
65 64
66 65 /**
67 66 * A <code>Locale</code> object represents a specific geographical, political,
68 67 * or cultural region. An operation that requires a <code>Locale</code> to perform
69 68 * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
70 69 * to tailor information for the user. For example, displaying a number
71 70 * is a locale-sensitive operation— the number should be formatted
72 71 * according to the customs and conventions of the user's native country,
73 72 * region, or culture.
74 73 *
75 74 * <p> The <code>Locale</code> class implements identifiers
76 75 * interchangeable with BCP 47 (IETF BCP 47, "Tags for Identifying
77 76 * Languages"), with support for the LDML (UTS#35, "Unicode Locale
78 77 * Data Markup Language") BCP 47-compatible extensions for locale data
79 78 * exchange.
80 79 *
81 80 * <p> A <code>Locale</code> object logically consists of the fields
82 81 * described below.
83 82 *
84 83 * <dl>
85 84 * <dt><a name="def_language"/><b>language</b></dt>
86 85 *
87 86 * <dd>ISO 639 alpha-2 or alpha-3 language code, or registered
88 87 * language subtags up to 8 alpha letters (for future enhancements).
89 88 * When a language has both an alpha-2 code and an alpha-3 code, the
90 89 * alpha-2 code must be used. You can find a full list of valid
91 90 * language codes in the IANA Language Subtag Registry (search for
92 91 * "Type: language"). The language field is case insensitive, but
93 92 * <code>Locale</code> always canonicalizes to lower case.</dd><br>
94 93 *
95 94 * <dd>Well-formed language values have the form
96 95 * <code>[a-zA-Z]{2,8}</code>. Note that this is not the the full
97 96 * BCP47 language production, since it excludes extlang. They are
98 97 * not needed since modern three-letter language codes replace
99 98 * them.</dd><br>
100 99 *
101 100 * <dd>Example: "en" (English), "ja" (Japanese), "kok" (Konkani)</dd><br>
102 101 *
103 102 * <dt><a name="def_script"/><b>script</b></dt>
104 103 *
105 104 * <dd>ISO 15924 alpha-4 script code. You can find a full list of
106 105 * valid script codes in the IANA Language Subtag Registry (search
107 106 * for "Type: script"). The script field is case insensitive, but
108 107 * <code>Locale</code> always canonicalizes to title case (the first
109 108 * letter is upper case and the rest of the letters are lower
110 109 * case).</dd><br>
111 110 *
112 111 * <dd>Well-formed script values have the form
113 112 * <code>[a-zA-Z]{4}</code></dd><br>
114 113 *
115 114 * <dd>Example: "Latn" (Latin), "Cyrl" (Cyrillic)</dd><br>
116 115 *
117 116 * <dt><a name="def_region"/><b>country (region)</b></dt>
118 117 *
119 118 * <dd>ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.
120 119 * You can find a full list of valid country and region codes in the
121 120 * IANA Language Subtag Registry (search for "Type: region"). The
122 121 * country (region) field is case insensitive, but
123 122 * <code>Locale</code> always canonicalizes to upper case.</dd><br>
124 123 *
125 124 * <dd>Well-formed country/region values have
126 125 * the form <code>[a-zA-Z]{2} | [0-9]{3}</code></dd><br>
127 126 *
128 127 * <dd>Example: "US" (United States), "FR" (France), "029"
129 128 * (Caribbean)</dd><br>
130 129 *
131 130 * <dt><a name="def_variant"/><b>variant</b></dt>
132 131 *
133 132 * <dd>Any arbitrary value used to indicate a variation of a
134 133 * <code>Locale</code>. Where there are two or more variant values
135 134 * each indicating its own semantics, these values should be ordered
136 135 * by importance, with most important first, separated by
137 136 * underscore('_'). The variant field is case sensitive.</dd><br>
138 137 *
139 138 * <dd>Note: IETF BCP 47 places syntactic restrictions on variant
140 139 * subtags. Also BCP 47 subtags are strictly used to indicate
141 140 * additional variations that define a language or its dialects that
142 141 * are not covered by any combinations of language, script and
143 142 * region subtags. You can find a full list of valid variant codes
144 143 * in the IANA Language Subtag Registry (search for "Type: variant").
145 144 *
146 145 * <p>However, the variant field in <code>Locale</code> has
147 146 * historically been used for any kind of variation, not just
148 147 * language variations. For example, some supported variants
149 148 * available in Java SE Runtime Environments indicate alternative
150 149 * cultural behaviors such as calendar type or number script. In
151 150 * BCP 47 this kind of information, which does not identify the
152 151 * language, is supported by extension subtags or private use
153 152 * subtags.</dd><br>
154 153 *
155 154 * <dd>Well-formed variant values have the form <code>SUBTAG
156 155 * (('_'|'-') SUBTAG)*</code> where <code>SUBTAG =
157 156 * [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}</code>. (Note: BCP 47 only
158 157 * uses hyphen ('-') as a delimiter, this is more lenient).</dd><br>
159 158 *
160 159 * <dd>Example: "polyton" (Polytonic Greek), "POSIX"</dd><br>
161 160 *
162 161 * <dt><a name="def_extensions"/><b>extensions</b></dt>
163 162 *
164 163 * <dd>A map from single character keys to string values, indicating
165 164 * extensions apart from language identification. The extensions in
166 165 * <code>Locale</code> implement the semantics and syntax of BCP 47
167 166 * extension subtags and private use subtags. The extensions are
168 167 * case insensitive, but <code>Locale</code> canonicalizes all
169 168 * extension keys and values to lower case. Note that extensions
170 169 * cannot have empty values.</dd><br>
171 170 *
172 171 * <dd>Well-formed keys are single characters from the set
173 172 * <code>[0-9a-zA-Z]</code>. Well-formed values have the form
174 173 * <code>SUBTAG ('-' SUBTAG)*</code> where for the key 'x'
175 174 * <code>SUBTAG = [0-9a-zA-Z]{1,8}</code> and for other keys
176 175 * <code>SUBTAG = [0-9a-zA-Z]{2,8}</code> (that is, 'x' allows
177 176 * single-character subtags).</dd><br>
178 177 *
179 178 * <dd>Example: key="u"/value="ca-japanese" (Japanese Calendar),
180 179 * key="x"/value="java-1-7"</dd>
181 180 * </dl>
182 181 *
183 182 * <b>Note:</b> Although BCP 47 requires field values to be registered
184 183 * in the IANA Language Subtag Registry, the <code>Locale</code> class
185 184 * does not provide any validation features. The <code>Builder</code>
186 185 * only checks if an individual field satisfies the syntactic
187 186 * requirement (is well-formed), but does not validate the value
188 187 * itself. See {@link Builder} for details.
189 188 *
190 189 * <h4><a name="def_locale_extension">Unicode locale/language extension</h4>
191 190 *
192 191 * <p>UTS#35, "Unicode Locale Data Markup Language" defines optional
193 192 * attributes and keywords to override or refine the default behavior
194 193 * associated with a locale. A keyword is represented by a pair of
195 194 * key and type. For example, "nu-thai" indicates that Thai local
196 195 * digits (value:"thai") should be used for formatting numbers
197 196 * (key:"nu").
198 197 *
199 198 * <p>The keywords are mapped to a BCP 47 extension value using the
200 199 * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}). The above
201 200 * example, "nu-thai", becomes the extension "u-nu-thai".code
202 201 *
203 202 * <p>Thus, when a <code>Locale</code> object contains Unicode locale
204 203 * attributes and keywords,
205 204 * <code>getExtension(UNICODE_LOCALE_EXTENSION)</code> will return a
206 205 * String representing this information, for example, "nu-thai". The
207 206 * <code>Locale</code> class also provides {@link
208 207 * #getUnicodeLocaleAttributes}, {@link #getUnicodeLocaleKeys}, and
209 208 * {@link #getUnicodeLocaleType} which allow you to access Unicode
210 209 * locale attributes and key/type pairs directly. When represented as
211 210 * a string, the Unicode Locale Extension lists attributes
212 211 * alphabetically, followed by key/type sequences with keys listed
213 212 * alphabetically (the order of subtags comprising a key's type is
214 213 * fixed when the type is defined)
215 214 *
216 215 * <p>A well-formed locale key has the form
217 216 * <code>[0-9a-zA-Z]{2}</code>. A well-formed locale type has the
218 217 * form <code>"" | [0-9a-zA-Z]{3,8} ('-' [0-9a-zA-Z]{3,8})*</code> (it
219 218 * can be empty, or a series of subtags 3-8 alphanums in length). A
220 219 * well-formed locale attribute has the form
221 220 * <code>[0-9a-zA-Z]{3,8}</code> (it is a single subtag with the same
222 221 * form as a locale type subtag).
223 222 *
224 223 * <p>The Unicode locale extension specifies optional behavior in
225 224 * locale-sensitive services. Although the LDML specification defines
226 225 * various keys and values, actual locale-sensitive service
227 226 * implementations in a Java Runtime Environment might not support any
228 227 * particular Unicode locale attributes or key/type pairs.
229 228 *
230 229 * <h4>Creating a Locale</h4>
231 230 *
232 231 * <p>There are several different ways to create a <code>Locale</code>
233 232 * object.
234 233 *
235 234 * <h5>Builder</h5>
236 235 *
237 236 * <p>Using {@link Builder} you can construct a <code>Locale</code> object
238 237 * that conforms to BCP 47 syntax.
239 238 *
240 239 * <h5>Constructors</h5>
241 240 *
242 241 * <p>The <code>Locale</code> class provides three constructors:
243 242 * <blockquote>
244 243 * <pre>
245 244 * {@link #Locale(String language)}
246 245 * {@link #Locale(String language, String country)}
247 246 * {@link #Locale(String language, String country, String variant)}
248 247 * </pre>
249 248 * </blockquote>
250 249 * These constructors allow you to create a <code>Locale</code> object
251 250 * with language, country and variant, but you cannot specify
252 251 * script or extensions.
253 252 *
254 253 * <h5>Factory Methods</h5>
255 254 *
256 255 * <p>The method {@link #forLanguageTag} creates a <code>Locale</code>
257 256 * object for a well-formed BCP 47 language tag.
258 257 *
259 258 * <h5>Locale Constants</h5>
260 259 *
261 260 * <p>The <code>Locale</code> class provides a number of convenient constants
262 261 * that you can use to create <code>Locale</code> objects for commonly used
263 262 * locales. For example, the following creates a <code>Locale</code> object
264 263 * for the United States:
265 264 * <blockquote>
266 265 * <pre>
267 266 * Locale.US
268 267 * </pre>
269 268 * </blockquote>
270 269 *
271 270 * <h4>Use of Locale</h4>
272 271 *
273 272 * <p>Once you've created a <code>Locale</code> you can query it for information
274 273 * about itself. Use <code>getCountry</code> to get the country (or region)
275 274 * code and <code>getLanguage</code> to get the language code.
276 275 * You can use <code>getDisplayCountry</code> to get the
277 276 * name of the country suitable for displaying to the user. Similarly,
278 277 * you can use <code>getDisplayLanguage</code> to get the name of
279 278 * the language suitable for displaying to the user. Interestingly,
280 279 * the <code>getDisplayXXX</code> methods are themselves locale-sensitive
281 280 * and have two versions: one that uses the default locale and one
282 281 * that uses the locale specified as an argument.
283 282 *
284 283 * <p>The Java Platform provides a number of classes that perform locale-sensitive
285 284 * operations. For example, the <code>NumberFormat</code> class formats
286 285 * numbers, currency, and percentages in a locale-sensitive manner. Classes
287 286 * such as <code>NumberFormat</code> have several convenience methods
288 287 * for creating a default object of that type. For example, the
289 288 * <code>NumberFormat</code> class provides these three convenience methods
290 289 * for creating a default <code>NumberFormat</code> object:
291 290 * <blockquote>
292 291 * <pre>
293 292 * NumberFormat.getInstance()
294 293 * NumberFormat.getCurrencyInstance()
295 294 * NumberFormat.getPercentInstance()
296 295 * </pre>
297 296 * </blockquote>
298 297 * Each of these methods has two variants; one with an explicit locale
299 298 * and one without; the latter uses the default locale:
300 299 * <blockquote>
301 300 * <pre>
302 301 * NumberFormat.getInstance(myLocale)
303 302 * NumberFormat.getCurrencyInstance(myLocale)
304 303 * NumberFormat.getPercentInstance(myLocale)
305 304 * </pre>
306 305 * </blockquote>
307 306 * A <code>Locale</code> is the mechanism for identifying the kind of object
308 307 * (<code>NumberFormat</code>) that you would like to get. The locale is
309 308 * <STRONG>just</STRONG> a mechanism for identifying objects,
310 309 * <STRONG>not</STRONG> a container for the objects themselves.
311 310 *
312 311 * <h4>Compatibility</h4>
313 312 *
314 313 * <p>In order to maintain compatibility with existing usage, Locale's
315 314 * constructors retain their behavior prior to the Java Runtime
316 315 * Environment version 1.7. The same is largely true for the
317 316 * <code>toString</code> method. Thus Locale objects can continue to
318 317 * be used as they were. In particular, clients who parse the output
319 318 * of toString into language, country, and variant fields can continue
320 319 * to do so (although this is strongly discouraged), although the
321 320 * variant field will have additional information in it if script or
322 321 * extensions are present.
323 322 *
324 323 * <p>In addition, BCP 47 imposes syntax restrictions that are not
325 324 * imposed by Locale's constructors. This means that conversions
326 325 * between some Locales and BCP 47 language tags cannot be made without
327 326 * losing information. Thus <code>toLanguageTag</code> cannot
328 327 * represent the state of locales whose language, country, or variant
329 328 * do not conform to BCP 47.
330 329 *
331 330 * <p>Because of these issues, it is recommended that clients migrate
332 331 * away from constructing non-conforming locales and use the
333 332 * <code>forLanguageTag</code> and <code>Locale.Builder</code> APIs instead.
334 333 * Clients desiring a string representation of the complete locale can
335 334 * then always rely on <code>toLanguageTag</code> for this purpose.
336 335 *
337 336 * <h5><a name="special_cases_constructor"/>Special cases</h5>
338 337 *
339 338 * <p>For compatibility reasons, two
340 339 * non-conforming locales are treated as special cases. These are
341 340 * <b><tt>ja_JP_JP</tt></b> and <b><tt>th_TH_TH</tt></b>. These are ill-formed
342 341 * in BCP 47 since the variants are too short. To ease migration to BCP 47,
343 342 * these are treated specially during construction. These two cases (and only
344 343 * these) cause a constructor to generate an extension, all other values behave
345 344 * exactly as they did prior to Java 7.
346 345 *
347 346 * <p>Java has used <tt>ja_JP_JP</tt> to represent Japanese as used in
348 347 * Japan together with the Japanese Imperial calendar. This is now
349 348 * representable using a Unicode locale extension, by specifying the
350 349 * Unicode locale key <tt>ca</tt> (for "calendar") and type
351 350 * <tt>japanese</tt>. When the Locale constructor is called with the
352 351 * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is
353 352 * automatically added.
354 353 *
355 354 * <p>Java has used <tt>th_TH_TH</tt> to represent Thai as used in
356 355 * Thailand together with Thai digits. This is also now representable using
357 356 * a Unicode locale extension, by specifying the Unicode locale key
358 357 * <tt>nu</tt> (for "number") and value <tt>thai</tt>. When the Locale
359 358 * constructor is called with the arguments "th", "TH", "TH", the
360 359 * extension "u-nu-thai" is automatically added.
361 360 *
362 361 * <h5>Serialization</h5>
363 362 *
364 363 * <p>During serialization, writeObject writes all fields to the output
365 364 * stream, including extensions.
366 365 *
367 366 * <p>During deserialization, readResolve adds extensions as described
368 367 * in <a href="#special_cases_constructor">Special Cases</a>, only
369 368 * for the two cases th_TH_TH and ja_JP_JP.
370 369 *
371 370 * <h5>Legacy language codes</h5>
372 371 *
373 372 * <p>Locale's constructor has always converted three language codes to
374 373 * their earlier, obsoleted forms: <tt>he</tt> maps to <tt>iw</tt>,
375 374 * <tt>yi</tt> maps to <tt>ji</tt>, and <tt>id</tt> maps to
376 375 * <tt>in</tt>. This continues to be the case, in order to not break
377 376 * backwards compatibility.
378 377 *
379 378 * <p>The APIs added in 1.7 map between the old and new language codes,
380 379 * maintaining the old codes internal to Locale (so that
381 380 * <code>getLanguage</code> and <code>toString</code> reflect the old
382 381 * code), but using the new codes in the BCP 47 language tag APIs (so
383 382 * that <code>toLanguageTag</code> reflects the new one). This
384 383 * preserves the equivalence between Locales no matter which code or
385 384 * API is used to construct them. Java's default resource bundle
386 385 * lookup mechanism also implements this mapping, so that resources
387 386 * can be named using either convention, see {@link ResourceBundle.Control}.
388 387 *
389 388 * <h5>Three-letter language/country(region) codes</h5>
390 389 *
391 390 * <p>The Locale constructors have always specified that the language
392 391 * and the country param be two characters in length, although in
393 392 * practice they have accepted any length. The specification has now
394 393 * been relaxed to allow language codes of two to eight characters and
395 394 * country (region) codes of two to three characters, and in
396 395 * particular, three-letter language codes and three-digit region
397 396 * codes as specified in the IANA Language Subtag Registry. For
398 397 * compatibility, the implementation still does not impose a length
399 398 * constraint.
400 399 *
401 400 * @see Builder
402 401 * @see ResourceBundle
403 402 * @see java.text.Format
404 403 * @see java.text.NumberFormat
405 404 * @see java.text.Collator
406 405 * @author Mark Davis
407 406 * @since 1.1
408 407 */
409 408 public final class Locale implements Cloneable, Serializable {
410 409
411 410 static private final Cache LOCALECACHE = new Cache();
412 411
413 412 /** Useful constant for language.
414 413 */
415 414 static public final Locale ENGLISH = createConstant("en", "");
416 415
417 416 /** Useful constant for language.
418 417 */
419 418 static public final Locale FRENCH = createConstant("fr", "");
420 419
421 420 /** Useful constant for language.
422 421 */
423 422 static public final Locale GERMAN = createConstant("de", "");
424 423
425 424 /** Useful constant for language.
426 425 */
427 426 static public final Locale ITALIAN = createConstant("it", "");
428 427
429 428 /** Useful constant for language.
430 429 */
431 430 static public final Locale JAPANESE = createConstant("ja", "");
432 431
433 432 /** Useful constant for language.
434 433 */
435 434 static public final Locale KOREAN = createConstant("ko", "");
436 435
437 436 /** Useful constant for language.
438 437 */
439 438 static public final Locale CHINESE = createConstant("zh", "");
440 439
441 440 /** Useful constant for language.
442 441 */
443 442 static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
444 443
445 444 /** Useful constant for language.
446 445 */
447 446 static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW");
448 447
449 448 /** Useful constant for country.
450 449 */
451 450 static public final Locale FRANCE = createConstant("fr", "FR");
452 451
453 452 /** Useful constant for country.
454 453 */
455 454 static public final Locale GERMANY = createConstant("de", "DE");
456 455
457 456 /** Useful constant for country.
458 457 */
459 458 static public final Locale ITALY = createConstant("it", "IT");
460 459
461 460 /** Useful constant for country.
462 461 */
463 462 static public final Locale JAPAN = createConstant("ja", "JP");
464 463
465 464 /** Useful constant for country.
466 465 */
467 466 static public final Locale KOREA = createConstant("ko", "KR");
468 467
469 468 /** Useful constant for country.
470 469 */
471 470 static public final Locale CHINA = SIMPLIFIED_CHINESE;
472 471
473 472 /** Useful constant for country.
474 473 */
475 474 static public final Locale PRC = SIMPLIFIED_CHINESE;
476 475
477 476 /** Useful constant for country.
478 477 */
479 478 static public final Locale TAIWAN = TRADITIONAL_CHINESE;
480 479
481 480 /** Useful constant for country.
482 481 */
483 482 static public final Locale UK = createConstant("en", "GB");
484 483
485 484 /** Useful constant for country.
486 485 */
487 486 static public final Locale US = createConstant("en", "US");
488 487
489 488 /** Useful constant for country.
490 489 */
491 490 static public final Locale CANADA = createConstant("en", "CA");
492 491
493 492 /** Useful constant for country.
494 493 */
495 494 static public final Locale CANADA_FRENCH = createConstant("fr", "CA");
496 495
497 496 /**
498 497 * Useful constant for the root locale. The root locale is the locale whose
499 498 * language, country, and variant are empty ("") strings. This is regarded
500 499 * as the base locale of all locales, and is used as the language/country
501 500 * neutral locale for the locale sensitive operations.
502 501 *
503 502 * @since 1.6
504 503 */
505 504 static public final Locale ROOT = createConstant("", "");
506 505
507 506 /**
508 507 * The key for the private use extension ('x').
509 508 *
510 509 * @see #getExtension(char)
511 510 * @see Builder#setExtension(char, String)
512 511 * @since 1.7
513 512 */
514 513 static public final char PRIVATE_USE_EXTENSION = 'x';
515 514
516 515 /**
517 516 * The key for Unicode locale extension ('u').
518 517 *
519 518 * @see #getExtension(char)
520 519 * @see Builder#setExtension(char, String)
521 520 * @since 1.7
522 521 */
523 522 static public final char UNICODE_LOCALE_EXTENSION = 'u';
524 523
525 524 /** serialization ID
526 525 */
527 526 static final long serialVersionUID = 9149081749638150636L;
528 527
529 528 /**
530 529 * Display types for retrieving localized names from the name providers.
531 530 */
532 531 private static final int DISPLAY_LANGUAGE = 0;
533 532 private static final int DISPLAY_COUNTRY = 1;
534 533 private static final int DISPLAY_VARIANT = 2;
535 534 private static final int DISPLAY_SCRIPT = 3;
536 535
537 536 /**
538 537 * Private constructor used by getInstance method
539 538 */
540 539 private Locale(BaseLocale baseLocale, LocaleExtensions extensions) {
541 540 this.baseLocale = baseLocale;
542 541 this.localeExtensions = extensions;
543 542 }
544 543
545 544 /**
546 545 * Construct a locale from language, country and variant.
547 546 * This constructor normalizes the language value to lowercase and
548 547 * the country value to uppercase.
549 548 * <p>
550 549 * <b>Note:</b>
551 550 * <ul>
552 551 * <li>ISO 639 is not a stable standard; some of the language codes it defines
553 552 * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
554 553 * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
555 554 * API on Locale will return only the OLD codes.
556 555 * <li>For backward compatibility reasons, this constructor does not make
557 556 * any syntactic checks on the input.
558 557 * <li>The two cases ("ja", "JP", "JP") and ("th", "TH", "TH") are handled specially,
559 558 * see <a href="#special_cases_constructor">Special Cases</a> for more information.
560 559 * </ul>
561 560 *
562 561 * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
563 562 * up to 8 characters in length. See the <code>Locale</code> class description about
564 563 * valid language values.
565 564 * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
566 565 * See the <code>Locale</code> class description about valid country values.
567 566 * @param variant Any arbitrary value used to indicate a variation of a <code>Locale</code>.
568 567 * See the <code>Locale</code> class description for the details.
569 568 * @exception NullPointerException thrown if any argument is null.
570 569 */
571 570 public Locale(String language, String country, String variant) {
572 571 if (language== null || country == null || variant == null) {
573 572 throw new NullPointerException();
574 573 }
575 574 baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), "", country, variant);
576 575 localeExtensions = getCompatibilityExtensions(language, "", country, variant);
577 576 }
578 577
579 578 /**
580 579 * Construct a locale from language and country.
581 580 * This constructor normalizes the language value to lowercase and
582 581 * the country value to uppercase.
583 582 * <p>
584 583 * <b>Note:</b>
585 584 * <ul>
586 585 * <li>ISO 639 is not a stable standard; some of the language codes it defines
587 586 * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
588 587 * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
589 588 * API on Locale will return only the OLD codes.
590 589 * <li>For backward compatibility reasons, this constructor does not make
591 590 * any syntactic checks on the input.
592 591 * </ul>
593 592 *
594 593 * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
595 594 * up to 8 characters in length. See the <code>Locale</code> class description about
596 595 * valid language values.
597 596 * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
598 597 * See the <code>Locale</code> class description about valid country values.
599 598 * @exception NullPointerException thrown if either argument is null.
600 599 */
601 600 public Locale(String language, String country) {
602 601 this(language, country, "");
603 602 }
604 603
605 604 /**
606 605 * Construct a locale from a language code.
607 606 * This constructor normalizes the language value to lowercase.
608 607 * <p>
609 608 * <b>Note:</b>
610 609 * <ul>
611 610 * <li>ISO 639 is not a stable standard; some of the language codes it defines
612 611 * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
613 612 * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
614 613 * API on Locale will return only the OLD codes.
615 614 * <li>For backward compatibility reasons, this constructor does not make
616 615 * any syntactic checks on the input.
617 616 * </ul>
618 617 *
619 618 * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
620 619 * up to 8 characters in length. See the <code>Locale</code> class description about
621 620 * valid language values.
622 621 * @exception NullPointerException thrown if argument is null.
623 622 * @since 1.4
624 623 */
625 624 public Locale(String language) {
626 625 this(language, "", "");
627 626 }
628 627
629 628 /**
630 629 * This method must be called only for creating the Locale.*
631 630 * constants due to making shortcuts.
632 631 */
633 632 private static Locale createConstant(String lang, String country) {
634 633 BaseLocale base = BaseLocale.createInstance(lang, country);
635 634 return getInstance(base, null);
636 635 }
637 636
638 637 /**
639 638 * Returns a <code>Locale</code> constructed from the given
640 639 * <code>language</code>, <code>country</code> and
641 640 * <code>variant</code>. If the same <code>Locale</code> instance
642 641 * is available in the cache, then that instance is
643 642 * returned. Otherwise, a new <code>Locale</code> instance is
644 643 * created and cached.
645 644 *
646 645 * @param language lowercase 2 to 8 language code.
647 646 * @param country uppercase two-letter ISO-3166 code and numric-3 UN M.49 area code.
648 647 * @param variant vendor and browser specific code. See class description.
649 648 * @return the <code>Locale</code> instance requested
650 649 * @exception NullPointerException if any argument is null.
651 650 */
652 651 static Locale getInstance(String language, String country, String variant) {
653 652 return getInstance(language, "", country, variant, null);
654 653 }
655 654
656 655 static Locale getInstance(String language, String script, String country,
657 656 String variant, LocaleExtensions extensions) {
658 657 if (language== null || script == null || country == null || variant == null) {
659 658 throw new NullPointerException();
660 659 }
661 660
662 661 if (extensions == null) {
663 662 extensions = getCompatibilityExtensions(language, script, country, variant);
664 663 }
665 664
666 665 BaseLocale baseloc = BaseLocale.getInstance(language, script, country, variant);
667 666 return getInstance(baseloc, extensions);
668 667 }
669 668
670 669 static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) {
671 670 LocaleKey key = new LocaleKey(baseloc, extensions);
672 671 return LOCALECACHE.get(key);
673 672 }
674 673
675 674 private static class Cache extends LocaleObjectCache<LocaleKey, Locale> {
676 675 private Cache() {
677 676 }
678 677
679 678 @Override
680 679 protected Locale createObject(LocaleKey key) {
681 680 return new Locale(key.base, key.exts);
682 681 }
683 682 }
684 683
685 684 private static final class LocaleKey {
686 685 private final BaseLocale base;
687 686 private final LocaleExtensions exts;
688 687 private final int hash;
689 688
690 689 private LocaleKey(BaseLocale baseLocale, LocaleExtensions extensions) {
691 690 base = baseLocale;
692 691 exts = extensions;
693 692
694 693 // Calculate the hash value here because it's always used.
695 694 int h = base.hashCode();
696 695 if (exts != null) {
697 696 h ^= exts.hashCode();
698 697 }
699 698 hash = h;
700 699 }
701 700
702 701 @Override
703 702 public boolean equals(Object obj) {
704 703 if (this == obj) {
705 704 return true;
706 705 }
707 706 if (!(obj instanceof LocaleKey)) {
708 707 return false;
709 708 }
710 709 LocaleKey other = (LocaleKey)obj;
711 710 if (hash != other.hash || !base.equals(other.base)) {
712 711 return false;
713 712 }
714 713 if (exts == null) {
715 714 return other.exts == null;
716 715 }
717 716 return exts.equals(other.exts);
718 717 }
719 718
720 719 @Override
721 720 public int hashCode() {
722 721 return hash;
723 722 }
724 723 }
725 724
726 725 /**
727 726 * Gets the current value of the default locale for this instance
728 727 * of the Java Virtual Machine.
729 728 * <p>
730 729 * The Java Virtual Machine sets the default locale during startup
731 730 * based on the host environment. It is used by many locale-sensitive
732 731 * methods if no locale is explicitly specified.
733 732 * It can be changed using the
734 733 * {@link #setDefault(java.util.Locale) setDefault} method.
735 734 *
736 735 * @return the default locale for this instance of the Java Virtual Machine
737 736 */
738 737 public static Locale getDefault() {
739 738 // do not synchronize this method - see 4071298
740 739 return defaultLocale;
741 740 }
742 741
743 742 /**
744 743 * Gets the current value of the default locale for the specified Category
745 744 * for this instance of the Java Virtual Machine.
746 745 * <p>
747 746 * The Java Virtual Machine sets the default locale during startup based
748 747 * on the host environment. It is used by many locale-sensitive methods
749 748 * if no locale is explicitly specified. It can be changed using the
750 749 * setDefault(Locale.Category, Locale) method.
751 750 *
752 751 * @param category - the specified category to get the default locale
753 752 * @throws NullPointerException - if category is null
754 753 * @return the default locale for the specified Category for this instance
755 754 * of the Java Virtual Machine
756 755 * @see #setDefault(Locale.Category, Locale)
757 756 * @since 1.7
758 757 */
759 758 public static Locale getDefault(Locale.Category category) {
760 759 // do not synchronize this method - see 4071298
761 760 switch (category) {
762 761 case DISPLAY:
763 762 if (defaultDisplayLocale == null) {
764 763 synchronized(Locale.class) {
765 764 if (defaultDisplayLocale == null) {
766 765 defaultDisplayLocale = initDefault(category);
767 766 }
768 767 }
769 768 }
770 769 return defaultDisplayLocale;
771 770 case FORMAT:
772 771 if (defaultFormatLocale == null) {
773 772 synchronized(Locale.class) {
774 773 if (defaultFormatLocale == null) {
775 774 defaultFormatLocale = initDefault(category);
776 775 }
777 776 }
778 777 }
779 778 return defaultFormatLocale;
780 779 default:
781 780 assert false: "Unknown Category";
782 781 }
783 782 return getDefault();
784 783 }
785 784
786 785 private static Locale initDefault() {
787 786 String language, region, script, country, variant;
788 787 language = AccessController.doPrivileged(
789 788 new GetPropertyAction("user.language", "en"));
790 789 // for compatibility, check for old user.region property
791 790 region = AccessController.doPrivileged(
792 791 new GetPropertyAction("user.region"));
793 792 if (region != null) {
794 793 // region can be of form country, country_variant, or _variant
795 794 int i = region.indexOf('_');
796 795 if (i >= 0) {
797 796 country = region.substring(0, i);
798 797 variant = region.substring(i + 1);
799 798 } else {
800 799 country = region;
801 800 variant = "";
802 801 }
803 802 script = "";
804 803 } else {
805 804 script = AccessController.doPrivileged(
806 805 new GetPropertyAction("user.script", ""));
807 806 country = AccessController.doPrivileged(
808 807 new GetPropertyAction("user.country", ""));
809 808 variant = AccessController.doPrivileged(
810 809 new GetPropertyAction("user.variant", ""));
811 810 }
812 811
813 812 return getInstance(language, script, country, variant, null);
814 813 }
815 814
816 815 private static Locale initDefault(Locale.Category category) {
817 816 return getInstance(
818 817 AccessController.doPrivileged(
819 818 new GetPropertyAction(category.languageKey, defaultLocale.getLanguage())),
820 819 AccessController.doPrivileged(
821 820 new GetPropertyAction(category.scriptKey, defaultLocale.getScript())),
822 821 AccessController.doPrivileged(
823 822 new GetPropertyAction(category.countryKey, defaultLocale.getCountry())),
824 823 AccessController.doPrivileged(
825 824 new GetPropertyAction(category.variantKey, defaultLocale.getVariant())),
826 825 null);
827 826 }
828 827
829 828 /**
830 829 * Sets the default locale for this instance of the Java Virtual Machine.
831 830 * This does not affect the host locale.
832 831 * <p>
833 832 * If there is a security manager, its <code>checkPermission</code>
834 833 * method is called with a <code>PropertyPermission("user.language", "write")</code>
835 834 * permission before the default locale is changed.
836 835 * <p>
837 836 * The Java Virtual Machine sets the default locale during startup
838 837 * based on the host environment. It is used by many locale-sensitive
839 838 * methods if no locale is explicitly specified.
840 839 * <p>
841 840 * Since changing the default locale may affect many different areas
842 841 * of functionality, this method should only be used if the caller
843 842 * is prepared to reinitialize locale-sensitive code running
844 843 * within the same Java Virtual Machine.
845 844 * <p>
846 845 * By setting the default locale with this method, all of the default
847 846 * locales for each Category are also set to the specified default locale.
848 847 *
849 848 * @throws SecurityException
850 849 * if a security manager exists and its
851 850 * <code>checkPermission</code> method doesn't allow the operation.
852 851 * @throws NullPointerException if <code>newLocale</code> is null
853 852 * @param newLocale the new default locale
854 853 * @see SecurityManager#checkPermission
855 854 * @see java.util.PropertyPermission
856 855 */
857 856 public static synchronized void setDefault(Locale newLocale) {
858 857 setDefault(Category.DISPLAY, newLocale);
859 858 setDefault(Category.FORMAT, newLocale);
860 859 defaultLocale = newLocale;
861 860 }
862 861
863 862 /**
864 863 * Sets the default locale for the specified Category for this instance
865 864 * of the Java Virtual Machine. This does not affect the host locale.
866 865 * <p>
867 866 * If there is a security manager, its checkPermission method is called
868 867 * with a PropertyPermission("user.language", "write") permission before
869 868 * the default locale is changed.
870 869 * <p>
871 870 * The Java Virtual Machine sets the default locale during startup based
872 871 * on the host environment. It is used by many locale-sensitive methods
873 872 * if no locale is explicitly specified.
874 873 * <p>
875 874 * Since changing the default locale may affect many different areas of
876 875 * functionality, this method should only be used if the caller is
877 876 * prepared to reinitialize locale-sensitive code running within the
878 877 * same Java Virtual Machine.
879 878 * <p>
880 879 *
881 880 * @param category - the specified category to set the default locale
882 881 * @param newLocale - the new default locale
883 882 * @throws SecurityException - if a security manager exists and its
884 883 * checkPermission method doesn't allow the operation.
885 884 * @throws NullPointerException - if category and/or newLocale is null
886 885 * @see SecurityManager#checkPermission(java.security.Permission)
887 886 * @see PropertyPermission
888 887 * @see #getDefault(Locale.Category)
889 888 * @since 1.7
890 889 */
891 890 public static synchronized void setDefault(Locale.Category category,
892 891 Locale newLocale) {
893 892 if (category == null)
894 893 throw new NullPointerException("Category cannot be NULL");
895 894 if (newLocale == null)
896 895 throw new NullPointerException("Can't set default locale to NULL");
897 896
898 897 SecurityManager sm = System.getSecurityManager();
899 898 if (sm != null) sm.checkPermission(new PropertyPermission
900 899 ("user.language", "write"));
901 900 switch (category) {
902 901 case DISPLAY:
903 902 defaultDisplayLocale = newLocale;
904 903 break;
905 904 case FORMAT:
906 905 defaultFormatLocale = newLocale;
907 906 break;
908 907 default:
909 908 assert false: "Unknown Category";
910 909 }
911 910 }
912 911
913 912 /**
914 913 * Returns an array of all installed locales.
915 914 * The returned array represents the union of locales supported
916 915 * by the Java runtime environment and by installed
917 916 * {@link java.util.spi.LocaleServiceProvider LocaleServiceProvider}
918 917 * implementations. It must contain at least a <code>Locale</code>
919 918 * instance equal to {@link java.util.Locale#US Locale.US}.
920 919 *
921 920 * @return An array of installed locales.
922 921 */
923 922 public static Locale[] getAvailableLocales() {
924 923 return LocaleServiceProviderPool.getAllAvailableLocales();
925 924 }
926 925
927 926 /**
928 927 * Returns a list of all 2-letter country codes defined in ISO 3166.
929 928 * Can be used to create Locales.
930 929 * <p>
931 930 * <b>Note:</b> The <code>Locale</code> class also supports other codes for
932 931 * country (region), such as 3-letter numeric UN M.49 area codes.
933 932 * Therefore, the list returned by this method does not contain ALL valid
934 933 * codes that can be used to create Locales.
935 934 */
936 935 public static String[] getISOCountries() {
937 936 if (isoCountries == null) {
938 937 isoCountries = getISO2Table(LocaleISOData.isoCountryTable);
939 938 }
940 939 String[] result = new String[isoCountries.length];
941 940 System.arraycopy(isoCountries, 0, result, 0, isoCountries.length);
942 941 return result;
943 942 }
944 943
945 944 /**
946 945 * Returns a list of all 2-letter language codes defined in ISO 639.
947 946 * Can be used to create Locales.
948 947 * <p>
949 948 * <b>Note:</b>
950 949 * <ul>
951 950 * <li>ISO 639 is not a stable standard— some languages' codes have changed.
952 951 * The list this function returns includes both the new and the old codes for the
953 952 * languages whose codes have changed.
954 953 * <li>The <code>Locale</code> class also supports language codes up to
955 954 * 8 characters in length. Therefore, the list returned by this method does
956 955 * not contain ALL valid codes that can be used to create Locales.
957 956 * </ul>
↓ open down ↓ |
884 lines elided |
↑ open up ↑ |
958 957 */
959 958 public static String[] getISOLanguages() {
960 959 if (isoLanguages == null) {
961 960 isoLanguages = getISO2Table(LocaleISOData.isoLanguageTable);
962 961 }
963 962 String[] result = new String[isoLanguages.length];
964 963 System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);
965 964 return result;
966 965 }
967 966
968 - private static final String[] getISO2Table(String table) {
967 + private static String[] getISO2Table(String table) {
969 968 int len = table.length() / 5;
970 969 String[] isoTable = new String[len];
971 970 for (int i = 0, j = 0; i < len; i++, j += 5) {
972 971 isoTable[i] = table.substring(j, j + 2);
973 972 }
974 973 return isoTable;
975 974 }
976 975
977 976 /**
978 977 * Returns the language code of this Locale.
979 978 *
980 979 * <p><b>Note:</b> ISO 639 is not a stable standard— some languages' codes have changed.
981 980 * Locale's constructor recognizes both the new and the old codes for the languages
982 981 * whose codes have changed, but this function always returns the old code. If you
983 982 * want to check for a specific language whose code has changed, don't do
984 983 * <pre>
985 984 * if (locale.getLanguage().equals("he")) // BAD!
986 985 * ...
987 986 * </pre>
988 987 * Instead, do
989 988 * <pre>
990 989 * if (locale.getLanguage().equals(new Locale("he").getLanguage()))
991 990 * ...
992 991 * </pre>
993 992 * @return The language code, or the empty string if none is defined.
994 993 * @see #getDisplayLanguage
995 994 */
996 995 public String getLanguage() {
997 996 return baseLocale.getLanguage();
998 997 }
999 998
1000 999 /**
1001 1000 * Returns the script for this locale, which should
1002 1001 * either be the empty string or an ISO 15924 4-letter script
1003 1002 * code. The first letter is uppercase and the rest are
1004 1003 * lowercase, for example, 'Latn', 'Cyrl'.
1005 1004 *
1006 1005 * @return The script code, or the empty string if none is defined.
1007 1006 * @see #getDisplayScript
1008 1007 * @since 1.7
1009 1008 */
1010 1009 public String getScript() {
1011 1010 return baseLocale.getScript();
1012 1011 }
1013 1012
1014 1013 /**
1015 1014 * Returns the country/region code for this locale, which should
1016 1015 * either be the empty string, an uppercase ISO 3166 2-letter code,
1017 1016 * or a UN M.49 3-digit code.
1018 1017 *
1019 1018 * @return The country/region code, or the empty string if none is defined.
1020 1019 * @see #getDisplayCountry
1021 1020 */
1022 1021 public String getCountry() {
1023 1022 return baseLocale.getRegion();
1024 1023 }
1025 1024
1026 1025 /**
↓ open down ↓ |
48 lines elided |
↑ open up ↑ |
1027 1026 * Returns the variant code for this locale.
1028 1027 *
1029 1028 * @return The variant code, or the empty string if none is defined.
1030 1029 * @see #getDisplayVariant
1031 1030 */
1032 1031 public String getVariant() {
1033 1032 return baseLocale.getVariant();
1034 1033 }
1035 1034
1036 1035 /**
1036 + * Returns {@code true} if this {@code Locale} has any <a href="#def_extensions">
1037 + * extensions</a>.
1038 + *
1039 + * @return {@code true} if this {@code Locale} has any extensions
1040 + * @since 1.8
1041 + */
1042 + public boolean hasExtensions() {
1043 + return localeExtensions != null;
1044 + }
1045 +
1046 + /**
1047 + * Returns a copy of this {@code Locale} with no <a href="#def_extensions">
1048 + * extensions</a>. If this {@code Locale} has no extensions, this {@code Locale}
1049 + * is returned.
1050 + *
1051 + * @return a copy of this {@code Locale} with no extensions, or {@code this}
1052 + * if {@code this} has no extensions
1053 + * @since 1.8
1054 + */
1055 + public Locale stripExtensions() {
1056 + return hasExtensions() ? Locale.getInstance(baseLocale, null) : this;
1057 + }
1058 +
1059 + /**
1037 1060 * Returns the extension (or private use) value associated with
1038 1061 * the specified key, or null if there is no extension
1039 1062 * associated with the key. To be well-formed, the key must be one
1040 1063 * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so
1041 1064 * for example 'z' and 'Z' represent the same extension.
1042 1065 *
1043 1066 * @param key the extension key
1044 1067 * @return The extension, or null if this locale defines no
1045 1068 * extension for the specified key.
1046 1069 * @throws IllegalArgumentException if key is not well-formed
1047 1070 * @see #PRIVATE_USE_EXTENSION
1048 1071 * @see #UNICODE_LOCALE_EXTENSION
1049 1072 * @since 1.7
1050 1073 */
1051 1074 public String getExtension(char key) {
1052 1075 if (!LocaleExtensions.isValidKey(key)) {
1053 1076 throw new IllegalArgumentException("Ill-formed extension key: " + key);
1054 1077 }
1055 - return (localeExtensions == null) ? null : localeExtensions.getExtensionValue(key);
1078 + return hasExtensions() ? localeExtensions.getExtensionValue(key) : null;
1056 1079 }
1057 1080
1058 1081 /**
1059 1082 * Returns the set of extension keys associated with this locale, or the
1060 1083 * empty set if it has no extensions. The returned set is unmodifiable.
1061 1084 * The keys will all be lower-case.
1062 1085 *
1063 1086 * @return The set of extension keys, or the empty set if this locale has
1064 1087 * no extensions.
1065 1088 * @since 1.7
1066 1089 */
1067 1090 public Set<Character> getExtensionKeys() {
1068 - if (localeExtensions == null) {
1091 + if (!hasExtensions()) {
1069 1092 return Collections.emptySet();
1070 1093 }
1071 1094 return localeExtensions.getKeys();
1072 1095 }
1073 1096
1074 1097 /**
1075 1098 * Returns the set of unicode locale attributes associated with
1076 1099 * this locale, or the empty set if it has no attributes. The
1077 1100 * returned set is unmodifiable.
1078 1101 *
1079 1102 * @return The set of attributes.
1080 1103 * @since 1.7
1081 1104 */
1082 1105 public Set<String> getUnicodeLocaleAttributes() {
1083 - if (localeExtensions == null) {
1106 + if (!hasExtensions()) {
1084 1107 return Collections.emptySet();
1085 1108 }
1086 1109 return localeExtensions.getUnicodeLocaleAttributes();
1087 1110 }
1088 1111
1089 1112 /**
1090 1113 * Returns the Unicode locale type associated with the specified Unicode locale key
1091 1114 * for this locale. Returns the empty string for keys that are defined with no type.
1092 1115 * Returns null if the key is not defined. Keys are case-insensitive. The key must
1093 1116 * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is
1094 1117 * thrown.
1095 1118 *
1096 1119 * @param key the Unicode locale key
1097 1120 * @return The Unicode locale type associated with the key, or null if the
1098 1121 * locale does not define the key.
1099 1122 * @throws IllegalArgumentException if the key is not well-formed
1100 1123 * @throws NullPointerException if <code>key</code> is null
1101 1124 * @since 1.7
1102 1125 */
1103 1126 public String getUnicodeLocaleType(String key) {
1104 - if (!UnicodeLocaleExtension.isKey(key)) {
1127 + if (!isUnicodeExtensionKey(key)) {
1105 1128 throw new IllegalArgumentException("Ill-formed Unicode locale key: " + key);
1106 1129 }
1107 - return (localeExtensions == null) ? null : localeExtensions.getUnicodeLocaleType(key);
1130 + return hasExtensions() ? localeExtensions.getUnicodeLocaleType(key) : null;
1108 1131 }
1109 1132
1110 1133 /**
1111 1134 * Returns the set of Unicode locale keys defined by this locale, or the empty set if
1112 1135 * this locale has none. The returned set is immutable. Keys are all lower case.
1113 1136 *
1114 1137 * @return The set of Unicode locale keys, or the empty set if this locale has
1115 1138 * no Unicode locale keywords.
1116 1139 * @since 1.7
1117 1140 */
1118 1141 public Set<String> getUnicodeLocaleKeys() {
1119 1142 if (localeExtensions == null) {
1120 1143 return Collections.emptySet();
1121 1144 }
1122 1145 return localeExtensions.getUnicodeLocaleKeys();
1123 1146 }
1124 1147
1125 1148 /**
1126 1149 * Package locale method returning the Locale's BaseLocale,
1127 1150 * used by ResourceBundle
1128 1151 * @return base locale of this Locale
1129 1152 */
1130 1153 BaseLocale getBaseLocale() {
1131 1154 return baseLocale;
1132 1155 }
1133 1156
1134 1157 /**
1135 1158 * Package private method returning the Locale's LocaleExtensions,
1136 1159 * used by ResourceBundle.
1137 1160 * @return locale exnteions of this Locale,
1138 1161 * or {@code null} if no extensions are defined
1139 1162 */
1140 1163 LocaleExtensions getLocaleExtensions() {
1141 1164 return localeExtensions;
1142 1165 }
1143 1166
1144 1167 /**
1145 1168 * Returns a string representation of this <code>Locale</code>
1146 1169 * object, consisting of language, country, variant, script,
1147 1170 * and extensions as below:
1148 1171 * <p><blockquote>
1149 1172 * language + "_" + country + "_" + (variant + "_#" | "#") + script + "-" + extensions
1150 1173 * </blockquote>
1151 1174 *
1152 1175 * Language is always lower case, country is always upper case, script is always title
1153 1176 * case, and extensions are always lower case. Extensions and private use subtags
1154 1177 * will be in canonical order as explained in {@link #toLanguageTag}.
1155 1178 *
1156 1179 * <p>When the locale has neither script nor extensions, the result is the same as in
1157 1180 * Java 6 and prior.
1158 1181 *
1159 1182 * <p>If both the language and country fields are missing, this function will return
1160 1183 * the empty string, even if the variant, script, or extensions field is present (you
1161 1184 * can't have a locale with just a variant, the variant must accompany a well-formed
1162 1185 * language or country code).
1163 1186 *
1164 1187 * <p>If script or extensions are present and variant is missing, no underscore is
1165 1188 * added before the "#".
1166 1189 *
1167 1190 * <p>This behavior is designed to support debugging and to be compatible with
1168 1191 * previous uses of <code>toString</code> that expected language, country, and variant
1169 1192 * fields only. To represent a Locale as a String for interchange purposes, use
1170 1193 * {@link #toLanguageTag}.
1171 1194 *
1172 1195 * <p>Examples: <ul><tt>
1173 1196 * <li>en
1174 1197 * <li>de_DE
1175 1198 * <li>_GB
1176 1199 * <li>en_US_WIN
1177 1200 * <li>de__POSIX
1178 1201 * <li>zh_CN_#Hans
1179 1202 * <li>zh_TW_#Hant-x-java
1180 1203 * <li>th_TH_TH_#u-nu-thai</tt></ul>
1181 1204 *
1182 1205 * @return A string representation of the Locale, for debugging.
1183 1206 * @see #getDisplayName
1184 1207 * @see #toLanguageTag
1185 1208 */
1186 1209 @Override
1187 1210 public final String toString() {
1188 1211 boolean l = (baseLocale.getLanguage().length() != 0);
1189 1212 boolean s = (baseLocale.getScript().length() != 0);
1190 1213 boolean r = (baseLocale.getRegion().length() != 0);
1191 1214 boolean v = (baseLocale.getVariant().length() != 0);
1192 1215 boolean e = (localeExtensions != null && localeExtensions.getID().length() != 0);
1193 1216
1194 1217 StringBuilder result = new StringBuilder(baseLocale.getLanguage());
1195 1218 if (r || (l && (v || s || e))) {
1196 1219 result.append('_')
1197 1220 .append(baseLocale.getRegion()); // This may just append '_'
1198 1221 }
1199 1222 if (v && (l || r)) {
1200 1223 result.append('_')
1201 1224 .append(baseLocale.getVariant());
1202 1225 }
1203 1226
1204 1227 if (s && (l || r)) {
1205 1228 result.append("_#")
1206 1229 .append(baseLocale.getScript());
1207 1230 }
1208 1231
1209 1232 if (e && (l || r)) {
1210 1233 result.append('_');
1211 1234 if (!s) {
1212 1235 result.append('#');
1213 1236 }
1214 1237 result.append(localeExtensions.getID());
1215 1238 }
1216 1239
1217 1240 return result.toString();
1218 1241 }
1219 1242
1220 1243 /**
1221 1244 * Returns a well-formed IETF BCP 47 language tag representing
1222 1245 * this locale.
1223 1246 *
1224 1247 * <p>If this <code>Locale</code> has a language, country, or
1225 1248 * variant that does not satisfy the IETF BCP 47 language tag
1226 1249 * syntax requirements, this method handles these fields as
1227 1250 * described below:
1228 1251 *
1229 1252 * <p><b>Language:</b> If language is empty, or not <a
1230 1253 * href="#def_language" >well-formed</a> (for example "a" or
1231 1254 * "e2"), it will be emitted as "und" (Undetermined).
1232 1255 *
1233 1256 * <p><b>Country:</b> If country is not <a
1234 1257 * href="#def_region">well-formed</a> (for example "12" or "USA"),
1235 1258 * it will be omitted.
1236 1259 *
1237 1260 * <p><b>Variant:</b> If variant <b>is</b> <a
1238 1261 * href="#def_variant">well-formed</a>, each sub-segment
1239 1262 * (delimited by '-' or '_') is emitted as a subtag. Otherwise:
1240 1263 * <ul>
1241 1264 *
1242 1265 * <li>if all sub-segments match <code>[0-9a-zA-Z]{1,8}</code>
1243 1266 * (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first
1244 1267 * ill-formed sub-segment and all following will be appended to
1245 1268 * the private use subtag. The first appended subtag will be
1246 1269 * "lvariant", followed by the sub-segments in order, separated by
1247 1270 * hyphen. For example, "x-lvariant-WIN",
1248 1271 * "Oracle-x-lvariant-JDK-Standard-Edition".
1249 1272 *
1250 1273 * <li>if any sub-segment does not match
1251 1274 * <code>[0-9a-zA-Z]{1,8}</code>, the variant will be truncated
1252 1275 * and the problematic sub-segment and all following sub-segments
1253 1276 * will be omitted. If the remainder is non-empty, it will be
1254 1277 * emitted as a private use subtag as above (even if the remainder
1255 1278 * turns out to be well-formed). For example,
1256 1279 * "Solaris_isjustthecoolestthing" is emitted as
1257 1280 * "x-lvariant-Solaris", not as "solaris".</li></ul>
1258 1281 *
1259 1282 * <p><b>Special Conversions:</b> Java supports some old locale
1260 1283 * representations, including deprecated ISO language codes,
1261 1284 * for compatibility. This method performs the following
1262 1285 * conversions:
1263 1286 * <ul>
1264 1287 *
1265 1288 * <li>Deprecated ISO language codes "iw", "ji", and "in" are
1266 1289 * converted to "he", "yi", and "id", respectively.
1267 1290 *
1268 1291 * <li>A locale with language "no", country "NO", and variant
1269 1292 * "NY", representing Norwegian Nynorsk (Norway), is converted
1270 1293 * to a language tag "nn-NO".</li></ul>
1271 1294 *
1272 1295 * <p><b>Note:</b> Although the language tag created by this
1273 1296 * method is well-formed (satisfies the syntax requirements
1274 1297 * defined by the IETF BCP 47 specification), it is not
1275 1298 * necessarily a valid BCP 47 language tag. For example,
1276 1299 * <pre>
1277 1300 * new Locale("xx", "YY").toLanguageTag();</pre>
↓ open down ↓ |
160 lines elided |
↑ open up ↑ |
1278 1301 *
1279 1302 * will return "xx-YY", but the language subtag "xx" and the
1280 1303 * region subtag "YY" are invalid because they are not registered
1281 1304 * in the IANA Language Subtag Registry.
1282 1305 *
1283 1306 * @return a BCP47 language tag representing the locale
1284 1307 * @see #forLanguageTag(String)
1285 1308 * @since 1.7
1286 1309 */
1287 1310 public String toLanguageTag() {
1311 + if (languageTag != null) {
1312 + return languageTag;
1313 + }
1314 +
1288 1315 LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);
1289 1316 StringBuilder buf = new StringBuilder();
1290 1317
1291 1318 String subtag = tag.getLanguage();
1292 1319 if (subtag.length() > 0) {
1293 1320 buf.append(LanguageTag.canonicalizeLanguage(subtag));
1294 1321 }
1295 1322
1296 1323 subtag = tag.getScript();
1297 1324 if (subtag.length() > 0) {
1298 1325 buf.append(LanguageTag.SEP);
1299 1326 buf.append(LanguageTag.canonicalizeScript(subtag));
1300 1327 }
1301 1328
1302 1329 subtag = tag.getRegion();
1303 1330 if (subtag.length() > 0) {
1304 1331 buf.append(LanguageTag.SEP);
1305 1332 buf.append(LanguageTag.canonicalizeRegion(subtag));
1306 1333 }
1307 1334
1308 1335 List<String>subtags = tag.getVariants();
1309 1336 for (String s : subtags) {
1310 1337 buf.append(LanguageTag.SEP);
1311 1338 // preserve casing
1312 1339 buf.append(s);
1313 1340 }
1314 1341
1315 1342 subtags = tag.getExtensions();
1316 1343 for (String s : subtags) {
1317 1344 buf.append(LanguageTag.SEP);
1318 1345 buf.append(LanguageTag.canonicalizeExtension(s));
1319 1346 }
1320 1347
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
1321 1348 subtag = tag.getPrivateuse();
1322 1349 if (subtag.length() > 0) {
1323 1350 if (buf.length() > 0) {
1324 1351 buf.append(LanguageTag.SEP);
1325 1352 }
1326 1353 buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);
1327 1354 // preserve casing
1328 1355 buf.append(subtag);
1329 1356 }
1330 1357
1331 - return buf.toString();
1358 + String langTag = buf.toString();
1359 + synchronized (this) {
1360 + if (languageTag == null) {
1361 + languageTag = langTag;
1362 + }
1363 + }
1364 + return languageTag;
1332 1365 }
1333 1366
1334 1367 /**
1335 1368 * Returns a locale for the specified IETF BCP 47 language tag string.
1336 1369 *
1337 1370 * <p>If the specified language tag contains any ill-formed subtags,
1338 1371 * the first such subtag and all following subtags are ignored. Compare
1339 1372 * to {@link Locale.Builder#setLanguageTag} which throws an exception
1340 1373 * in this case.
1341 1374 *
1342 1375 * <p>The following <b>conversions</b> are performed:<ul>
1343 1376 *
1344 1377 * <li>The language code "und" is mapped to language "".
1345 1378 *
1346 1379 * <li>The language codes "he", "yi", and "id" are mapped to "iw",
1347 1380 * "ji", and "in" respectively. (This is the same canonicalization
1348 1381 * that's done in Locale's constructors.)
1349 1382 *
1350 1383 * <li>The portion of a private use subtag prefixed by "lvariant",
1351 1384 * if any, is removed and appended to the variant field in the
1352 1385 * result locale (without case normalization). If it is then
1353 1386 * empty, the private use subtag is discarded:
1354 1387 *
1355 1388 * <pre>
1356 1389 * Locale loc;
1357 1390 * loc = Locale.forLanguageTag("en-US-x-lvariant-POSIX");
1358 1391 * loc.getVariant(); // returns "POSIX"
1359 1392 * loc.getExtension('x'); // returns null
1360 1393 *
1361 1394 * loc = Locale.forLanguageTag("de-POSIX-x-URP-lvariant-Abc-Def");
1362 1395 * loc.getVariant(); // returns "POSIX_Abc_Def"
1363 1396 * loc.getExtension('x'); // returns "urp"
1364 1397 * </pre>
1365 1398 *
1366 1399 * <li>When the languageTag argument contains an extlang subtag,
1367 1400 * the first such subtag is used as the language, and the primary
1368 1401 * language subtag and other extlang subtags are ignored:
1369 1402 *
1370 1403 * <pre>
1371 1404 * Locale.forLanguageTag("ar-aao").getLanguage(); // returns "aao"
1372 1405 * Locale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US"
1373 1406 * </pre>
1374 1407 *
1375 1408 * <li>Case is normalized except for variant tags, which are left
1376 1409 * unchanged. Language is normalized to lower case, script to
1377 1410 * title case, country to upper case, and extensions to lower
1378 1411 * case.
1379 1412 *
1380 1413 * <li>If, after processing, the locale would exactly match either
1381 1414 * ja_JP_JP or th_TH_TH with no extensions, the appropriate
1382 1415 * extensions are added as though the constructor had been called:
1383 1416 *
1384 1417 * <pre>
1385 1418 * Locale.forLanguageTag("ja-JP-x-lvariant-JP").toLanguageTag();
1386 1419 * // returns "ja-JP-u-ca-japanese-x-lvariant-JP"
1387 1420 * Locale.forLanguageTag("th-TH-x-lvariant-TH").toLanguageTag();
1388 1421 * // returns "th-TH-u-nu-thai-x-lvariant-TH"
1389 1422 * <pre></ul>
1390 1423 *
1391 1424 * <p>This implements the 'Language-Tag' production of BCP47, and
1392 1425 * so supports grandfathered (regular and irregular) as well as
1393 1426 * private use language tags. Stand alone private use tags are
1394 1427 * represented as empty language and extension 'x-whatever',
1395 1428 * and grandfathered tags are converted to their canonical replacements
1396 1429 * where they exist.
1397 1430 *
1398 1431 * <p>Grandfathered tags with canonical replacements are as follows:
1399 1432 *
1400 1433 * <table>
1401 1434 * <tbody align="center">
1402 1435 * <tr><th>grandfathered tag</th><th> </th><th>modern replacement</th></tr>
1403 1436 * <tr><td>art-lojban</td><td> </td><td>jbo</td></tr>
1404 1437 * <tr><td>i-ami</td><td> </td><td>ami</td></tr>
1405 1438 * <tr><td>i-bnn</td><td> </td><td>bnn</td></tr>
1406 1439 * <tr><td>i-hak</td><td> </td><td>hak</td></tr>
1407 1440 * <tr><td>i-klingon</td><td> </td><td>tlh</td></tr>
1408 1441 * <tr><td>i-lux</td><td> </td><td>lb</td></tr>
1409 1442 * <tr><td>i-navajo</td><td> </td><td>nv</td></tr>
1410 1443 * <tr><td>i-pwn</td><td> </td><td>pwn</td></tr>
1411 1444 * <tr><td>i-tao</td><td> </td><td>tao</td></tr>
1412 1445 * <tr><td>i-tay</td><td> </td><td>tay</td></tr>
1413 1446 * <tr><td>i-tsu</td><td> </td><td>tsu</td></tr>
1414 1447 * <tr><td>no-bok</td><td> </td><td>nb</td></tr>
1415 1448 * <tr><td>no-nyn</td><td> </td><td>nn</td></tr>
1416 1449 * <tr><td>sgn-BE-FR</td><td> </td><td>sfb</td></tr>
1417 1450 * <tr><td>sgn-BE-NL</td><td> </td><td>vgt</td></tr>
1418 1451 * <tr><td>sgn-CH-DE</td><td> </td><td>sgg</td></tr>
1419 1452 * <tr><td>zh-guoyu</td><td> </td><td>cmn</td></tr>
1420 1453 * <tr><td>zh-hakka</td><td> </td><td>hak</td></tr>
1421 1454 * <tr><td>zh-min-nan</td><td> </td><td>nan</td></tr>
1422 1455 * <tr><td>zh-xiang</td><td> </td><td>hsn</td></tr>
1423 1456 * </tbody>
1424 1457 * </table>
1425 1458 *
1426 1459 * <p>Grandfathered tags with no modern replacement will be
1427 1460 * converted as follows:
1428 1461 *
1429 1462 * <table>
1430 1463 * <tbody align="center">
1431 1464 * <tr><th>grandfathered tag</th><th> </th><th>converts to</th></tr>
1432 1465 * <tr><td>cel-gaulish</td><td> </td><td>xtg-x-cel-gaulish</td></tr>
1433 1466 * <tr><td>en-GB-oed</td><td> </td><td>en-GB-x-oed</td></tr>
1434 1467 * <tr><td>i-default</td><td> </td><td>en-x-i-default</td></tr>
1435 1468 * <tr><td>i-enochian</td><td> </td><td>und-x-i-enochian</td></tr>
1436 1469 * <tr><td>i-mingo</td><td> </td><td>see-x-i-mingo</td></tr>
1437 1470 * <tr><td>zh-min</td><td> </td><td>nan-x-zh-min</td></tr>
1438 1471 * </tbody>
1439 1472 * </table>
1440 1473 *
1441 1474 * <p>For a list of all grandfathered tags, see the
1442 1475 * IANA Language Subtag Registry (search for "Type: grandfathered").
1443 1476 *
1444 1477 * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>
1445 1478 * and <code>forLanguageTag</code> will round-trip.
1446 1479 *
1447 1480 * @param languageTag the language tag
1448 1481 * @return The locale that best represents the language tag.
1449 1482 * @throws NullPointerException if <code>languageTag</code> is <code>null</code>
1450 1483 * @see #toLanguageTag()
1451 1484 * @see java.util.Locale.Builder#setLanguageTag(String)
1452 1485 * @since 1.7
1453 1486 */
1454 1487 public static Locale forLanguageTag(String languageTag) {
1455 1488 LanguageTag tag = LanguageTag.parse(languageTag, null);
1456 1489 InternalLocaleBuilder bldr = new InternalLocaleBuilder();
1457 1490 bldr.setLanguageTag(tag);
1458 1491 BaseLocale base = bldr.getBaseLocale();
1459 1492 LocaleExtensions exts = bldr.getLocaleExtensions();
1460 1493 if (exts == null && base.getVariant().length() > 0) {
1461 1494 exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),
1462 1495 base.getRegion(), base.getVariant());
1463 1496 }
1464 1497 return getInstance(base, exts);
1465 1498 }
1466 1499
1467 1500 /**
1468 1501 * Returns a three-letter abbreviation of this locale's language.
1469 1502 * If the language matches an ISO 639-1 two-letter code, the
1470 1503 * corresponding ISO 639-2/T three-letter lowercase code is
1471 1504 * returned. The ISO 639-2 language codes can be found on-line,
1472 1505 * see "Codes for the Representation of Names of Languages Part 2:
1473 1506 * Alpha-3 Code". If the locale specifies a three-letter
1474 1507 * language, the language is returned as is. If the locale does
1475 1508 * not specify a language the empty string is returned.
1476 1509 *
1477 1510 * @return A three-letter abbreviation of this locale's language.
1478 1511 * @exception MissingResourceException Throws MissingResourceException if
1479 1512 * three-letter language abbreviation is not available for this locale.
1480 1513 */
1481 1514 public String getISO3Language() throws MissingResourceException {
1482 1515 String lang = baseLocale.getLanguage();
1483 1516 if (lang.length() == 3) {
1484 1517 return lang;
1485 1518 }
1486 1519
1487 1520 String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
1488 1521 if (language3 == null) {
1489 1522 throw new MissingResourceException("Couldn't find 3-letter language code for "
1490 1523 + lang, "FormatData_" + toString(), "ShortLanguage");
1491 1524 }
1492 1525 return language3;
1493 1526 }
1494 1527
1495 1528 /**
1496 1529 * Returns a three-letter abbreviation for this locale's country.
1497 1530 * If the country matches an ISO 3166-1 alpha-2 code, the
1498 1531 * corresponding ISO 3166-1 alpha-3 uppercase code is returned.
1499 1532 * If the locale doesn't specify a country, this will be the empty
1500 1533 * string.
1501 1534 *
1502 1535 * <p>The ISO 3166-1 codes can be found on-line.
1503 1536 *
1504 1537 * @return A three-letter abbreviation of this locale's country.
1505 1538 * @exception MissingResourceException Throws MissingResourceException if the
1506 1539 * three-letter country abbreviation is not available for this locale.
↓ open down ↓ |
165 lines elided |
↑ open up ↑ |
1507 1540 */
1508 1541 public String getISO3Country() throws MissingResourceException {
1509 1542 String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
1510 1543 if (country3 == null) {
1511 1544 throw new MissingResourceException("Couldn't find 3-letter country code for "
1512 1545 + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
1513 1546 }
1514 1547 return country3;
1515 1548 }
1516 1549
1517 - private static final String getISO3Code(String iso2Code, String table) {
1550 + private static String getISO3Code(String iso2Code, String table) {
1518 1551 int codeLength = iso2Code.length();
1519 1552 if (codeLength == 0) {
1520 1553 return "";
1521 1554 }
1522 1555
1523 1556 int tableLength = table.length();
1524 1557 int index = tableLength;
1525 1558 if (codeLength == 2) {
1526 1559 char c1 = iso2Code.charAt(0);
1527 1560 char c2 = iso2Code.charAt(1);
1528 1561 for (index = 0; index < tableLength; index += 5) {
1529 1562 if (table.charAt(index) == c1
1530 1563 && table.charAt(index + 1) == c2) {
1531 1564 break;
1532 1565 }
1533 1566 }
1534 1567 }
1535 1568 return index < tableLength ? table.substring(index + 2, index + 5) : null;
1536 1569 }
1537 1570
1538 1571 /**
1539 1572 * Returns a name for the locale's language that is appropriate for display to the
1540 1573 * user.
1541 1574 * If possible, the name returned will be localized for the default locale.
1542 1575 * For example, if the locale is fr_FR and the default locale
1543 1576 * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
1544 1577 * the default locale is fr_FR, getDisplayLanguage() will return "anglais".
1545 1578 * If the name returned cannot be localized for the default locale,
1546 1579 * (say, we don't have a Japanese name for Croatian),
1547 1580 * this function falls back on the English name, and uses the ISO code as a last-resort
1548 1581 * value. If the locale doesn't specify a language, this function returns the empty string.
1549 1582 */
1550 1583 public final String getDisplayLanguage() {
1551 1584 return getDisplayLanguage(getDefault(Category.DISPLAY));
1552 1585 }
1553 1586
1554 1587 /**
1555 1588 * Returns a name for the locale's language that is appropriate for display to the
1556 1589 * user.
1557 1590 * If possible, the name returned will be localized according to inLocale.
1558 1591 * For example, if the locale is fr_FR and inLocale
1559 1592 * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and
1560 1593 * inLocale is fr_FR, getDisplayLanguage() will return "anglais".
1561 1594 * If the name returned cannot be localized according to inLocale,
1562 1595 * (say, we don't have a Japanese name for Croatian),
1563 1596 * this function falls back on the English name, and finally
1564 1597 * on the ISO code as a last-resort value. If the locale doesn't specify a language,
1565 1598 * this function returns the empty string.
1566 1599 *
1567 1600 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1568 1601 */
1569 1602 public String getDisplayLanguage(Locale inLocale) {
1570 1603 return getDisplayString(baseLocale.getLanguage(), inLocale, DISPLAY_LANGUAGE);
1571 1604 }
1572 1605
1573 1606 /**
1574 1607 * Returns a name for the the locale's script that is appropriate for display to
1575 1608 * the user. If possible, the name will be localized for the default locale. Returns
1576 1609 * the empty string if this locale doesn't specify a script code.
1577 1610 *
1578 1611 * @return the display name of the script code for the current default locale
1579 1612 * @since 1.7
1580 1613 */
1581 1614 public String getDisplayScript() {
1582 1615 return getDisplayScript(getDefault(Category.DISPLAY));
1583 1616 }
1584 1617
1585 1618 /**
1586 1619 * Returns a name for the locale's script that is appropriate
1587 1620 * for display to the user. If possible, the name will be
1588 1621 * localized for the given locale. Returns the empty string if
1589 1622 * this locale doesn't specify a script code.
1590 1623 *
1591 1624 * @return the display name of the script code for the current default locale
1592 1625 * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1593 1626 * @since 1.7
1594 1627 */
1595 1628 public String getDisplayScript(Locale inLocale) {
1596 1629 return getDisplayString(baseLocale.getScript(), inLocale, DISPLAY_SCRIPT);
1597 1630 }
1598 1631
1599 1632 /**
1600 1633 * Returns a name for the locale's country that is appropriate for display to the
1601 1634 * user.
1602 1635 * If possible, the name returned will be localized for the default locale.
1603 1636 * For example, if the locale is fr_FR and the default locale
1604 1637 * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
1605 1638 * the default locale is fr_FR, getDisplayCountry() will return "Etats-Unis".
1606 1639 * If the name returned cannot be localized for the default locale,
1607 1640 * (say, we don't have a Japanese name for Croatia),
1608 1641 * this function falls back on the English name, and uses the ISO code as a last-resort
1609 1642 * value. If the locale doesn't specify a country, this function returns the empty string.
1610 1643 */
1611 1644 public final String getDisplayCountry() {
1612 1645 return getDisplayCountry(getDefault(Category.DISPLAY));
1613 1646 }
1614 1647
1615 1648 /**
1616 1649 * Returns a name for the locale's country that is appropriate for display to the
1617 1650 * user.
1618 1651 * If possible, the name returned will be localized according to inLocale.
1619 1652 * For example, if the locale is fr_FR and inLocale
1620 1653 * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and
1621 1654 * inLocale is fr_FR, getDisplayCountry() will return "Etats-Unis".
1622 1655 * If the name returned cannot be localized according to inLocale.
1623 1656 * (say, we don't have a Japanese name for Croatia),
1624 1657 * this function falls back on the English name, and finally
1625 1658 * on the ISO code as a last-resort value. If the locale doesn't specify a country,
1626 1659 * this function returns the empty string.
1627 1660 *
1628 1661 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1629 1662 */
1630 1663 public String getDisplayCountry(Locale inLocale) {
1631 1664 return getDisplayString(baseLocale.getRegion(), inLocale, DISPLAY_COUNTRY);
1632 1665 }
↓ open down ↓ |
105 lines elided |
↑ open up ↑ |
1633 1666
1634 1667 private String getDisplayString(String code, Locale inLocale, int type) {
1635 1668 if (code.length() == 0) {
1636 1669 return "";
1637 1670 }
1638 1671
1639 1672 if (inLocale == null) {
1640 1673 throw new NullPointerException();
1641 1674 }
1642 1675
1643 - try {
1644 - OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1645 - String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
1646 - String result = null;
1647 -
1648 - // Check whether a provider can provide an implementation that's closer
1649 - // to the requested locale than what the Java runtime itself can provide.
1650 - LocaleServiceProviderPool pool =
1651 - LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
1652 - if (pool.hasProviders()) {
1653 - result = pool.getLocalizedObject(
1654 - LocaleNameGetter.INSTANCE,
1655 - inLocale, bundle, key,
1656 - type, code);
1657 - }
1658 -
1659 - if (result == null) {
1660 - result = bundle.getString(key);
1661 - }
1662 -
1676 + LocaleServiceProviderPool pool =
1677 + LocaleServiceProviderPool.getPool(LocaleNameProvider.class);
1678 + String key = (type == DISPLAY_VARIANT ? "%%"+code : code);
1679 + String result = pool.getLocalizedObject(
1680 + LocaleNameGetter.INSTANCE,
1681 + inLocale, key, type, code);
1663 1682 if (result != null) {
1664 1683 return result;
1665 1684 }
1666 - }
1667 - catch (Exception e) {
1668 - // just fall through
1669 - }
1685 +
1670 1686 return code;
1671 1687 }
1672 1688
1673 1689 /**
1674 1690 * Returns a name for the locale's variant code that is appropriate for display to the
1675 1691 * user. If possible, the name will be localized for the default locale. If the locale
1676 1692 * doesn't specify a variant code, this function returns the empty string.
1677 1693 */
1678 1694 public final String getDisplayVariant() {
1679 1695 return getDisplayVariant(getDefault(Category.DISPLAY));
1680 1696 }
1681 1697
1682 1698 /**
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
1683 1699 * Returns a name for the locale's variant code that is appropriate for display to the
1684 1700 * user. If possible, the name will be localized for inLocale. If the locale
1685 1701 * doesn't specify a variant code, this function returns the empty string.
1686 1702 *
1687 1703 * @exception NullPointerException if <code>inLocale</code> is <code>null</code>
1688 1704 */
1689 1705 public String getDisplayVariant(Locale inLocale) {
1690 1706 if (baseLocale.getVariant().length() == 0)
1691 1707 return "";
1692 1708
1693 - OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1709 + OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale);
1694 1710
1695 1711 String names[] = getDisplayVariantArray(bundle, inLocale);
1696 1712
1697 1713 // Get the localized patterns for formatting a list, and use
1698 1714 // them to format the list.
1699 1715 String listPattern = null;
1700 1716 String listCompositionPattern = null;
1701 1717 try {
1702 1718 listPattern = bundle.getString("ListPattern");
1703 1719 listCompositionPattern = bundle.getString("ListCompositionPattern");
1704 1720 } catch (MissingResourceException e) {
1705 1721 }
1706 1722 return formatList(names, listPattern, listCompositionPattern);
1707 1723 }
1708 1724
1709 1725 /**
1710 1726 * Returns a name for the locale that is appropriate for display to the
1711 1727 * user. This will be the values returned by getDisplayLanguage(),
1712 1728 * getDisplayScript(), getDisplayCountry(), and getDisplayVariant() assembled
1713 1729 * into a single string. The the non-empty values are used in order,
1714 1730 * with the second and subsequent names in parentheses. For example:
1715 1731 * <blockquote>
1716 1732 * language (script, country, variant)<br>
1717 1733 * language (country)<br>
1718 1734 * language (variant)<br>
1719 1735 * script (country)<br>
1720 1736 * country<br>
1721 1737 * </blockquote>
1722 1738 * depending on which fields are specified in the locale. If the
1723 1739 * language, sacript, country, and variant fields are all empty,
1724 1740 * this function returns the empty string.
1725 1741 */
1726 1742 public final String getDisplayName() {
1727 1743 return getDisplayName(getDefault(Category.DISPLAY));
1728 1744 }
1729 1745
1730 1746 /**
1731 1747 * Returns a name for the locale that is appropriate for display
1732 1748 * to the user. This will be the values returned by
1733 1749 * getDisplayLanguage(), getDisplayScript(),getDisplayCountry(),
1734 1750 * and getDisplayVariant() assembled into a single string.
1735 1751 * The non-empty values are used in order,
1736 1752 * with the second and subsequent names in parentheses. For example:
1737 1753 * <blockquote>
1738 1754 * language (script, country, variant)<br>
1739 1755 * language (country)<br>
1740 1756 * language (variant)<br>
↓ open down ↓ |
37 lines elided |
↑ open up ↑ |
1741 1757 * script (country)<br>
1742 1758 * country<br>
1743 1759 * </blockquote>
1744 1760 * depending on which fields are specified in the locale. If the
1745 1761 * language, script, country, and variant fields are all empty,
1746 1762 * this function returns the empty string.
1747 1763 *
1748 1764 * @throws NullPointerException if <code>inLocale</code> is <code>null</code>
1749 1765 */
1750 1766 public String getDisplayName(Locale inLocale) {
1751 - OpenListResourceBundle bundle = LocaleData.getLocaleNames(inLocale);
1767 + OpenListResourceBundle bundle = LocaleProviderAdapter.forJRE().getLocaleData().getLocaleNames(inLocale);
1752 1768
1753 1769 String languageName = getDisplayLanguage(inLocale);
1754 1770 String scriptName = getDisplayScript(inLocale);
1755 1771 String countryName = getDisplayCountry(inLocale);
1756 1772 String[] variantNames = getDisplayVariantArray(bundle, inLocale);
1757 1773
1758 1774 // Get the localized patterns for formatting a display name.
1759 1775 String displayNamePattern = null;
1760 1776 String listPattern = null;
1761 1777 String listCompositionPattern = null;
1762 1778 try {
1763 1779 displayNamePattern = bundle.getString("DisplayNamePattern");
1764 1780 listPattern = bundle.getString("ListPattern");
1765 1781 listCompositionPattern = bundle.getString("ListCompositionPattern");
1766 1782 } catch (MissingResourceException e) {
1767 1783 }
1768 1784
1769 1785 // The display name consists of a main name, followed by qualifiers.
1770 1786 // Typically, the format is "MainName (Qualifier, Qualifier)" but this
1771 1787 // depends on what pattern is stored in the display locale.
1772 1788 String mainName = null;
1773 1789 String[] qualifierNames = null;
1774 1790
1775 1791 // The main name is the language, or if there is no language, the script,
1776 1792 // then if no script, the country. If there is no language/script/country
1777 1793 // (an anomalous situation) then the display name is simply the variant's
1778 1794 // display name.
1779 1795 if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {
1780 1796 if (variantNames.length == 0) {
1781 1797 return "";
1782 1798 } else {
1783 1799 return formatList(variantNames, listPattern, listCompositionPattern);
1784 1800 }
1785 1801 }
1786 1802 ArrayList<String> names = new ArrayList<>(4);
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
1787 1803 if (languageName.length() != 0) {
1788 1804 names.add(languageName);
1789 1805 }
1790 1806 if (scriptName.length() != 0) {
1791 1807 names.add(scriptName);
1792 1808 }
1793 1809 if (countryName.length() != 0) {
1794 1810 names.add(countryName);
1795 1811 }
1796 1812 if (variantNames.length != 0) {
1797 - for (String var : variantNames) {
1798 - names.add(var);
1799 - }
1813 + names.addAll(Arrays.asList(variantNames));
1800 1814 }
1801 1815
1802 1816 // The first one in the main name
1803 1817 mainName = names.get(0);
1804 1818
1805 1819 // Others are qualifiers
1806 1820 int numNames = names.size();
1807 1821 qualifierNames = (numNames > 1) ?
1808 1822 names.subList(1, numNames).toArray(new String[numNames - 1]) : new String[0];
1809 1823
1810 1824 // Create an array whose first element is the number of remaining
1811 1825 // elements. This serves as a selector into a ChoiceFormat pattern from
1812 1826 // the resource. The second and third elements are the main name and
1813 1827 // the qualifier; if there are no qualifiers, the third element is
1814 1828 // unused by the format pattern.
1815 1829 Object[] displayNames = {
1816 1830 new Integer(qualifierNames.length != 0 ? 2 : 1),
1817 1831 mainName,
1818 1832 // We could also just call formatList() and have it handle the empty
1819 1833 // list case, but this is more efficient, and we want it to be
1820 1834 // efficient since all the language-only locales will not have any
1821 1835 // qualifiers.
1822 1836 qualifierNames.length != 0 ? formatList(qualifierNames, listPattern, listCompositionPattern) : null
1823 1837 };
1824 1838
1825 1839 if (displayNamePattern != null) {
1826 1840 return new MessageFormat(displayNamePattern).format(displayNames);
1827 1841 }
1828 1842 else {
1829 1843 // If we cannot get the message format pattern, then we use a simple
1830 1844 // hard-coded pattern. This should not occur in practice unless the
1831 1845 // installation is missing some core files (FormatData etc.).
1832 1846 StringBuilder result = new StringBuilder();
1833 1847 result.append((String)displayNames[1]);
1834 1848 if (displayNames.length > 2) {
1835 1849 result.append(" (");
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
1836 1850 result.append((String)displayNames[2]);
1837 1851 result.append(')');
1838 1852 }
1839 1853 return result.toString();
1840 1854 }
1841 1855 }
1842 1856
1843 1857 /**
1844 1858 * Overrides Cloneable.
1845 1859 */
1860 + @Override
1846 1861 public Object clone()
1847 1862 {
1848 1863 try {
1849 1864 Locale that = (Locale)super.clone();
1850 1865 return that;
1851 1866 } catch (CloneNotSupportedException e) {
1852 1867 throw new InternalError(e);
1853 1868 }
1854 1869 }
1855 1870
1856 1871 /**
1857 1872 * Override hashCode.
1858 1873 * Since Locales are often used in hashtables, caches the value
1859 1874 * for speed.
1860 1875 */
1861 1876 @Override
1862 1877 public int hashCode() {
1863 1878 int hc = hashCodeValue;
1864 1879 if (hc == 0) {
1865 1880 hc = baseLocale.hashCode();
1866 1881 if (localeExtensions != null) {
1867 1882 hc ^= localeExtensions.hashCode();
1868 1883 }
1869 1884 hashCodeValue = hc;
1870 1885 }
1871 1886 return hc;
1872 1887 }
1873 1888
1874 1889 // Overrides
1875 1890
1876 1891 /**
1877 1892 * Returns true if this Locale is equal to another object. A Locale is
1878 1893 * deemed equal to another Locale with identical language, script, country,
1879 1894 * variant and extensions, and unequal to all other objects.
1880 1895 *
1881 1896 * @return true if this Locale is equal to the specified object.
1882 1897 */
1883 1898 @Override
1884 1899 public boolean equals(Object obj) {
1885 1900 if (this == obj) // quick check
1886 1901 return true;
1887 1902 if (!(obj instanceof Locale))
1888 1903 return false;
1889 1904 BaseLocale otherBase = ((Locale)obj).baseLocale;
1890 1905 if (!baseLocale.equals(otherBase)) {
1891 1906 return false;
1892 1907 }
1893 1908 if (localeExtensions == null) {
1894 1909 return ((Locale)obj).localeExtensions == null;
1895 1910 }
1896 1911 return localeExtensions.equals(((Locale)obj).localeExtensions);
1897 1912 }
1898 1913
1899 1914 // ================= privates =====================================
1900 1915
1901 1916 private transient BaseLocale baseLocale;
1902 1917 private transient LocaleExtensions localeExtensions;
↓ open down ↓ |
47 lines elided |
↑ open up ↑ |
1903 1918
1904 1919 /**
1905 1920 * Calculated hashcode
1906 1921 */
1907 1922 private transient volatile int hashCodeValue = 0;
1908 1923
1909 1924 private volatile static Locale defaultLocale = initDefault();
1910 1925 private volatile static Locale defaultDisplayLocale = null;
1911 1926 private volatile static Locale defaultFormatLocale = null;
1912 1927
1928 + private transient volatile String languageTag;
1929 +
1913 1930 /**
1914 1931 * Return an array of the display names of the variant.
1915 1932 * @param bundle the ResourceBundle to use to get the display names
1916 1933 * @return an array of display names, possible of zero length.
1917 1934 */
1918 1935 private String[] getDisplayVariantArray(OpenListResourceBundle bundle, Locale inLocale) {
1919 1936 // Split the variant name into tokens separated by '_'.
1920 1937 StringTokenizer tokenizer = new StringTokenizer(baseLocale.getVariant(), "_");
1921 1938 String[] names = new String[tokenizer.countTokens()];
1922 1939
1923 1940 // For each variant token, lookup the display name. If
1924 1941 // not found, use the variant name itself.
1925 1942 for (int i=0; i<names.length; ++i) {
1926 1943 names[i] = getDisplayString(tokenizer.nextToken(),
1927 1944 inLocale, DISPLAY_VARIANT);
1928 1945 }
1929 1946
1930 1947 return names;
1931 1948 }
1932 1949
1933 1950 /**
1934 1951 * Format a list using given pattern strings.
1935 1952 * If either of the patterns is null, then a the list is
1936 1953 * formatted by concatenation with the delimiter ','.
1937 1954 * @param stringList the list of strings to be formatted.
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
1938 1955 * @param listPattern should create a MessageFormat taking 0-3 arguments
1939 1956 * and formatting them into a list.
1940 1957 * @param listCompositionPattern should take 2 arguments
1941 1958 * and is used by composeList.
1942 1959 * @return a string representing the list.
1943 1960 */
1944 1961 private static String formatList(String[] stringList, String listPattern, String listCompositionPattern) {
1945 1962 // If we have no list patterns, compose the list in a simple,
1946 1963 // non-localized way.
1947 1964 if (listPattern == null || listCompositionPattern == null) {
1948 - StringBuffer result = new StringBuffer();
1949 - for (int i=0; i<stringList.length; ++i) {
1950 - if (i>0) result.append(',');
1965 + StringBuilder result = new StringBuilder();
1966 + for (int i = 0; i < stringList.length; ++i) {
1967 + if (i > 0) {
1968 + result.append(',');
1969 + }
1951 1970 result.append(stringList[i]);
1952 1971 }
1953 1972 return result.toString();
1954 1973 }
1955 1974
1956 1975 // Compose the list down to three elements if necessary
1957 1976 if (stringList.length > 3) {
1958 1977 MessageFormat format = new MessageFormat(listCompositionPattern);
1959 1978 stringList = composeList(format, stringList);
1960 1979 }
1961 1980
1962 1981 // Rebuild the argument list with the list length as the first element
1963 1982 Object[] args = new Object[stringList.length + 1];
1964 1983 System.arraycopy(stringList, 0, args, 1, stringList.length);
1965 1984 args[0] = new Integer(stringList.length);
1966 1985
1967 1986 // Format it using the pattern in the resource
1968 1987 MessageFormat format = new MessageFormat(listPattern);
1969 1988 return format.format(args);
1970 1989 }
1971 1990
1972 1991 /**
1973 1992 * Given a list of strings, return a list shortened to three elements.
1974 1993 * Shorten it by applying the given format to the first two elements
1975 1994 * recursively.
1976 1995 * @param format a format which takes two arguments
1977 1996 * @param list a list of strings
1978 1997 * @return if the list is three elements or shorter, the same list;
1979 1998 * otherwise, a new list of three elements.
1980 1999 */
1981 2000 private static String[] composeList(MessageFormat format, String[] list) {
1982 2001 if (list.length <= 3) return list;
1983 2002
1984 2003 // Use the given format to compose the first two elements into one
1985 2004 String[] listItems = { list[0], list[1] };
1986 2005 String newItem = format.format(listItems);
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
1987 2006
1988 2007 // Form a new list one element shorter
1989 2008 String[] newList = new String[list.length-1];
1990 2009 System.arraycopy(list, 2, newList, 1, newList.length-1);
1991 2010 newList[0] = newItem;
1992 2011
1993 2012 // Recurse
1994 2013 return composeList(format, newList);
1995 2014 }
1996 2015
2016 + // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to
2017 + // avoid its class loading.
2018 + private static boolean isUnicodeExtensionKey(String s) {
2019 + // 2alphanum
2020 + return (s.length() == 2) && LocaleUtils.isAlphaNumericString(s);
2021 + }
2022 +
1997 2023 /**
1998 2024 * @serialField language String
1999 2025 * language subtag in lower case. (See <a href="java/util/Locale.html#getLanguage()">getLanguage()</a>)
2000 2026 * @serialField country String
2001 2027 * country subtag in upper case. (See <a href="java/util/Locale.html#getCountry()">getCountry()</a>)
2002 2028 * @serialField variant String
2003 2029 * variant subtags separated by LOWLINE characters. (See <a href="java/util/Locale.html#getVariant()">getVariant()</a>)
2004 2030 * @serialField hashcode int
2005 2031 * deprecated, for forward compatibility only
2006 2032 * @serialField script String
2007 2033 * script subtag in title case (See <a href="java/util/Locale.html#getScript()">getScript()</a>)
2008 2034 * @serialField extensions String
2009 2035 * canonical representation of extensions, that is,
2010 2036 * BCP47 extensions in alphabetical order followed by
2011 2037 * BCP47 private use subtags, all in lower case letters
2012 2038 * separated by HYPHEN-MINUS characters.
2013 2039 * (See <a href="java/util/Locale.html#getExtensionKeys()">getExtensionKeys()</a>,
2014 2040 * <a href="java/util/Locale.html#getExtension(char)">getExtension(char)</a>)
2015 2041 */
2016 2042 private static final ObjectStreamField[] serialPersistentFields = {
2017 2043 new ObjectStreamField("language", String.class),
2018 2044 new ObjectStreamField("country", String.class),
2019 2045 new ObjectStreamField("variant", String.class),
2020 2046 new ObjectStreamField("hashcode", int.class),
2021 2047 new ObjectStreamField("script", String.class),
2022 2048 new ObjectStreamField("extensions", String.class),
2023 2049 };
2024 2050
2025 2051 /**
2026 2052 * Serializes this <code>Locale</code> to the specified <code>ObjectOutputStream</code>.
2027 2053 * @param out the <code>ObjectOutputStream</code> to write
2028 2054 * @throws IOException
2029 2055 * @since 1.7
2030 2056 */
2031 2057 private void writeObject(ObjectOutputStream out) throws IOException {
2032 2058 ObjectOutputStream.PutField fields = out.putFields();
2033 2059 fields.put("language", baseLocale.getLanguage());
2034 2060 fields.put("script", baseLocale.getScript());
2035 2061 fields.put("country", baseLocale.getRegion());
2036 2062 fields.put("variant", baseLocale.getVariant());
2037 2063 fields.put("extensions", localeExtensions == null ? "" : localeExtensions.getID());
2038 2064 fields.put("hashcode", -1); // place holder just for backward support
2039 2065 out.writeFields();
2040 2066 }
2041 2067
2042 2068 /**
2043 2069 * Deserializes this <code>Locale</code>.
2044 2070 * @param in the <code>ObjectInputStream</code> to read
2045 2071 * @throws IOException
2046 2072 * @throws ClassNotFoundException
2047 2073 * @throws IllformdLocaleException
2048 2074 * @since 1.7
2049 2075 */
2050 2076 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
2051 2077 ObjectInputStream.GetField fields = in.readFields();
2052 2078 String language = (String)fields.get("language", "");
2053 2079 String script = (String)fields.get("script", "");
2054 2080 String country = (String)fields.get("country", "");
2055 2081 String variant = (String)fields.get("variant", "");
2056 2082 String extStr = (String)fields.get("extensions", "");
2057 2083 baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);
2058 2084 if (extStr.length() > 0) {
2059 2085 try {
2060 2086 InternalLocaleBuilder bldr = new InternalLocaleBuilder();
2061 2087 bldr.setExtensions(extStr);
2062 2088 localeExtensions = bldr.getLocaleExtensions();
2063 2089 } catch (LocaleSyntaxException e) {
2064 2090 throw new IllformedLocaleException(e.getMessage());
2065 2091 }
2066 2092 } else {
2067 2093 localeExtensions = null;
2068 2094 }
2069 2095 }
2070 2096
2071 2097 /**
2072 2098 * Returns a cached <code>Locale</code> instance equivalent to
2073 2099 * the deserialized <code>Locale</code>. When serialized
2074 2100 * language, country and variant fields read from the object data stream
2075 2101 * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions
2076 2102 * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>
2077 2103 * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script
2078 2104 * type is "thai"). See <a href="Locale.html#special_cases_constructor"/>Special Cases</a>
2079 2105 * for more information.
2080 2106 *
2081 2107 * @return an instance of <code>Locale</code> equivalent to
2082 2108 * the deserialized <code>Locale</code>.
2083 2109 * @throws java.io.ObjectStreamException
2084 2110 */
2085 2111 private Object readResolve() throws java.io.ObjectStreamException {
2086 2112 return getInstance(baseLocale.getLanguage(), baseLocale.getScript(),
2087 2113 baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions);
2088 2114 }
2089 2115
2090 2116 private static volatile String[] isoLanguages = null;
2091 2117
2092 2118 private static volatile String[] isoCountries = null;
2093 2119
2094 2120 private static String convertOldISOCodes(String language) {
2095 2121 // we accept both the old and the new ISO codes for the languages whose ISO
2096 2122 // codes have changed, but we always store the OLD code, for backward compatibility
2097 2123 language = LocaleUtils.toLowerString(language).intern();
2098 2124 if (language == "he") {
2099 2125 return "iw";
2100 2126 } else if (language == "yi") {
2101 2127 return "ji";
2102 2128 } else if (language == "id") {
2103 2129 return "in";
2104 2130 } else {
2105 2131 return language;
2106 2132 }
2107 2133 }
2108 2134
2109 2135 private static LocaleExtensions getCompatibilityExtensions(String language,
2110 2136 String script,
2111 2137 String country,
2112 2138 String variant) {
2113 2139 LocaleExtensions extensions = null;
2114 2140 // Special cases for backward compatibility support
2115 2141 if (LocaleUtils.caseIgnoreMatch(language, "ja")
2116 2142 && script.length() == 0
2117 2143 && LocaleUtils.caseIgnoreMatch(country, "jp")
2118 2144 && "JP".equals(variant)) {
2119 2145 // ja_JP_JP -> u-ca-japanese (calendar = japanese)
2120 2146 extensions = LocaleExtensions.CALENDAR_JAPANESE;
2121 2147 } else if (LocaleUtils.caseIgnoreMatch(language, "th")
2122 2148 && script.length() == 0
2123 2149 && LocaleUtils.caseIgnoreMatch(country, "th")
2124 2150 && "TH".equals(variant)) {
2125 2151 // th_TH_TH -> u-nu-thai (numbersystem = thai)
2126 2152 extensions = LocaleExtensions.NUMBER_THAI;
2127 2153 }
2128 2154 return extensions;
↓ open down ↓ |
122 lines elided |
↑ open up ↑ |
2129 2155 }
2130 2156
2131 2157 /**
2132 2158 * Obtains a localized locale names from a LocaleNameProvider
2133 2159 * implementation.
2134 2160 */
2135 2161 private static class LocaleNameGetter
2136 2162 implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, String> {
2137 2163 private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();
2138 2164
2165 + @Override
2139 2166 public String getObject(LocaleNameProvider localeNameProvider,
2140 2167 Locale locale,
2141 2168 String key,
2142 2169 Object... params) {
2143 2170 assert params.length == 2;
2144 2171 int type = (Integer)params[0];
2145 2172 String code = (String)params[1];
2146 2173
2147 2174 switch(type) {
2148 2175 case DISPLAY_LANGUAGE:
2149 2176 return localeNameProvider.getDisplayLanguage(code, locale);
2150 2177 case DISPLAY_COUNTRY:
2151 2178 return localeNameProvider.getDisplayCountry(code, locale);
2152 2179 case DISPLAY_VARIANT:
2153 2180 return localeNameProvider.getDisplayVariant(code, locale);
2154 2181 case DISPLAY_SCRIPT:
2155 2182 return localeNameProvider.getDisplayScript(code, locale);
2156 2183 default:
2157 2184 assert false; // shouldn't happen
2158 2185 }
2159 2186
2160 2187 return null;
2161 2188 }
2162 2189 }
2163 2190
2164 2191 /**
2165 2192 * Enum for locale categories. These locale categories are used to get/set
2166 2193 * the default locale for the specific functionality represented by the
2167 2194 * category.
2168 2195 *
2169 2196 * @see #getDefault(Locale.Category)
2170 2197 * @see #setDefault(Locale.Category, Locale)
2171 2198 * @since 1.7
2172 2199 */
2173 2200 public enum Category {
2174 2201
2175 2202 /**
2176 2203 * Category used to represent the default locale for
2177 2204 * displaying user interfaces.
2178 2205 */
2179 2206 DISPLAY("user.language.display",
2180 2207 "user.script.display",
2181 2208 "user.country.display",
2182 2209 "user.variant.display"),
2183 2210
2184 2211 /**
2185 2212 * Category used to represent the default locale for
2186 2213 * formatting dates, numbers, and/or currencies.
2187 2214 */
2188 2215 FORMAT("user.language.format",
2189 2216 "user.script.format",
2190 2217 "user.country.format",
2191 2218 "user.variant.format");
2192 2219
2193 2220 Category(String languageKey, String scriptKey, String countryKey, String variantKey) {
2194 2221 this.languageKey = languageKey;
2195 2222 this.scriptKey = scriptKey;
2196 2223 this.countryKey = countryKey;
2197 2224 this.variantKey = variantKey;
2198 2225 }
2199 2226
2200 2227 final String languageKey;
2201 2228 final String scriptKey;
2202 2229 final String countryKey;
2203 2230 final String variantKey;
2204 2231 }
2205 2232
2206 2233 /**
2207 2234 * <code>Builder</code> is used to build instances of <code>Locale</code>
2208 2235 * from values configured by the setters. Unlike the <code>Locale</code>
2209 2236 * constructors, the <code>Builder</code> checks if a value configured by a
2210 2237 * setter satisfies the syntax requirements defined by the <code>Locale</code>
2211 2238 * class. A <code>Locale</code> object created by a <code>Builder</code> is
2212 2239 * well-formed and can be transformed to a well-formed IETF BCP 47 language tag
2213 2240 * without losing information.
2214 2241 *
2215 2242 * <p><b>Note:</b> The <code>Locale</code> class does not provide any
2216 2243 * syntactic restrictions on variant, while BCP 47 requires each variant
2217 2244 * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3
2218 2245 * alphanumerics. The method <code>setVariant</code> throws
2219 2246 * <code>IllformedLocaleException</code> for a variant that does not satisfy
2220 2247 * this restriction. If it is necessary to support such a variant, use a
2221 2248 * Locale constructor. However, keep in mind that a <code>Locale</code>
2222 2249 * object created this way might lose the variant information when
2223 2250 * transformed to a BCP 47 language tag.
2224 2251 *
2225 2252 * <p>The following example shows how to create a <code>Locale</code> object
2226 2253 * with the <code>Builder</code>.
2227 2254 * <blockquote>
2228 2255 * <pre>
2229 2256 * Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
2230 2257 * </pre>
2231 2258 * </blockquote>
2232 2259 *
2233 2260 * <p>Builders can be reused; <code>clear()</code> resets all
2234 2261 * fields to their default values.
2235 2262 *
2236 2263 * @see Locale#forLanguageTag
2237 2264 * @since 1.7
2238 2265 */
2239 2266 public static final class Builder {
2240 2267 private final InternalLocaleBuilder localeBuilder;
2241 2268
2242 2269 /**
2243 2270 * Constructs an empty Builder. The default value of all
2244 2271 * fields, extensions, and private use information is the
2245 2272 * empty string.
2246 2273 */
2247 2274 public Builder() {
2248 2275 localeBuilder = new InternalLocaleBuilder();
2249 2276 }
2250 2277
2251 2278 /**
2252 2279 * Resets the <code>Builder</code> to match the provided
2253 2280 * <code>locale</code>. Existing state is discarded.
2254 2281 *
2255 2282 * <p>All fields of the locale must be well-formed, see {@link Locale}.
2256 2283 *
2257 2284 * <p>Locales with any ill-formed fields cause
2258 2285 * <code>IllformedLocaleException</code> to be thrown, except for the
2259 2286 * following three cases which are accepted for compatibility
2260 2287 * reasons:<ul>
2261 2288 * <li>Locale("ja", "JP", "JP") is treated as "ja-JP-u-ca-japanese"
2262 2289 * <li>Locale("th", "TH", "TH") is treated as "th-TH-u-nu-thai"
2263 2290 * <li>Locale("no", "NO", "NY") is treated as "nn-NO"</ul>
2264 2291 *
2265 2292 * @param locale the locale
2266 2293 * @return This builder.
2267 2294 * @throws IllformedLocaleException if <code>locale</code> has
2268 2295 * any ill-formed fields.
2269 2296 * @throws NullPointerException if <code>locale</code> is null.
2270 2297 */
2271 2298 public Builder setLocale(Locale locale) {
2272 2299 try {
2273 2300 localeBuilder.setLocale(locale.baseLocale, locale.localeExtensions);
2274 2301 } catch (LocaleSyntaxException e) {
2275 2302 throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
2276 2303 }
2277 2304 return this;
2278 2305 }
2279 2306
2280 2307 /**
2281 2308 * Resets the Builder to match the provided IETF BCP 47
2282 2309 * language tag. Discards the existing state. Null and the
2283 2310 * empty string cause the builder to be reset, like {@link
2284 2311 * #clear}. Grandfathered tags (see {@link
2285 2312 * Locale#forLanguageTag}) are converted to their canonical
2286 2313 * form before being processed. Otherwise, the language tag
2287 2314 * must be well-formed (see {@link Locale}) or an exception is
2288 2315 * thrown (unlike <code>Locale.forLanguageTag</code>, which
2289 2316 * just discards ill-formed and following portions of the
2290 2317 * tag).
2291 2318 *
2292 2319 * @param languageTag the language tag
2293 2320 * @return This builder.
2294 2321 * @throws IllformedLocaleException if <code>languageTag</code> is ill-formed
2295 2322 * @see Locale#forLanguageTag(String)
2296 2323 */
2297 2324 public Builder setLanguageTag(String languageTag) {
2298 2325 ParseStatus sts = new ParseStatus();
2299 2326 LanguageTag tag = LanguageTag.parse(languageTag, sts);
2300 2327 if (sts.isError()) {
2301 2328 throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex());
2302 2329 }
2303 2330 localeBuilder.setLanguageTag(tag);
2304 2331 return this;
2305 2332 }
2306 2333
2307 2334 /**
2308 2335 * Sets the language. If <code>language</code> is the empty string or
2309 2336 * null, the language in this <code>Builder</code> is removed. Otherwise,
2310 2337 * the language must be <a href="./Locale.html#def_language">well-formed</a>
2311 2338 * or an exception is thrown.
2312 2339 *
2313 2340 * <p>The typical language value is a two or three-letter language
2314 2341 * code as defined in ISO639.
2315 2342 *
2316 2343 * @param language the language
2317 2344 * @return This builder.
2318 2345 * @throws IllformedLocaleException if <code>language</code> is ill-formed
2319 2346 */
2320 2347 public Builder setLanguage(String language) {
2321 2348 try {
2322 2349 localeBuilder.setLanguage(language);
2323 2350 } catch (LocaleSyntaxException e) {
2324 2351 throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
2325 2352 }
2326 2353 return this;
2327 2354 }
2328 2355
2329 2356 /**
2330 2357 * Sets the script. If <code>script</code> is null or the empty string,
2331 2358 * the script in this <code>Builder</code> is removed.
2332 2359 * Otherwise, the script must be <a href="./Locale.html#def_script">well-formed</a> or an
2333 2360 * exception is thrown.
2334 2361 *
2335 2362 * <p>The typical script value is a four-letter script code as defined by ISO 15924.
2336 2363 *
2337 2364 * @param script the script
2338 2365 * @return This builder.
2339 2366 * @throws IllformedLocaleException if <code>script</code> is ill-formed
2340 2367 */
2341 2368 public Builder setScript(String script) {
2342 2369 try {
2343 2370 localeBuilder.setScript(script);
2344 2371 } catch (LocaleSyntaxException e) {
2345 2372 throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
2346 2373 }
2347 2374 return this;
2348 2375 }
2349 2376
2350 2377 /**
2351 2378 * Sets the region. If region is null or the empty string, the region
2352 2379 * in this <code>Builder</code> is removed. Otherwise,
2353 2380 * the region must be <a href="./Locale.html#def_region">well-formed</a> or an
2354 2381 * exception is thrown.
2355 2382 *
2356 2383 * <p>The typical region value is a two-letter ISO 3166 code or a
2357 2384 * three-digit UN M.49 area code.
2358 2385 *
2359 2386 * <p>The country value in the <code>Locale</code> created by the
2360 2387 * <code>Builder</code> is always normalized to upper case.
2361 2388 *
2362 2389 * @param region the region
2363 2390 * @return This builder.
2364 2391 * @throws IllformedLocaleException if <code>region</code> is ill-formed
2365 2392 */
2366 2393 public Builder setRegion(String region) {
2367 2394 try {
2368 2395 localeBuilder.setRegion(region);
2369 2396 } catch (LocaleSyntaxException e) {
2370 2397 throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
2371 2398 }
2372 2399 return this;
2373 2400 }
2374 2401
2375 2402 /**
2376 2403 * Sets the variant. If variant is null or the empty string, the
2377 2404 * variant in this <code>Builder</code> is removed. Otherwise, it
2378 2405 * must consist of one or more <a href="./Locale.html#def_variant">well-formed</a>
2379 2406 * subtags, or an exception is thrown.
2380 2407 *
2381 2408 * <p><b>Note:</b> This method checks if <code>variant</code>
2382 2409 * satisfies the IETF BCP 47 variant subtag's syntax requirements,
2383 2410 * and normalizes the value to lowercase letters. However,
2384 2411 * the <code>Locale</code> class does not impose any syntactic
2385 2412 * restriction on variant, and the variant value in
2386 2413 * <code>Locale</code> is case sensitive. To set such a variant,
2387 2414 * use a Locale constructor.
2388 2415 *
2389 2416 * @param variant the variant
2390 2417 * @return This builder.
2391 2418 * @throws IllformedLocaleException if <code>variant</code> is ill-formed
2392 2419 */
2393 2420 public Builder setVariant(String variant) {
2394 2421 try {
2395 2422 localeBuilder.setVariant(variant);
2396 2423 } catch (LocaleSyntaxException e) {
2397 2424 throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
2398 2425 }
2399 2426 return this;
2400 2427 }
2401 2428
2402 2429 /**
2403 2430 * Sets the extension for the given key. If the value is null or the
2404 2431 * empty string, the extension is removed. Otherwise, the extension
2405 2432 * must be <a href="./Locale.html#def_extensions">well-formed</a> or an exception
2406 2433 * is thrown.
2407 2434 *
2408 2435 * <p><b>Note:</b> The key {@link Locale#UNICODE_LOCALE_EXTENSION
2409 2436 * UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension.
2410 2437 * Setting a value for this key replaces any existing Unicode locale key/type
2411 2438 * pairs with those defined in the extension.
2412 2439 *
2413 2440 * <p><b>Note:</b> The key {@link Locale#PRIVATE_USE_EXTENSION
2414 2441 * PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be
2415 2442 * well-formed, the value for this key needs only to have subtags of one to
2416 2443 * eight alphanumeric characters, not two to eight as in the general case.
2417 2444 *
2418 2445 * @param key the extension key
2419 2446 * @param value the extension value
2420 2447 * @return This builder.
2421 2448 * @throws IllformedLocaleException if <code>key</code> is illegal
2422 2449 * or <code>value</code> is ill-formed
2423 2450 * @see #setUnicodeLocaleKeyword(String, String)
2424 2451 */
2425 2452 public Builder setExtension(char key, String value) {
2426 2453 try {
2427 2454 localeBuilder.setExtension(key, value);
2428 2455 } catch (LocaleSyntaxException e) {
2429 2456 throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
2430 2457 }
2431 2458 return this;
2432 2459 }
2433 2460
2434 2461 /**
2435 2462 * Sets the Unicode locale keyword type for the given key. If the type
2436 2463 * is null, the Unicode keyword is removed. Otherwise, the key must be
2437 2464 * non-null and both key and type must be <a
2438 2465 * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
2439 2466 * is thrown.
2440 2467 *
2441 2468 * <p>Keys and types are converted to lower case.
2442 2469 *
2443 2470 * <p><b>Note</b>:Setting the 'u' extension via {@link #setExtension}
2444 2471 * replaces all Unicode locale keywords with those defined in the
2445 2472 * extension.
2446 2473 *
2447 2474 * @param key the Unicode locale key
2448 2475 * @param type the Unicode locale type
2449 2476 * @return This builder.
2450 2477 * @throws IllformedLocaleException if <code>key</code> or <code>type</code>
2451 2478 * is ill-formed
2452 2479 * @throws NullPointerException if <code>key</code> is null
2453 2480 * @see #setExtension(char, String)
2454 2481 */
2455 2482 public Builder setUnicodeLocaleKeyword(String key, String type) {
2456 2483 try {
2457 2484 localeBuilder.setUnicodeLocaleKeyword(key, type);
2458 2485 } catch (LocaleSyntaxException e) {
2459 2486 throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
2460 2487 }
2461 2488 return this;
2462 2489 }
2463 2490
2464 2491 /**
2465 2492 * Adds a unicode locale attribute, if not already present, otherwise
2466 2493 * has no effect. The attribute must not be null and must be <a
2467 2494 * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
2468 2495 * is thrown.
2469 2496 *
2470 2497 * @param attribute the attribute
2471 2498 * @return This builder.
2472 2499 * @throws NullPointerException if <code>attribute</code> is null
2473 2500 * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
2474 2501 * @see #setExtension(char, String)
2475 2502 */
2476 2503 public Builder addUnicodeLocaleAttribute(String attribute) {
2477 2504 try {
2478 2505 localeBuilder.addUnicodeLocaleAttribute(attribute);
2479 2506 } catch (LocaleSyntaxException e) {
2480 2507 throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
2481 2508 }
2482 2509 return this;
2483 2510 }
2484 2511
2485 2512 /**
2486 2513 * Removes a unicode locale attribute, if present, otherwise has no
2487 2514 * effect. The attribute must not be null and must be <a
2488 2515 * href="./Locale.html#def_locale_extension">well-formed</a> or an exception
2489 2516 * is thrown.
2490 2517 *
2491 2518 * <p>Attribute comparision for removal is case-insensitive.
2492 2519 *
2493 2520 * @param attribute the attribute
2494 2521 * @return This builder.
2495 2522 * @throws NullPointerException if <code>attribute</code> is null
2496 2523 * @throws IllformedLocaleException if <code>attribute</code> is ill-formed
2497 2524 * @see #setExtension(char, String)
2498 2525 */
2499 2526 public Builder removeUnicodeLocaleAttribute(String attribute) {
2500 2527 try {
2501 2528 localeBuilder.removeUnicodeLocaleAttribute(attribute);
2502 2529 } catch (LocaleSyntaxException e) {
2503 2530 throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
2504 2531 }
2505 2532 return this;
2506 2533 }
2507 2534
2508 2535 /**
2509 2536 * Resets the builder to its initial, empty state.
2510 2537 *
2511 2538 * @return This builder.
2512 2539 */
2513 2540 public Builder clear() {
2514 2541 localeBuilder.clear();
2515 2542 return this;
2516 2543 }
2517 2544
2518 2545 /**
2519 2546 * Resets the extensions to their initial, empty state.
2520 2547 * Language, script, region and variant are unchanged.
2521 2548 *
2522 2549 * @return This builder.
2523 2550 * @see #setExtension(char, String)
2524 2551 */
2525 2552 public Builder clearExtensions() {
2526 2553 localeBuilder.clearExtensions();
2527 2554 return this;
2528 2555 }
2529 2556
2530 2557 /**
2531 2558 * Returns an instance of <code>Locale</code> created from the fields set
2532 2559 * on this builder.
2533 2560 *
2534 2561 * <p>This applies the conversions listed in {@link Locale#forLanguageTag}
2535 2562 * when constructing a Locale. (Grandfathered tags are handled in
2536 2563 * {@link #setLanguageTag}.)
2537 2564 *
2538 2565 * @return A Locale.
2539 2566 */
2540 2567 public Locale build() {
2541 2568 BaseLocale baseloc = localeBuilder.getBaseLocale();
2542 2569 LocaleExtensions extensions = localeBuilder.getLocaleExtensions();
2543 2570 if (extensions == null && baseloc.getVariant().length() > 0) {
2544 2571 extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),
2545 2572 baseloc.getRegion(), baseloc.getVariant());
2546 2573 }
2547 2574 return Locale.getInstance(baseloc, extensions);
2548 2575 }
2549 2576 }
2550 2577 }
↓ open down ↓ |
402 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX