1 /*
2 * Hunt - A refined core library for D programming language.
3 *
4 * Copyright (C) 2018-2019 HuntLabs
5 *
6 * Website: https://www.huntlabs.net/
7 *
8 * Licensed under the Apache-2.0 License.
9 *
10 */11 12 modulehunt.util.Locale;
13 14 importhunt.Exceptions;
15 importhunt.Functions;
16 importhunt.stream.Common;
17 importhunt.logging;
18 importhunt.collection;
19 importhunt.system.Environment;
20 importhunt.util.StringBuilder;
21 importhunt.util.Common;
22 importhunt.util.Configuration;
23 24 importstd.array;
25 importstd.concurrency : initOnce;
26 importstd.string;
27 28 /**
29 * A <code>Locale</code> object represents a specific geographical, political,
30 * or cultural region. An operation that requires a <code>Locale</code> to perform
31 * its task is called <em>locale-sensitive</em> and uses the <code>Locale</code>
32 * to tailor information for the user. For example, displaying a number
33 * is a locale-sensitive operation— the number should be formatted
34 * according to the customs and conventions of the user's native country,
35 * region, or culture.
36 *
37 * <p> The {@code Locale} class implements IETF BCP 47 which is composed of
38 * <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 "Matching of Language
39 * Tags"</a> and <a href="http://tools.ietf.org/html/rfc5646">RFC 5646 "Tags
40 * for Identifying Languages"</a> with support for the LDML (UTS#35, "Unicode
41 * Locale Data Markup Language") BCP 47-compatible extensions for locale data
42 * exchange.
43 *
44 * <p> A <code>Locale</code> object logically consists of the fields
45 * described below.
46 *
47 * <dl>
48 * <dt><a id="def_language"><b>language</b></a></dt>
49 *
50 * <dd>ISO 639 alpha-2 or alpha-3 language code, or registered
51 * language subtags up to 8 alpha letters (for future enhancements).
52 * When a language has both an alpha-2 code and an alpha-3 code, the
53 * alpha-2 code must be used. You can find a full list of valid
54 * language codes in the IANA Language Subtag Registry (search for
55 * "Type: language"). The language field is case insensitive, but
56 * <code>Locale</code> always canonicalizes to lower case.</dd>
57 *
58 * <dd>Well-formed language values have the form
59 * <code>[a-zA-Z]{2,8}</code>. Note that this is not the full
60 * BCP47 language production, since it excludes extlang. They are
61 * not needed since modern three-letter language codes replace
62 * them.</dd>
63 *
64 * <dd>Example: "en" (English), "ja" (Japanese), "kok" (Konkani)</dd>
65 *
66 * <dt><a id="def_script"><b>script</b></a></dt>
67 *
68 * <dd>ISO 15924 alpha-4 script code. You can find a full list of
69 * valid script codes in the IANA Language Subtag Registry (search
70 * for "Type: script"). The script field is case insensitive, but
71 * <code>Locale</code> always canonicalizes to title case (the first
72 * letter is upper case and the rest of the letters are lower
73 * case).</dd>
74 *
75 * <dd>Well-formed script values have the form
76 * <code>[a-zA-Z]{4}</code></dd>
77 *
78 * <dd>Example: "Latn" (Latin), "Cyrl" (Cyrillic)</dd>
79 *
80 * <dt><a id="def_region"><b>country (region)</b></a></dt>
81 *
82 * <dd>ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.
83 * You can find a full list of valid country and region codes in the
84 * IANA Language Subtag Registry (search for "Type: region"). The
85 * country (region) field is case insensitive, but
86 * <code>Locale</code> always canonicalizes to upper case.</dd>
87 *
88 * <dd>Well-formed country/region values have
89 * the form <code>[a-zA-Z]{2} | [0-9]{3}</code></dd>
90 *
91 * <dd>Example: "US" (United States), "FR" (France), "029"
92 * (Caribbean)</dd>
93 *
94 * <dt><a id="def_variant"><b>variant</b></a></dt>
95 *
96 * <dd>Any arbitrary value used to indicate a variation of a
97 * <code>Locale</code>. Where there are two or more variant values
98 * each indicating its own semantics, these values should be ordered
99 * by importance, with most important first, separated by
100 * underscore('_'). The variant field is case sensitive.</dd>
101 *
102 * <dd>Note: IETF BCP 47 places syntactic restrictions on variant
103 * subtags. Also BCP 47 subtags are strictly used to indicate
104 * additional variations that define a language or its dialects that
105 * are not covered by any combinations of language, script and
106 * region subtags. You can find a full list of valid variant codes
107 * in the IANA Language Subtag Registry (search for "Type: variant").
108 *
109 * <p>However, the variant field in <code>Locale</code> has
110 * historically been used for any kind of variation, not just
111 * language variations. For example, some supported variants
112 * available in Java SE Runtime Environments indicate alternative
113 * cultural behaviors such as calendar type or number script. In
114 * BCP 47 this kind of information, which does not identify the
115 * language, is supported by extension subtags or private use
116 * subtags.</dd>
117 *
118 * <dd>Well-formed variant values have the form <code>SUBTAG
119 * (('_'|'-') SUBTAG)*</code> where <code>SUBTAG =
120 * [0-9][0-9a-zA-Z]{3} | [0-9a-zA-Z]{5,8}</code>. (Note: BCP 47 only
121 * uses hyphen ('-') as a delimiter, this is more lenient).</dd>
122 *
123 * <dd>Example: "polyton" (Polytonic Greek), "POSIX"</dd>
124 *
125 * <dt><a id="def_extensions"><b>extensions</b></a></dt>
126 *
127 * <dd>A map from single character keys to string values, indicating
128 * extensions apart from language identification. The extensions in
129 * <code>Locale</code> implement the semantics and syntax of BCP 47
130 * extension subtags and private use subtags. The extensions are
131 * case insensitive, but <code>Locale</code> canonicalizes all
132 * extension keys and values to lower case. Note that extensions
133 * cannot have empty values.</dd>
134 *
135 * <dd>Well-formed keys are single characters from the set
136 * <code>[0-9a-zA-Z]</code>. Well-formed values have the form
137 * <code>SUBTAG ('-' SUBTAG)*</code> where for the key 'x'
138 * <code>SUBTAG = [0-9a-zA-Z]{1,8}</code> and for other keys
139 * <code>SUBTAG = [0-9a-zA-Z]{2,8}</code> (that is, 'x' allows
140 * single-character subtags).</dd>
141 *
142 * <dd>Example: key="u"/value="ca-japanese" (Japanese Calendar),
143 * key="x"/value="java-1-7"</dd>
144 * </dl>
145 *
146 * <b>Note:</b> Although BCP 47 requires field values to be registered
147 * in the IANA Language Subtag Registry, the <code>Locale</code> class
148 * does not provide any validation features. The <code>Builder</code>
149 * only checks if an individual field satisfies the syntactic
150 * requirement (is well-formed), but does not validate the value
151 * itself. See {@link Builder} for details.
152 *
153 * <h3><a id="def_locale_extension">Unicode locale/language extension</a></h3>
154 *
155 * <p>UTS#35, "Unicode Locale Data Markup Language" defines optional
156 * attributes and keywords to override or refine the default behavior
157 * associated with a locale. A keyword is represented by a pair of
158 * key and type. For example, "nu-thai" indicates that Thai local
159 * digits (value:"thai") should be used for formatting numbers
160 * (key:"nu").
161 *
162 * <p>The keywords are mapped to a BCP 47 extension value using the
163 * extension key 'u' ({@link #UNICODE_LOCALE_EXTENSION}). The above
164 * example, "nu-thai", becomes the extension "u-nu-thai".
165 *
166 * <p>Thus, when a <code>Locale</code> object contains Unicode locale
167 * attributes and keywords,
168 * <code>getExtension(UNICODE_LOCALE_EXTENSION)</code> will return a
169 * string representing this information, for example, "nu-thai". The
170 * <code>Locale</code> class also provides {@link
171 * #getUnicodeLocaleAttributes}, {@link #getUnicodeLocaleKeys}, and
172 * {@link #getUnicodeLocaleType} which allow you to access Unicode
173 * locale attributes and key/type pairs directly. When represented as
174 * a string, the Unicode Locale Extension lists attributes
175 * alphabetically, followed by key/type sequences with keys listed
176 * alphabetically (the order of subtags comprising a key's type is
177 * fixed when the type is defined)
178 *
179 * <p>A well-formed locale key has the form
180 * <code>[0-9a-zA-Z]{2}</code>. A well-formed locale type has the
181 * form <code>"" | [0-9a-zA-Z]{3,8} ('-' [0-9a-zA-Z]{3,8})*</code> (it
182 * can be empty, or a series of subtags 3-8 alphanums in length). A
183 * well-formed locale attribute has the form
184 * <code>[0-9a-zA-Z]{3,8}</code> (it is a single subtag with the same
185 * form as a locale type subtag).
186 *
187 * <p>The Unicode locale extension specifies optional behavior in
188 * locale-sensitive services. Although the LDML specification defines
189 * various keys and values, actual locale-sensitive service
190 * implementations in a Java Runtime Environment might not support any
191 * particular Unicode locale attributes or key/type pairs.
192 *
193 * <h4>Creating a Locale</h4>
194 *
195 * <p>There are several different ways to create a <code>Locale</code>
196 * object.
197 *
198 * <h5>Builder</h5>
199 *
200 * <p>Using {@link Builder} you can construct a <code>Locale</code> object
201 * that conforms to BCP 47 syntax.
202 *
203 * <h5>Constructors</h5>
204 *
205 * <p>The <code>Locale</code> class provides three constructors:
206 * <blockquote>
207 * <pre>
208 * {@link #Locale(string language)}
209 * {@link #Locale(string language, string country)}
210 * {@link #Locale(string language, string country, string variant)}
211 * </pre>
212 * </blockquote>
213 * These constructors allow you to create a <code>Locale</code> object
214 * with language, country and variant, but you cannot specify
215 * script or extensions.
216 *
217 * <h5>Factory Methods</h5>
218 *
219 * <p>The method {@link #forLanguageTag} creates a <code>Locale</code>
220 * object for a well-formed BCP 47 language tag.
221 *
222 * <h5>Locale Constants</h5>
223 *
224 * <p>The <code>Locale</code> class provides a number of convenient constants
225 * that you can use to create <code>Locale</code> objects for commonly used
226 * locales. For example, the following creates a <code>Locale</code> object
227 * for the United States:
228 * <blockquote>
229 * <pre>
230 * Locale.US
231 * </pre>
232 * </blockquote>
233 *
234 * <h4><a id="LocaleMatching">Locale Matching</a></h4>
235 *
236 * <p>If an application or a system is internationalized and provides localized
237 * resources for multiple locales, it sometimes needs to find one or more
238 * locales (or language tags) which meet each user's specific preferences. Note
239 * that a term "language tag" is used interchangeably with "locale" in this
240 * locale matching documentation.
241 *
242 * <p>In order to do matching a user's preferred locales to a set of language
243 * tags, <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 Matching of
244 * Language Tags</a> defines two mechanisms: filtering and lookup.
245 * <em>Filtering</em> is used to get all matching locales, whereas
246 * <em>lookup</em> is to choose the best matching locale.
247 * Matching is done case-insensitively. These matching mechanisms are described
248 * in the following sections.
249 *
250 * <p>A user's preference is called a <em>Language Priority List</em> and is
251 * expressed as a list of language ranges. There are syntactically two types of
252 * language ranges: basic and extended. See
253 * {@link Locale.LanguageRange Locale.LanguageRange} for details.
254 *
255 * <h5>Filtering</h5>
256 *
257 * <p>The filtering operation returns all matching language tags. It is defined
258 * in RFC 4647 as follows:
259 * "In filtering, each language range represents the least specific language
260 * tag (that is, the language tag with fewest number of subtags) that is an
261 * acceptable match. All of the language tags in the matching set of tags will
262 * have an equal or greater number of subtags than the language range. Every
263 * non-wildcard subtag in the language range will appear in every one of the
264 * matching language tags."
265 *
266 * <p>There are two types of filtering: filtering for basic language ranges
267 * (called "basic filtering") and filtering for extended language ranges
268 * (called "extended filtering"). They may return different results by what
269 * kind of language ranges are included in the given Language Priority List.
270 * {@link Locale.FilteringMode} is a parameter to specify how filtering should
271 * be done.
272 *
273 * <h5>Lookup</h5>
274 *
275 * <p>The lookup operation returns the best matching language tags. It is
276 * defined in RFC 4647 as follows:
277 * "By contrast with filtering, each language range represents the most
278 * specific tag that is an acceptable match. The first matching tag found,
279 * according to the user's priority, is considered the closest match and is the
280 * item returned."
281 *
282 * <p>For example, if a Language Priority List consists of two language ranges,
283 * {@code "zh-Hant-TW"} and {@code "en-US"}, in prioritized order, lookup
284 * method progressively searches the language tags below in order to find the
285 * best matching language tag.
286 * <blockquote>
287 * <pre>
288 * 1. zh-Hant-TW
289 * 2. zh-Hant
290 * 3. zh
291 * 4. en-US
292 * 5. en
293 * </pre>
294 * </blockquote>
295 * If there is a language tag which matches completely to a language range
296 * above, the language tag is returned.
297 *
298 * <p>{@code "*"} is the special language range, and it is ignored in lookup.
299 *
300 * <p>If multiple language tags match as a result of the subtag {@code '*'}
301 * included in a language range, the first matching language tag returned by
302 * an {@link Iterator} over a {@link Collection} of language tags is treated as
303 * the best matching one.
304 *
305 * <h4>Use of Locale</h4>
306 *
307 * <p>Once you've created a <code>Locale</code> you can query it for information
308 * about itself. Use <code>getCountry</code> to get the country (or region)
309 * code and <code>getLanguage</code> to get the language code.
310 * You can use <code>getDisplayCountry</code> to get the
311 * name of the country suitable for displaying to the user. Similarly,
312 * you can use <code>getDisplayLanguage</code> to get the name of
313 * the language suitable for displaying to the user. Interestingly,
314 * the <code>getDisplayXXX</code> methods are themselves locale-sensitive
315 * and have two versions: one that uses the default
316 * {@link LocaleCategory#DISPLAY DISPLAY} locale and one
317 * that uses the locale specified as an argument.
318 *
319 * <p>The Java Platform provides a number of classes that perform locale-sensitive
320 * operations. For example, the <code>NumberFormat</code> class formats
321 * numbers, currency, and percentages in a locale-sensitive manner. Classes
322 * such as <code>NumberFormat</code> have several convenience methods
323 * for creating a default object of that type. For example, the
324 * <code>NumberFormat</code> class provides these three convenience methods
325 * for creating a default <code>NumberFormat</code> object:
326 * <blockquote>
327 * <pre>
328 * NumberFormat.getInstance()
329 * NumberFormat.getCurrencyInstance()
330 * NumberFormat.getPercentInstance()
331 * </pre>
332 * </blockquote>
333 * Each of these methods has two variants; one with an explicit locale
334 * and one without; the latter uses the default
335 * {@link LocaleCategory#FORMAT FORMAT} locale:
336 * <blockquote>
337 * <pre>
338 * NumberFormat.getInstance(myLocale)
339 * NumberFormat.getCurrencyInstance(myLocale)
340 * NumberFormat.getPercentInstance(myLocale)
341 * </pre>
342 * </blockquote>
343 * A <code>Locale</code> is the mechanism for identifying the kind of object
344 * (<code>NumberFormat</code>) that you would like to get. The locale is
345 * <STRONG>just</STRONG> a mechanism for identifying objects,
346 * <STRONG>not</STRONG> a container for the objects themselves.
347 *
348 * <h4>Compatibility</h4>
349 *
350 * <p>In order to maintain compatibility with existing usage, Locale's
351 * constructors retain their behavior prior to the Java Runtime
352 * Environment version 1.7. The same is largely true for the
353 * <code>toString</code> method. Thus Locale objects can continue to
354 * be used as they were. In particular, clients who parse the output
355 * of toString into language, country, and variant fields can continue
356 * to do so (although this is strongly discouraged), although the
357 * variant field will have additional information in it if script or
358 * extensions are present.
359 *
360 * <p>In addition, BCP 47 imposes syntax restrictions that are not
361 * imposed by Locale's constructors. This means that conversions
362 * between some Locales and BCP 47 language tags cannot be made without
363 * losing information. Thus <code>toLanguageTag</code> cannot
364 * represent the state of locales whose language, country, or variant
365 * do not conform to BCP 47.
366 *
367 * <p>Because of these issues, it is recommended that clients migrate
368 * away from constructing non-conforming locales and use the
369 * <code>forLanguageTag</code> and <code>Locale.Builder</code> APIs instead.
370 * Clients desiring a string representation of the complete locale can
371 * then always rely on <code>toLanguageTag</code> for this purpose.
372 *
373 * <h5><a id="special_cases_constructor">Special cases</a></h5>
374 *
375 * <p>For compatibility reasons, two
376 * non-conforming locales are treated as special cases. These are
377 * <b>{@code ja_JP_JP}</b> and <b>{@code th_TH_TH}</b>. These are ill-formed
378 * in BCP 47 since the variants are too short. To ease migration to BCP 47,
379 * these are treated specially during construction. These two cases (and only
380 * these) cause a constructor to generate an extension, all other values behave
381 * exactly as they did prior to Java 7.
382 *
383 * <p>Java has used {@code ja_JP_JP} to represent Japanese as used in
384 * Japan together with the Japanese Imperial calendar. This is now
385 * representable using a Unicode locale extension, by specifying the
386 * Unicode locale key {@code ca} (for "calendar") and type
387 * {@code japanese}. When the Locale constructor is called with the
388 * arguments "ja", "JP", "JP", the extension "u-ca-japanese" is
389 * automatically added.
390 *
391 * <p>Java has used {@code th_TH_TH} to represent Thai as used in
392 * Thailand together with Thai digits. This is also now representable using
393 * a Unicode locale extension, by specifying the Unicode locale key
394 * {@code nu} (for "number") and value {@code thai}. When the Locale
395 * constructor is called with the arguments "th", "TH", "TH", the
396 * extension "u-nu-thai" is automatically added.
397 *
398 * <h5>Serialization</h5>
399 *
400 * <p>During serialization, writeObject writes all fields to the output
401 * stream, including extensions.
402 *
403 * <p>During deserialization, readResolve adds extensions as described
404 * in <a href="#special_cases_constructor">Special Cases</a>, only
405 * for the two cases th_TH_TH and ja_JP_JP.
406 *
407 * <h5>Legacy language codes</h5>
408 *
409 * <p>Locale's constructor has always converted three language codes to
410 * their earlier, obsoleted forms: {@code he} maps to {@code iw},
411 * {@code yi} maps to {@code ji}, and {@code id} maps to
412 * {@code in}. This continues to be the case, in order to not break
413 * backwards compatibility.
414 *
415 * <p>The APIs added in 1.7 map between the old and new language codes,
416 * maintaining the old codes internal to Locale (so that
417 * <code>getLanguage</code> and <code>toString</code> reflect the old
418 * code), but using the new codes in the BCP 47 language tag APIs (so
419 * that <code>toLanguageTag</code> reflects the new one). This
420 * preserves the equivalence between Locales no matter which code or
421 * API is used to construct them. Java's default resource bundle
422 * lookup mechanism also implements this mapping, so that resources
423 * can be named using either convention, see {@link ResourceBundle.Control}.
424 *
425 * <h5>Three-letter language/country(region) codes</h5>
426 *
427 * <p>The Locale constructors have always specified that the language
428 * and the country param be two characters in length, although in
429 * practice they have accepted any length. The specification has now
430 * been relaxed to allow language codes of two to eight characters and
431 * country (region) codes of two to three characters, and in
432 * particular, three-letter language codes and three-digit region
433 * codes as specified in the IANA Language Subtag Registry. For
434 * compatibility, the implementation still does not impose a length
435 * constraint.
436 *
437 * @see Builder
438 * @see ResourceBundle
439 * @see java.text.Format
440 * @see java.text.NumberFormat
441 * @see java.text.Collator
442 * @author Mark Davis
443 */444 finalclassLocale// : Cloneable445 {
446 447 private__gsharedLocale[size_t] LOCALECACHE;
448 449 /** Useful constant for language.
450 */451 staticLocaleENGLISH() {
452 __gsharedLocalem;
453 returninitOnce!(m)(createConstant("en", ""));
454 }
455 456 /** Useful constant for language.
457 */458 staticLocaleFRENCH() {
459 __gsharedLocalem;
460 returninitOnce!(m)(createConstant("fr", ""));
461 }
462 463 /** Useful constant for language.
464 */465 staticLocaleGERMAN() {
466 __gsharedLocalem;
467 returninitOnce!(m)(createConstant("de", ""));
468 }
469 470 /** Useful constant for language.
471 */472 staticLocaleITALIAN() {
473 __gsharedLocalem;
474 returninitOnce!(m)(createConstant("it", ""));
475 }
476 477 /** Useful constant for language.
478 */479 staticLocaleJAPANESE() {
480 __gsharedLocalem;
481 returninitOnce!(m)(createConstant("ja", ""));
482 }
483 484 /** Useful constant for language.
485 */486 staticLocaleKOREAN() {
487 __gsharedLocalem;
488 returninitOnce!(m)(createConstant("ko", ""));
489 }
490 491 /** Useful constant for language.
492 */493 staticLocaleCHINESE() {
494 __gsharedLocalem;
495 returninitOnce!(m)(createConstant("zh", ""));
496 }
497 498 /** Useful constant for language.
499 */500 staticLocaleSIMPLIFIED_CHINESE() {
501 __gsharedLocalem;
502 returninitOnce!(m)(createConstant("zh", "CN"));
503 }
504 505 /** Useful constant for language.
506 */507 staticLocaleTRADITIONAL_CHINESE() {
508 __gsharedLocalem;
509 returninitOnce!(m)(createConstant("zh", "TW"));
510 }
511 512 /** Useful constant for country.
513 */514 staticLocaleFRANCE() {
515 __gsharedLocalem;
516 returninitOnce!(m)(createConstant("fr", "FR"));
517 }
518 519 /** Useful constant for country.
520 */521 staticLocaleGERMANY() {
522 __gsharedLocalem;
523 returninitOnce!(m)(createConstant("de", "DE"));
524 }
525 526 /** Useful constant for country.
527 */528 staticLocaleITALY() {
529 __gsharedLocalem;
530 returninitOnce!(m)(createConstant("it", "IT"));
531 }
532 533 /** Useful constant for country.
534 */535 staticLocaleJAPAN() {
536 __gsharedLocalem;
537 returninitOnce!(m)(createConstant("ja", "JP"));
538 }
539 540 /** Useful constant for country.
541 */542 staticLocaleKOREA() {
543 __gsharedLocalem;
544 returninitOnce!(m)(createConstant("ko", "KR"));
545 }
546 547 /** Useful constant for country.
548 */549 550 aliasCHINA = SIMPLIFIED_CHINESE;
551 552 /** Useful constant for country.
553 */554 aliasPRC = SIMPLIFIED_CHINESE;
555 556 /** Useful constant for country.
557 */558 aliasTAIWAN = TRADITIONAL_CHINESE;
559 560 561 /** Useful constant for country.
562 */563 staticLocaleUK() {
564 __gsharedLocalem;
565 returninitOnce!(m)(createConstant("en", "GB"));
566 }
567 568 /** Useful constant for country.
569 */570 staticLocaleUS() {
571 __gsharedLocalem;
572 returninitOnce!(m)(createConstant("en", "US"));
573 }
574 575 /** Useful constant for country.
576 */577 staticLocaleCANADA() {
578 __gsharedLocalem;
579 returninitOnce!(m)(createConstant("en", "CA"));
580 }
581 582 /** Useful constant for country.
583 */584 staticLocaleCANADA_FRENCH() {
585 __gsharedLocalem;
586 returninitOnce!(m)(createConstant("fr", "CA"));
587 }
588 589 /**
590 * Useful constant for the root locale. The root locale is the locale whose
591 * language, country, and variant are empty ("") strings. This is regarded
592 * as the base locale of all locales, and is used as the language/country
593 * neutral locale for the locale sensitive operations.
594 *
595 */596 staticLocaleROOT() {
597 __gsharedLocalem;
598 returninitOnce!(m)(createConstant("", ""));
599 }
600 601 /**
602 * The key for the private use extension ('x').
603 *
604 * @see #getExtension(char)
605 * @see Builder#setExtension(char, string)
606 */607 enumcharPRIVATE_USE_EXTENSION = 'x';
608 609 /**
610 * The key for Unicode locale extension ('u').
611 *
612 * @see #getExtension(char)
613 * @see Builder#setExtension(char, string)
614 */615 enumcharUNICODE_LOCALE_EXTENSION = 'u';
616 617 618 /**
619 * Enum for specifying the type defined in ISO 3166. This enum is used to
620 * retrieve the two-letter ISO3166-1 alpha-2, three-letter ISO3166-1
621 * alpha-3, four-letter ISO3166-3 country codes.
622 *
623 * @see #getISOCountries(Locale.IsoCountryCode)
624 */625 staticclassIsoCountryCode626 {
627 /**
628 * PART1_ALPHA2 is used to represent the ISO3166-1 alpha-2 two letter
629 * country codes.
630 */631 __gsharedIsoCountryCodePART1_ALPHA2;
632 633 sharedstaticthis()
634 {
635 PART1_ALPHA2 = newclassIsoCountryCode636 {
637 overrideSet!(string) createCountryCodeSet()
638 {
639 implementationMissing();
640 returnnull;
641 // return Set.of(Locale.getISOCountries());642 }
643 };
644 PART1_ALPHA3 = newclassIsoCountryCode645 {
646 overrideSet!(string) createCountryCodeSet()
647 {
648 implementationMissing();
649 returnnull;
650 // return LocaleISOData.computeISO3166_1Alpha3Countries();651 }
652 };
653 654 PART3 = newclassIsoCountryCode655 {
656 overrideSet!(string) createCountryCodeSet()
657 {
658 implementationMissing();
659 returnnull;
660 // return Set.of(LocaleISOData.ISO3166_3);661 }
662 };
663 }
664 665 /**
666 *
667 * PART1_ALPHA3 is used to represent the ISO3166-1 alpha-3 three letter
668 * country codes.
669 */670 __gsharedIsoCountryCodePART1_ALPHA3;
671 672 /**
673 * PART3 is used to represent the ISO3166-3 four letter country codes.
674 */675 __gsharedIsoCountryCodePART3;
676 677 /**
678 * Concrete implementation of this method attempts to compute value
679 * for iso3166CodesMap for each IsoCountryCode type key.
680 */681 abstractSet!(string) createCountryCodeSet();
682 683 /**
684 * Map to hold country codes for each ISO3166 part.
685 */686 private__gsharedMap!(IsoCountryCode, Set!(string)) iso3166CodesMap;
687 688 sharedstaticthis()
689 {
690 iso3166CodesMap = newHashMap!(IsoCountryCode, Set!(string))();
691 }
692 693 /**
694 * This method is called from Locale class to retrieve country code set
695 * for getISOCountries(type)
696 */697 staticSet!(string) retrieveISOCountryCodes(IsoCountryCodetype)
698 {
699 implementationMissing();
700 returnnull;
701 // return iso3166CodesMap.computeIfAbsent(type, IsoCountryCode.createCountryCodeSet);702 }
703 }
704 705 /**
706 * Display types for retrieving localized names from the name providers.
707 */708 privateenumintDISPLAY_LANGUAGE = 0;
709 privateenumintDISPLAY_COUNTRY = 1;
710 privateenumintDISPLAY_VARIANT = 2;
711 privateenumintDISPLAY_SCRIPT = 3;
712 privateenumintDISPLAY_UEXT_KEY = 4;
713 privateenumintDISPLAY_UEXT_TYPE = 5;
714 715 privatestringlanguage;
716 privatestringscript;
717 privatestringregion;
718 privatestringvariant;
719 720 /**
721 * Private constructor used by getInstance method
722 */723 // private this(BaseLocale baseLocale, LocaleExtensions extensions) {724 // this.baseLocale = baseLocale;725 // this.localeExtensions = extensions;726 // }727 728 /**
729 * Construct a locale from language, country and variant.
730 * This constructor normalizes the language value to lowercase and
731 * the country value to uppercase.
732 * <p>
733 * <b>Note:</b>
734 * <ul>
735 * <li>ISO 639 is not a stable standard; some of the language codes it defines
736 * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
737 * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
738 * API on Locale will return only the OLD codes.
739 * <li>For backward compatibility reasons, this constructor does not make
740 * any syntactic checks on the input.
741 * <li>The two cases ("ja", "JP", "JP") and ("th", "TH", "TH") are handled specially,
742 * see <a href="#special_cases_constructor">Special Cases</a> for more information.
743 * </ul>
744 *
745 * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
746 * up to 8 characters in length. See the <code>Locale</code> class description about
747 * valid language values.
748 * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
749 * See the <code>Locale</code> class description about valid country values.
750 * @param variant Any arbitrary value used to indicate a variation of a <code>Locale</code>.
751 * See the <code>Locale</code> class description for the details.
752 * @exception NullPointerException thrown if any argument is null.
753 */754 this(stringlanguage, stringcountry, stringvariant)
755 {
756 if (languageisnull || countryisnull || variantisnull)
757 {
758 thrownewNullPointerException();
759 }
760 761 this.language = convertOldISOCodes(language);
762 this.region = country;
763 this.variant = variant;
764 }
765 766 /**
767 * Construct a locale from language and country.
768 * This constructor normalizes the language value to lowercase and
769 * the country value to uppercase.
770 * <p>
771 * <b>Note:</b>
772 * <ul>
773 * <li>ISO 639 is not a stable standard; some of the language codes it defines
774 * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
775 * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
776 * API on Locale will return only the OLD codes.
777 * <li>For backward compatibility reasons, this constructor does not make
778 * any syntactic checks on the input.
779 * </ul>
780 *
781 * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
782 * up to 8 characters in length. See the <code>Locale</code> class description about
783 * valid language values.
784 * @param country An ISO 3166 alpha-2 country code or a UN M.49 numeric-3 area code.
785 * See the <code>Locale</code> class description about valid country values.
786 * @exception NullPointerException thrown if either argument is null.
787 */788 this(stringlanguage, stringcountry)
789 {
790 this(language, country, "");
791 }
792 793 /**
794 * Construct a locale from a language code.
795 * This constructor normalizes the language value to lowercase.
796 * <p>
797 * <b>Note:</b>
798 * <ul>
799 * <li>ISO 639 is not a stable standard; some of the language codes it defines
800 * (specifically "iw", "ji", and "in") have changed. This constructor accepts both the
801 * old codes ("iw", "ji", and "in") and the new codes ("he", "yi", and "id"), but all other
802 * API on Locale will return only the OLD codes.
803 * <li>For backward compatibility reasons, this constructor does not make
804 * any syntactic checks on the input.
805 * </ul>
806 *
807 * @param language An ISO 639 alpha-2 or alpha-3 language code, or a language subtag
808 * up to 8 characters in length. See the <code>Locale</code> class description about
809 * valid language values.
810 * @exception NullPointerException thrown if argument is null.
811 */812 this(stringlanguage)
813 {
814 this(language, "", "");
815 }
816 817 /**
818 * This method must be called only for creating the Locale.*
819 * constants due to making shortcuts.
820 */821 privatestaticLocalecreateConstant(stringlang, stringcountry)
822 {
823 // BaseLocale base = BaseLocale.createInstance(lang, country);824 // return getInstance(base, null);825 Localele = newLocale(lang, country);
826 size_tkey = hashOf(lang, country) ;
827 LOCALECACHE[key] = le;
828 829 returnle;
830 }
831 832 staticsize_thashOf(stringlanguage, stringcountry, stringscript = null, stringvariant = null) {
833 size_tr = 0;
834 if(language !isnull)
835 r += .hashOf(language.toLower());
836 if(country !isnull)
837 r += .hashOf(country.toLower());
838 if(script !isnull)
839 r += .hashOf(script.toLower());
840 if(variant !isnull)
841 r += .hashOf(variant.toLower());
842 returnr;
843 }
844 845 /**
846 * Returns a <code>Locale</code> constructed from the given
847 * <code>language</code>, <code>country</code> and
848 * <code>variant</code>. If the same <code>Locale</code> instance
849 * is available in the cache, then that instance is
850 * returned. Otherwise, a new <code>Locale</code> instance is
851 * created and cached.
852 *
853 * @param language lowercase 2 to 8 language code.
854 * @param country uppercase two-letter ISO-3166 code and numeric-3 UN M.49 area code.
855 * @param variant vendor and browser specific code. See class description.
856 * @return the <code>Locale</code> instance requested
857 * @exception NullPointerException if any argument is null.
858 */859 staticLocalegetInstance(stringlanguage, stringcountry, stringvariant) {
860 returngetInstance(language, "", country, variant);
861 }
862 863 staticLocalegetInstance(stringlanguage, stringscript, stringcountry, stringvariant) {
864 if (languageisnull || scriptisnull || countryisnull || variantisnull) {
865 thrownewNullPointerException();
866 }
867 868 version(HUNT_DEBUG) {
869 tracef("language=%s, script=%s, country=%s, variant=%s",
870 language, script, country, variant);
871 }
872 size_tkey = hashOf(language, country, script, variant);
873 Localele = LOCALECACHE.get(key, null);
874 if(leisnull) {
875 le = newLocale(language, country, variant);
876 LOCALECACHE[key] = le;
877 }
878 returnle;
879 }
880 881 /**
882 * Gets the current value of the default locale for this instance
883 * of the Java Virtual Machine.
884 * <p>
885 * The Java Virtual Machine sets the default locale during startup
886 * based on the host environment. It is used by many locale-sensitive
887 * methods if no locale is explicitly specified.
888 * It can be changed using the
889 * {@link #setDefault(java.util.Locale) setDefault} method.
890 *
891 * @return the default locale for this instance of the Java Virtual Machine
892 */893 staticLocalegetDefault()
894 {
895 returninitOnce!(defaultLocale)(initDefault());
896 // do not synchronize this method - see 4071298897 }
898 private__gsharedLocaledefaultLocale;
899 900 /**
901 * Gets the current value of the default locale for the specified Category
902 * for this instance of the Java Virtual Machine.
903 * <p>
904 * The Java Virtual Machine sets the default locale during startup based
905 * on the host environment. It is used by many locale-sensitive methods
906 * if no locale is explicitly specified. It can be changed using the
907 * setDefault(LocaleCategory, Locale) method.
908 *
909 * @param category - the specified category to get the default locale
910 * @throws NullPointerException if category is null
911 * @return the default locale for the specified Category for this instance
912 * of the Java Virtual Machine
913 * @see #setDefault(LocaleCategory, Locale)
914 */915 staticLocalegetDefault(LocaleCategorycategory) {
916 // do not synchronize this method - see 4071298917 if(category == LocaleCategory.DISPLAY) {
918 if (defaultDisplayLocaleisnull) {
919 synchronized {
920 if (defaultDisplayLocaleisnull) {
921 defaultDisplayLocale = initDefault(category);
922 }
923 }
924 }
925 returndefaultDisplayLocale;
926 } elseif(category == LocaleCategory.FORMAT) {
927 if (defaultFormatLocaleisnull) {
928 synchronized {
929 if (defaultFormatLocaleisnull) {
930 defaultFormatLocale = initDefault(category);
931 }
932 }
933 }
934 returndefaultFormatLocale;
935 } else {
936 assert(false, "Unknown locale category");
937 }
938 }
939 940 privatestaticLocaleinitDefault() {
941 ConfigBuilderprops = Environment.getProperties();
942 stringlanguage = props.getProperty("user.language", "en");
943 stringscript = props.getProperty("user.script", "");
944 stringcountry = props.getProperty("user.country", "");
945 stringvariant = props.getProperty("user.variant", "");
946 947 returngetInstance(language, script, country, variant);
948 }
949 950 privatestaticLocaleinitDefault(LocaleCategorycategory) {
951 ConfigBuilderprops = Environment.getProperties();
952 LocaledefaultLocale = getDefault();
953 954 returngetInstance(
955 props.getProperty(category.languageKey,
956 defaultLocale.getLanguage()),
957 props.getProperty(category.scriptKey,
958 defaultLocale.getScript()),
959 props.getProperty(category.countryKey,
960 defaultLocale.getCountry()),
961 props.getProperty(category.variantKey,
962 defaultLocale.getVariant()));
963 }
964 965 966 /**
967 * Sets the default locale for this instance of the Java Virtual Machine.
968 * This does not affect the host locale.
969 * <p>
970 * If there is a security manager, its <code>checkPermission</code>
971 * method is called with a <code>PropertyPermission("user.language", "write")</code>
972 * permission before the default locale is changed.
973 * <p>
974 * The Java Virtual Machine sets the default locale during startup
975 * based on the host environment. It is used by many locale-sensitive
976 * methods if no locale is explicitly specified.
977 * <p>
978 * Since changing the default locale may affect many different areas
979 * of functionality, this method should only be used if the caller
980 * is prepared to reinitialize locale-sensitive code running
981 * within the same Java Virtual Machine.
982 * <p>
983 * By setting the default locale with this method, all of the default
984 * locales for each Category are also set to the specified default locale.
985 *
986 * @throws SecurityException
987 * if a security manager exists and its
988 * <code>checkPermission</code> method doesn't allow the operation.
989 * @throws NullPointerException if <code>newLocale</code> is null
990 * @param newLocale the new default locale
991 * @see SecurityManager#checkPermission
992 * @see java.util.PropertyPermission
993 */994 staticvoidsetDefault(LocalenewLocale) {
995 setDefault(LocaleCategory.DISPLAY, newLocale);
996 setDefault(LocaleCategory.FORMAT, newLocale);
997 defaultLocale = newLocale;
998 }
999 1000 /**
1001 * Sets the default locale for the specified Category for this instance
1002 * of the Java Virtual Machine. This does not affect the host locale.
1003 * <p>
1004 * If there is a security manager, its checkPermission method is called
1005 * with a PropertyPermission("user.language", "write") permission before
1006 * the default locale is changed.
1007 * <p>
1008 * The Java Virtual Machine sets the default locale during startup based
1009 * on the host environment. It is used by many locale-sensitive methods
1010 * if no locale is explicitly specified.
1011 * <p>
1012 * Since changing the default locale may affect many different areas of
1013 * functionality, this method should only be used if the caller is
1014 * prepared to reinitialize locale-sensitive code running within the
1015 * same Java Virtual Machine.
1016 *
1017 * @param category - the specified category to set the default locale
1018 * @param newLocale - the new default locale
1019 * @throws SecurityException if a security manager exists and its
1020 * checkPermission method doesn't allow the operation.
1021 * @throws NullPointerException if category and/or newLocale is null
1022 * @see SecurityManager#checkPermission(java.security.Permission)
1023 * @see PropertyPermission
1024 * @see #getDefault(LocaleCategory)
1025 */1026 staticvoidsetDefault(LocaleCategorycategory, LocalenewLocale) {
1027 implementationMissing(false);
1028 // if (category is null)1029 // throw new NullPointerException("Category cannot be NULL");1030 // if (newLocale is null)1031 // throw new NullPointerException("Can't set default locale to NULL");1032 1033 // SecurityManager sm = System.getSecurityManager();1034 // if (sm !is null) sm.checkPermission(new PropertyPermission1035 // ("user.language", "write"));1036 // switch (category) {1037 // case DISPLAY:1038 // defaultDisplayLocale = newLocale;1039 // break;1040 // case FORMAT:1041 // defaultFormatLocale = newLocale;1042 // break;1043 // default:1044 // assert false: "Unknown Category";1045 // }1046 }
1047 1048 // /**1049 // * Returns an array of all installed locales.1050 // * The returned array represents the union of locales supported1051 // * by the Java runtime environment and by installed1052 // * {@link java.util.spi.LocaleServiceProvider LocaleServiceProvider}1053 // * implementations. It must contain at least a <code>Locale</code>1054 // * instance equal to {@link java.util.Locale#US Locale.US}.1055 // *1056 // * @return An array of installed locales.1057 // */1058 // static Locale[] getAvailableLocales() {1059 // return LocaleServiceProviderPool.getAllAvailableLocales();1060 // }1061 1062 // /**1063 // * Returns a list of all 2-letter country codes defined in ISO 3166.1064 // * Can be used to create Locales.1065 // * This method is equivalent to {@link #getISOCountries(Locale.IsoCountryCode type)}1066 // * with {@code type} {@link IsoCountryCode#PART1_ALPHA2}.1067 // * <p>1068 // * <b>Note:</b> The <code>Locale</code> class also supports other codes for1069 // * country (region), such as 3-letter numeric UN M.49 area codes.1070 // * Therefore, the list returned by this method does not contain ALL valid1071 // * codes that can be used to create Locales.1072 // * <p>1073 // * Note that this method does not return obsolete 2-letter country codes.1074 // * ISO3166-3 codes which designate country codes for those obsolete codes,1075 // * can be retrieved from {@link #getISOCountries(Locale.IsoCountryCode type)} with1076 // * {@code type} {@link IsoCountryCode#PART3}.1077 // * @return An array of ISO 3166 two-letter country codes.1078 // */1079 // static string[] getISOCountries() {1080 // if (isoCountries is null) {1081 // isoCountries = getISO2Table(LocaleISOData.isoCountryTable);1082 // }1083 // string[] result = new string[isoCountries.length];1084 // System.arraycopy(isoCountries, 0, result, 0, isoCountries.length);1085 // return result;1086 // }1087 1088 // /**1089 // * Returns a {@code Set} of ISO3166 country codes for the specified type.1090 // *1091 // * @param type {@link Locale.IsoCountryCode} specified ISO code type.1092 // * @see java.util.Locale.IsoCountryCode1093 // * @throws NullPointerException if type is null1094 // * @return a {@code Set} of ISO country codes for the specified type.1095 // */1096 // static Set!(string) getISOCountries(IsoCountryCode type) {1097 // assert(type);1098 // return IsoCountryCode.retrieveISOCountryCodes(type);1099 // }1100 1101 // /**1102 // * Returns a list of all 2-letter language codes defined in ISO 639.1103 // * Can be used to create Locales.1104 // * <p>1105 // * <b>Note:</b>1106 // * <ul>1107 // * <li>ISO 639 is not a stable standard— some languages' codes have changed.1108 // * The list this function returns includes both the new and the old codes for the1109 // * languages whose codes have changed.1110 // * <li>The <code>Locale</code> class also supports language codes up to1111 // * 8 characters in length. Therefore, the list returned by this method does1112 // * not contain ALL valid codes that can be used to create Locales.1113 // * </ul>1114 // *1115 // * @return An array of ISO 639 two-letter language codes.1116 // */1117 // static string[] getISOLanguages() {1118 // if (isoLanguages is null) {1119 // isoLanguages = getISO2Table(LocaleISOData.isoLanguageTable);1120 // }1121 // string[] result = new string[isoLanguages.length];1122 // System.arraycopy(isoLanguages, 0, result, 0, isoLanguages.length);1123 // return result;1124 // }1125 1126 // private static string[] getISO2Table(string table) {1127 // int len = table.length() / 5;1128 // string[] isoTable = new string[len];1129 // for (int i = 0, j = 0; i < len; i++, j += 5) {1130 // isoTable[i] = table.substring(j, j + 2);1131 // }1132 // return isoTable;1133 // }1134 1135 /**
1136 * Returns the language code of this Locale.
1137 *
1138 * <p><b>Note:</b> ISO 639 is not a stable standard— some languages' codes have changed.
1139 * Locale's constructor recognizes both the new and the old codes for the languages
1140 * whose codes have changed, but this function always returns the old code. If you
1141 * want to check for a specific language whose code has changed, don't do
1142 * <pre>
1143 * if (locale.getLanguage().equals("he")) // BAD!
1144 * ...
1145 * </pre>
1146 * Instead, do
1147 * <pre>
1148 * if (locale.getLanguage().equals(new Locale("he").getLanguage()))
1149 * ...
1150 * </pre>
1151 * @return The language code, or the empty string if none is defined.
1152 * @see #getDisplayLanguage
1153 */1154 stringgetLanguage() {
1155 returnlanguage;
1156 }
1157 1158 /**
1159 * Returns the script for this locale, which should
1160 * either be the empty string or an ISO 15924 4-letter script
1161 * code. The first letter is uppercase and the rest are
1162 * lowercase, for example, 'Latn', 'Cyrl'.
1163 *
1164 * @return The script code, or the empty string if none is defined.
1165 * @see #getDisplayScript
1166 */1167 stringgetScript() {
1168 returnscript;
1169 }
1170 1171 /**
1172 * Returns the country/region code for this locale, which should
1173 * either be the empty string, an uppercase ISO 3166 2-letter code,
1174 * or a UN M.49 3-digit code.
1175 *
1176 * @return The country/region code, or the empty string if none is defined.
1177 * @see #getDisplayCountry
1178 */1179 stringgetCountry() {
1180 returnregion;
1181 }
1182 1183 /**
1184 * Returns the variant code for this locale.
1185 *
1186 * @return The variant code, or the empty string if none is defined.
1187 * @see #getDisplayVariant
1188 */1189 stringgetVariant() {
1190 returnvariant;
1191 }
1192 1193 /**
1194 * Returns {@code true} if this {@code Locale} has any <a href="#def_extensions">
1195 * extensions</a>.
1196 *
1197 * @return {@code true} if this {@code Locale} has any extensions
1198 */1199 boolhasExtensions() {
1200 returnfalse;
1201 }
1202 1203 // /**1204 // * Returns a copy of this {@code Locale} with no <a href="#def_extensions">1205 // * extensions</a>. If this {@code Locale} has no extensions, this {@code Locale}1206 // * is returned.1207 // *1208 // * @return a copy of this {@code Locale} with no extensions, or {@code this}1209 // * if {@code this} has no extensions1210 // */1211 // Locale stripExtensions() {1212 // return hasExtensions() ? Locale.getInstance(baseLocale, null) : this;1213 // }1214 1215 // /**1216 // * Returns the extension (or private use) value associated with1217 // * the specified key, or null if there is no extension1218 // * associated with the key. To be well-formed, the key must be one1219 // * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so1220 // * for example 'z' and 'Z' represent the same extension.1221 // *1222 // * @param key the extension key1223 // * @return The extension, or null if this locale defines no1224 // * extension for the specified key.1225 // * @throws IllegalArgumentException if key is not well-formed1226 // * @see #PRIVATE_USE_EXTENSION1227 // * @see #UNICODE_LOCALE_EXTENSION1228 // */1229 // string getExtension(char key) {1230 // if (!LocaleExtensions.isValidKey(key)) {1231 // throw new IllegalArgumentException("Ill-formed extension key: " ~ key);1232 // }1233 // return hasExtensions() ? localeExtensions.getExtensionValue(key) : null;1234 // }1235 1236 // /**1237 // * Returns the set of extension keys associated with this locale, or the1238 // * empty set if it has no extensions. The returned set is unmodifiable.1239 // * The keys will all be lower-case.1240 // *1241 // * @return The set of extension keys, or the empty set if this locale has1242 // * no extensions.1243 // */1244 // Set<Character> getExtensionKeys() {1245 // if (!hasExtensions()) {1246 // return Collections.emptySet();1247 // }1248 // return localeExtensions.getKeys();1249 // }1250 1251 // /**1252 // * Returns the set of unicode locale attributes associated with1253 // * this locale, or the empty set if it has no attributes. The1254 // * returned set is unmodifiable.1255 // *1256 // * @return The set of attributes.1257 // */1258 // Set!(string) getUnicodeLocaleAttributes() {1259 // if (!hasExtensions()) {1260 // return Collections.emptySet();1261 // }1262 // return localeExtensions.getUnicodeLocaleAttributes();1263 // }1264 1265 // /**1266 // * Returns the Unicode locale type associated with the specified Unicode locale key1267 // * for this locale. Returns the empty string for keys that are defined with no type.1268 // * Returns null if the key is not defined. Keys are case-insensitive. The key must1269 // * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is1270 // * thrown.1271 // *1272 // * @param key the Unicode locale key1273 // * @return The Unicode locale type associated with the key, or null if the1274 // * locale does not define the key.1275 // * @throws IllegalArgumentException if the key is not well-formed1276 // * @throws NullPointerException if <code>key</code> is null1277 // */1278 stringgetUnicodeLocaleType(stringkey) {
1279 /* if (!isUnicodeExtensionKey(key)) {
1280 throw new IllegalArgumentException("Ill-formed Unicode locale key: " ~ key);
1281 }
1282 return hasExtensions() ? localeExtensions.getUnicodeLocaleType(key) : null; */1283 return"iso";
1284 }
1285 1286 // /**1287 // * Returns the set of Unicode locale keys defined by this locale, or the empty set if1288 // * this locale has none. The returned set is immutable. Keys are all lower case.1289 // *1290 // * @return The set of Unicode locale keys, or the empty set if this locale has1291 // * no Unicode locale keywords.1292 // */1293 // Set!(string) getUnicodeLocaleKeys() {1294 // if (localeExtensions is null) {1295 // return Collections.emptySet();1296 // }1297 // return localeExtensions.getUnicodeLocaleKeys();1298 // }1299 1300 // /**1301 // * Package locale method returning the Locale's BaseLocale,1302 // * used by ResourceBundle1303 // * @return base locale of this Locale1304 // */1305 // BaseLocale getBaseLocale() {1306 // return baseLocale;1307 // }1308 1309 // /**1310 // * Package private method returning the Locale's LocaleExtensions,1311 // * used by ResourceBundle.1312 // * @return locale extensions of this Locale,1313 // * or {@code null} if no extensions are defined1314 // */1315 // LocaleExtensions getLocaleExtensions() {1316 // return localeExtensions;1317 // }1318 1319 /**
1320 * Returns a string representation of this <code>Locale</code>
1321 * object, consisting of language, country, variant, script,
1322 * and extensions as below:
1323 * <blockquote>
1324 * language ~ "_" ~ country ~ "_" ~ (variant ~ "_#" | "#") + script ~ "_" ~ extensions
1325 * </blockquote>
1326 *
1327 * Language is always lower case, country is always upper case, script is always title
1328 * case, and extensions are always lower case. Extensions and private use subtags
1329 * will be in canonical order as explained in {@link #toLanguageTag}.
1330 *
1331 * <p>When the locale has neither script nor extensions, the result is the same as in
1332 * Java 6 and prior.
1333 *
1334 * <p>If both the language and country fields are missing, this function will return
1335 * the empty string, even if the variant, script, or extensions field is present (you
1336 * can't have a locale with just a variant, the variant must accompany a well-formed
1337 * language or country code).
1338 *
1339 * <p>If script or extensions are present and variant is missing, no underscore is
1340 * added before the "#".
1341 *
1342 * <p>This behavior is designed to support debugging and to be compatible with
1343 * previous uses of <code>toString</code> that expected language, country, and variant
1344 * fields only. To represent a Locale as a string for interchange purposes, use
1345 * {@link #toLanguageTag}.
1346 *
1347 * <p>Examples: <ul>
1348 * <li>{@code en}</li>
1349 * <li>{@code de_DE}</li>
1350 * <li>{@code _GB}</li>
1351 * <li>{@code en_US_WIN}</li>
1352 * <li>{@code de__POSIX}</li>
1353 * <li>{@code zh_CN_#Hans}</li>
1354 * <li>{@code zh_TW_#Hant_x-java}</li>
1355 * <li>{@code th_TH_TH_#u-nu-thai}</li></ul>
1356 *
1357 * @return A string representation of the Locale, for debugging.
1358 * @see #getDisplayName
1359 * @see #toLanguageTag
1360 */1361 overridestringtoString() {
1362 1363 booll = (language.length != 0);
1364 bools = (script.length != 0);
1365 boolr = (region.length != 0);
1366 boolv = (variant.length != 0);
1367 // bool e = (localeExtensions !is null && localeExtensions.getID().length() != 0);1368 1369 StringBuilderresult = newStringBuilder(language);
1370 if (r || (l && (v || s ))) {
1371 result.append('_')
1372 .append(region); // This may just append '_'1373 }
1374 if (v && (l || r)) {
1375 result.append('_')
1376 .append(variant);
1377 }
1378 1379 if (s && (l || r)) {
1380 result.append("_#")
1381 .append(script);
1382 }
1383 1384 returnresult.toString();
1385 }
1386 1387 // /**1388 // * Returns a well-formed IETF BCP 47 language tag representing1389 // * this locale.1390 // *1391 // * <p>If this <code>Locale</code> has a language, country, or1392 // * variant that does not satisfy the IETF BCP 47 language tag1393 // * syntax requirements, this method handles these fields as1394 // * described below:1395 // *1396 // * <p><b>Language:</b> If language is empty, or not <a1397 // * href="#def_language" >well-formed</a> (for example "a" or1398 // * "e2"), it will be emitted as "und" (Undetermined).1399 // *1400 // * <p><b>Country:</b> If country is not <a1401 // * href="#def_region">well-formed</a> (for example "12" or "USA"),1402 // * it will be omitted.1403 // *1404 // * <p><b>Variant:</b> If variant <b>is</b> <a1405 // * href="#def_variant">well-formed</a>, each sub-segment1406 // * (delimited by '-' or '_') is emitted as a subtag. Otherwise:1407 // * <ul>1408 // *1409 // * <li>if all sub-segments match <code>[0-9a-zA-Z]{1,8}</code>1410 // * (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first1411 // * ill-formed sub-segment and all following will be appended to1412 // * the private use subtag. The first appended subtag will be1413 // * "lvariant", followed by the sub-segments in order, separated by1414 // * hyphen. For example, "x-lvariant-WIN",1415 // * "Oracle-x-lvariant-JDK-Standard-Edition".1416 // *1417 // * <li>if any sub-segment does not match1418 // * <code>[0-9a-zA-Z]{1,8}</code>, the variant will be truncated1419 // * and the problematic sub-segment and all following sub-segments1420 // * will be omitted. If the remainder is non-empty, it will be1421 // * emitted as a private use subtag as above (even if the remainder1422 // * turns out to be well-formed). For example,1423 // * "Solaris_isjustthecoolestthing" is emitted as1424 // * "x-lvariant-Solaris", not as "solaris".</li></ul>1425 // *1426 // * <p><b>Special Conversions:</b> Java supports some old locale1427 // * representations, including deprecated ISO language codes,1428 // * for compatibility. This method performs the following1429 // * conversions:1430 // * <ul>1431 // *1432 // * <li>Deprecated ISO language codes "iw", "ji", and "in" are1433 // * converted to "he", "yi", and "id", respectively.1434 // *1435 // * <li>A locale with language "no", country "NO", and variant1436 // * "NY", representing Norwegian Nynorsk (Norway), is converted1437 // * to a language tag "nn-NO".</li></ul>1438 // *1439 // * <p><b>Note:</b> Although the language tag created by this1440 // * method is well-formed (satisfies the syntax requirements1441 // * defined by the IETF BCP 47 specification), it is not1442 // * necessarily a valid BCP 47 language tag. For example,1443 // * <pre>1444 // * new Locale("xx", "YY").toLanguageTag();</pre>1445 // *1446 // * will return "xx-YY", but the language subtag "xx" and the1447 // * region subtag "YY" are invalid because they are not registered1448 // * in the IANA Language Subtag Registry.1449 // *1450 // * @return a BCP47 language tag representing the locale1451 // * @see #forLanguageTag(string)1452 // */1453 // string toLanguageTag() {1454 // if (languageTag !is null) {1455 // return languageTag;1456 // }1457 1458 // LanguageTag tag = LanguageTag.parseLocale(baseLocale, localeExtensions);1459 // StringBuilder buf = new StringBuilder();1460 1461 // string subtag = tag.getLanguage();1462 // if (subtag.length() > 0) {1463 // buf.append(LanguageTag.canonicalizeLanguage(subtag));1464 // }1465 1466 // subtag = tag.getScript();1467 // if (subtag.length() > 0) {1468 // buf.append(LanguageTag.SEP);1469 // buf.append(LanguageTag.canonicalizeScript(subtag));1470 // }1471 1472 // subtag = tag.getRegion();1473 // if (subtag.length() > 0) {1474 // buf.append(LanguageTag.SEP);1475 // buf.append(LanguageTag.canonicalizeRegion(subtag));1476 // }1477 1478 // List<string>subtags = tag.getVariants();1479 // for (string s : subtags) {1480 // buf.append(LanguageTag.SEP);1481 // // preserve casing1482 // buf.append(s);1483 // }1484 1485 // subtags = tag.getExtensions();1486 // for (string s : subtags) {1487 // buf.append(LanguageTag.SEP);1488 // buf.append(LanguageTag.canonicalizeExtension(s));1489 // }1490 1491 // subtag = tag.getPrivateuse();1492 // if (subtag.length() > 0) {1493 // if (buf.length() > 0) {1494 // buf.append(LanguageTag.SEP);1495 // }1496 // buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP);1497 // // preserve casing1498 // buf.append(subtag);1499 // }1500 1501 // string langTag = buf.toString();1502 // synchronized (this) {1503 // if (languageTag is null) {1504 // languageTag = langTag;1505 // }1506 // }1507 // return languageTag;1508 // }1509 1510 // /**1511 // * Returns a locale for the specified IETF BCP 47 language tag string.1512 // *1513 // * <p>If the specified language tag contains any ill-formed subtags,1514 // * the first such subtag and all following subtags are ignored. Compare1515 // * to {@link Locale.Builder#setLanguageTag} which throws an exception1516 // * in this case.1517 // *1518 // * <p>The following <b>conversions</b> are performed:<ul>1519 // *1520 // * <li>The language code "und" is mapped to language "".1521 // *1522 // * <li>The language codes "he", "yi", and "id" are mapped to "iw",1523 // * "ji", and "in" respectively. (This is the same canonicalization1524 // * that's done in Locale's constructors.)1525 // *1526 // * <li>The portion of a private use subtag prefixed by "lvariant",1527 // * if any, is removed and appended to the variant field in the1528 // * result locale (without case normalization). If it is then1529 // * empty, the private use subtag is discarded:1530 // *1531 // * <pre>1532 // * Locale loc;1533 // * loc = Locale.forLanguageTag("en-US-x-lvariant-POSIX");1534 // * loc.getVariant(); // returns "POSIX"1535 // * loc.getExtension('x'); // returns null1536 // *1537 // * loc = Locale.forLanguageTag("de-POSIX-x-URP-lvariant-Abc-Def");1538 // * loc.getVariant(); // returns "POSIX_Abc_Def"1539 // * loc.getExtension('x'); // returns "urp"1540 // * </pre>1541 // *1542 // * <li>When the languageTag argument contains an extlang subtag,1543 // * the first such subtag is used as the language, and the primary1544 // * language subtag and other extlang subtags are ignored:1545 // *1546 // * <pre>1547 // * Locale.forLanguageTag("ar-aao").getLanguage(); // returns "aao"1548 // * Locale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US"1549 // * </pre>1550 // *1551 // * <li>Case is normalized except for variant tags, which are left1552 // * unchanged. Language is normalized to lower case, script to1553 // * title case, country to upper case, and extensions to lower1554 // * case.1555 // *1556 // * <li>If, after processing, the locale would exactly match either1557 // * ja_JP_JP or th_TH_TH with no extensions, the appropriate1558 // * extensions are added as though the constructor had been called:1559 // *1560 // * <pre>1561 // * Locale.forLanguageTag("ja-JP-x-lvariant-JP").toLanguageTag();1562 // * // returns "ja-JP-u-ca-japanese-x-lvariant-JP"1563 // * Locale.forLanguageTag("th-TH-x-lvariant-TH").toLanguageTag();1564 // * // returns "th-TH-u-nu-thai-x-lvariant-TH"1565 // * </pre></ul>1566 // *1567 // * <p>This implements the 'Language-Tag' production of BCP47, and1568 // * so supports grandfathered (regular and irregular) as well as1569 // * private use language tags. Stand alone private use tags are1570 // * represented as empty language and extension 'x-whatever',1571 // * and grandfathered tags are converted to their canonical replacements1572 // * where they exist.1573 // *1574 // * <p>Grandfathered tags with canonical replacements are as follows:1575 // *1576 // * <table class="striped">1577 // * <caption style="display:none">Grandfathered tags with canonical replacements</caption>1578 // * <thead style="text-align:center">1579 // * <tr><th scope="col" style="padding: 0 2px">grandfathered tag</th><th scope="col" style="padding: 0 2px">modern replacement</th></tr>1580 // * </thead>1581 // * <tbody style="text-align:center">1582 // * <tr><th scope="row">art-lojban</th><td>jbo</td></tr>1583 // * <tr><th scope="row">i-ami</th><td>ami</td></tr>1584 // * <tr><th scope="row">i-bnn</th><td>bnn</td></tr>1585 // * <tr><th scope="row">i-hak</th><td>hak</td></tr>1586 // * <tr><th scope="row">i-klingon</th><td>tlh</td></tr>1587 // * <tr><th scope="row">i-lux</th><td>lb</td></tr>1588 // * <tr><th scope="row">i-navajo</th><td>nv</td></tr>1589 // * <tr><th scope="row">i-pwn</th><td>pwn</td></tr>1590 // * <tr><th scope="row">i-tao</th><td>tao</td></tr>1591 // * <tr><th scope="row">i-tay</th><td>tay</td></tr>1592 // * <tr><th scope="row">i-tsu</th><td>tsu</td></tr>1593 // * <tr><th scope="row">no-bok</th><td>nb</td></tr>1594 // * <tr><th scope="row">no-nyn</th><td>nn</td></tr>1595 // * <tr><th scope="row">sgn-BE-FR</th><td>sfb</td></tr>1596 // * <tr><th scope="row">sgn-BE-NL</th><td>vgt</td></tr>1597 // * <tr><th scope="row">sgn-CH-DE</th><td>sgg</td></tr>1598 // * <tr><th scope="row">zh-guoyu</th><td>cmn</td></tr>1599 // * <tr><th scope="row">zh-hakka</th><td>hak</td></tr>1600 // * <tr><th scope="row">zh-min-nan</th><td>nan</td></tr>1601 // * <tr><th scope="row">zh-xiang</th><td>hsn</td></tr>1602 // * </tbody>1603 // * </table>1604 // *1605 // * <p>Grandfathered tags with no modern replacement will be1606 // * converted as follows:1607 // *1608 // * <table class="striped">1609 // * <caption style="display:none">Grandfathered tags with no modern replacement</caption>1610 // * <thead style="text-align:center">1611 // * <tr><th scope="col" style="padding: 0 2px">grandfathered tag</th><th scope="col" style="padding: 0 2px">converts to</th></tr>1612 // * </thead>1613 // * <tbody style="text-align:center">1614 // * <tr><th scope="row">cel-gaulish</th><td>xtg-x-cel-gaulish</td></tr>1615 // * <tr><th scope="row">en-GB-oed</th><td>en-GB-x-oed</td></tr>1616 // * <tr><th scope="row">i-default</th><td>en-x-i-default</td></tr>1617 // * <tr><th scope="row">i-enochian</th><td>und-x-i-enochian</td></tr>1618 // * <tr><th scope="row">i-mingo</th><td>see-x-i-mingo</td></tr>1619 // * <tr><th scope="row">zh-min</th><td>nan-x-zh-min</td></tr>1620 // * </tbody>1621 // * </table>1622 // *1623 // * <p>For a list of all grandfathered tags, see the1624 // * IANA Language Subtag Registry (search for "Type: grandfathered").1625 // *1626 // * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code>1627 // * and <code>forLanguageTag</code> will round-trip.1628 // *1629 // * @param languageTag the language tag1630 // * @return The locale that best represents the language tag.1631 // * @throws NullPointerException if <code>languageTag</code> is <code>null</code>1632 // * @see #toLanguageTag()1633 // * @see java.util.Locale.Builder#setLanguageTag(string)1634 // */1635 // static Locale forLanguageTag(string languageTag) {1636 // LanguageTag tag = LanguageTag.parse(languageTag, null);1637 // InternalLocaleBuilder bldr = new InternalLocaleBuilder();1638 // bldr.setLanguageTag(tag);1639 // BaseLocale base = bldr.getBaseLocale();1640 // LocaleExtensions exts = bldr.getLocaleExtensions();1641 // if (exts is null && base.getVariant().length() > 0) {1642 // exts = getCompatibilityExtensions(base.getLanguage(), base.getScript(),1643 // base.getRegion(), base.getVariant());1644 // }1645 // return getInstance(base, exts);1646 // }1647 1648 // /**1649 // * Returns a three-letter abbreviation of this locale's language.1650 // * If the language matches an ISO 639-1 two-letter code, the1651 // * corresponding ISO 639-2/T three-letter lowercase code is1652 // * returned. The ISO 639-2 language codes can be found on-line,1653 // * see "Codes for the Representation of Names of Languages Part 2:1654 // * Alpha-3 Code". If the locale specifies a three-letter1655 // * language, the language is returned as is. If the locale does1656 // * not specify a language the empty string is returned.1657 // *1658 // * @return A three-letter abbreviation of this locale's language.1659 // * @exception MissingResourceException Throws MissingResourceException if1660 // * three-letter language abbreviation is not available for this locale.1661 // */1662 // string getISO3Language() throws MissingResourceException {1663 // string lang = language;1664 // if (lang.length() == 3) {1665 // return lang;1666 // }1667 1668 // string language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);1669 // if (language3 is null) {1670 // throw new MissingResourceException("Couldn't find 3-letter language code for "1671 // + lang, "FormatData_" ~ toString(), "ShortLanguage");1672 // }1673 // return language3;1674 // }1675 1676 // /**1677 // * Returns a three-letter abbreviation for this locale's country.1678 // * If the country matches an ISO 3166-1 alpha-2 code, the1679 // * corresponding ISO 3166-1 alpha-3 uppercase code is returned.1680 // * If the locale doesn't specify a country, this will be the empty1681 // * string.1682 // *1683 // * <p>The ISO 3166-1 codes can be found on-line.1684 // *1685 // * @return A three-letter abbreviation of this locale's country.1686 // * @exception MissingResourceException Throws MissingResourceException if the1687 // * three-letter country abbreviation is not available for this locale.1688 // */1689 // string getISO3Country() throws MissingResourceException {1690 // string country3 = getISO3Code(region, LocaleISOData.isoCountryTable);1691 // if (country3 is null) {1692 // throw new MissingResourceException("Couldn't find 3-letter country code for "1693 // + region, "FormatData_" ~ toString(), "ShortCountry");1694 // }1695 // return country3;1696 // }1697 1698 // private static string getISO3Code(string iso2Code, string table) {1699 // int codeLength = iso2Code.length();1700 // if (codeLength == 0) {1701 // return "";1702 // }1703 1704 // int tableLength = table.length();1705 // int index = tableLength;1706 // if (codeLength == 2) {1707 // char c1 = iso2Code[0];1708 // char c2 = iso2Code[1];1709 // for (index = 0; index < tableLength; index += 5) {1710 // if (table[index] == c11711 // && table[index + 1] == c2) {1712 // break;1713 // }1714 // }1715 // }1716 // return index < tableLength ? table.substring(index + 2, index + 5) : null;1717 // }1718 1719 // /**1720 // * Returns a name for the locale's language that is appropriate for display to the1721 // * user.1722 // * If possible, the name returned will be localized for the default1723 // * {@link LocaleCategory#DISPLAY DISPLAY} locale.1724 // * For example, if the locale is fr_FR and the default1725 // * {@link LocaleCategory#DISPLAY DISPLAY} locale1726 // * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and1727 // * the default {@link LocaleCategory#DISPLAY DISPLAY} locale is fr_FR,1728 // * getDisplayLanguage() will return "anglais".1729 // * If the name returned cannot be localized for the default1730 // * {@link LocaleCategory#DISPLAY DISPLAY} locale,1731 // * (say, we don't have a Japanese name for Croatian),1732 // * this function falls back on the English name, and uses the ISO code as a last-resort1733 // * value. If the locale doesn't specify a language, this function returns the empty string.1734 // *1735 // * @return The name of the display language.1736 // */1737 // final string getDisplayLanguage() {1738 // return getDisplayLanguage(getDefault(Category.DISPLAY));1739 // }1740 1741 // /**1742 // * Returns a name for the locale's language that is appropriate for display to the1743 // * user.1744 // * If possible, the name returned will be localized according to inLocale.1745 // * For example, if the locale is fr_FR and inLocale1746 // * is en_US, getDisplayLanguage() will return "French"; if the locale is en_US and1747 // * inLocale is fr_FR, getDisplayLanguage() will return "anglais".1748 // * If the name returned cannot be localized according to inLocale,1749 // * (say, we don't have a Japanese name for Croatian),1750 // * this function falls back on the English name, and finally1751 // * on the ISO code as a last-resort value. If the locale doesn't specify a language,1752 // * this function returns the empty string.1753 // *1754 // * @param inLocale The locale for which to retrieve the display language.1755 // * @return The name of the display language appropriate to the given locale.1756 // * @exception NullPointerException if <code>inLocale</code> is <code>null</code>1757 // */1758 // string getDisplayLanguage(Locale inLocale) {1759 // return getDisplaystring(language, null, inLocale, DISPLAY_LANGUAGE);1760 // }1761 1762 // /**1763 // * Returns a name for the locale's script that is appropriate for display to1764 // * the user. If possible, the name will be localized for the default1765 // * {@link LocaleCategory#DISPLAY DISPLAY} locale. Returns1766 // * the empty string if this locale doesn't specify a script code.1767 // *1768 // * @return the display name of the script code for the current default1769 // * {@link LocaleCategory#DISPLAY DISPLAY} locale1770 // */1771 // string getDisplayScript() {1772 // return getDisplayScript(getDefault(Category.DISPLAY));1773 // }1774 1775 // /**1776 // * Returns a name for the locale's script that is appropriate1777 // * for display to the user. If possible, the name will be1778 // * localized for the given locale. Returns the empty string if1779 // * this locale doesn't specify a script code.1780 // *1781 // * @param inLocale The locale for which to retrieve the display script.1782 // * @return the display name of the script code for the current default1783 // * {@link LocaleCategory#DISPLAY DISPLAY} locale1784 // * @throws NullPointerException if <code>inLocale</code> is <code>null</code>1785 // */1786 // string getDisplayScript(Locale inLocale) {1787 // return getDisplaystring(script, null, inLocale, DISPLAY_SCRIPT);1788 // }1789 1790 // /**1791 // * Returns a name for the locale's country that is appropriate for display to the1792 // * user.1793 // * If possible, the name returned will be localized for the default1794 // * {@link LocaleCategory#DISPLAY DISPLAY} locale.1795 // * For example, if the locale is fr_FR and the default1796 // * {@link LocaleCategory#DISPLAY DISPLAY} locale1797 // * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and1798 // * the default {@link LocaleCategory#DISPLAY DISPLAY} locale is fr_FR,1799 // * getDisplayCountry() will return "Etats-Unis".1800 // * If the name returned cannot be localized for the default1801 // * {@link LocaleCategory#DISPLAY DISPLAY} locale,1802 // * (say, we don't have a Japanese name for Croatia),1803 // * this function falls back on the English name, and uses the ISO code as a last-resort1804 // * value. If the locale doesn't specify a country, this function returns the empty string.1805 // *1806 // * @return The name of the country appropriate to the locale.1807 // */1808 // final string getDisplayCountry() {1809 // return getDisplayCountry(getDefault(Category.DISPLAY));1810 // }1811 1812 // /**1813 // * Returns a name for the locale's country that is appropriate for display to the1814 // * user.1815 // * If possible, the name returned will be localized according to inLocale.1816 // * For example, if the locale is fr_FR and inLocale1817 // * is en_US, getDisplayCountry() will return "France"; if the locale is en_US and1818 // * inLocale is fr_FR, getDisplayCountry() will return "Etats-Unis".1819 // * If the name returned cannot be localized according to inLocale.1820 // * (say, we don't have a Japanese name for Croatia),1821 // * this function falls back on the English name, and finally1822 // * on the ISO code as a last-resort value. If the locale doesn't specify a country,1823 // * this function returns the empty string.1824 // *1825 // * @param inLocale The locale for which to retrieve the display country.1826 // * @return The name of the country appropriate to the given locale.1827 // * @exception NullPointerException if <code>inLocale</code> is <code>null</code>1828 // */1829 // string getDisplayCountry(Locale inLocale) {1830 // return getDisplaystring(region, null, inLocale, DISPLAY_COUNTRY);1831 // }1832 1833 // private string getDisplaystring(string code, string cat, Locale inLocale, int type) {1834 // assert(inLocale);1835 // assert(code);1836 1837 // if (code.isEmpty()) {1838 // return "";1839 // }1840 1841 // LocaleServiceProviderPool pool =1842 // LocaleServiceProviderPool.getPool(LocaleNameProvider.class);1843 // string rbKey = (type == DISPLAY_VARIANT ? "%%"+code : code);1844 // string result = pool.getLocalizedObject(1845 // LocaleNameGetter.INSTANCE,1846 // inLocale, rbKey, type, code, cat);1847 // return result !is null ? result : code;1848 // }1849 1850 // /**1851 // * Returns a name for the locale's variant code that is appropriate for display to the1852 // * user. If possible, the name will be localized for the default1853 // * {@link LocaleCategory#DISPLAY DISPLAY} locale. If the locale1854 // * doesn't specify a variant code, this function returns the empty string.1855 // *1856 // * @return The name of the display variant code appropriate to the locale.1857 // */1858 // final string getDisplayVariant() {1859 // return getDisplayVariant(getDefault(Category.DISPLAY));1860 // }1861 1862 // /**1863 // * Returns a name for the locale's variant code that is appropriate for display to the1864 // * user. If possible, the name will be localized for inLocale. If the locale1865 // * doesn't specify a variant code, this function returns the empty string.1866 // *1867 // * @param inLocale The locale for which to retrieve the display variant code.1868 // * @return The name of the display variant code appropriate to the given locale.1869 // * @exception NullPointerException if <code>inLocale</code> is <code>null</code>1870 // */1871 // string getDisplayVariant(Locale inLocale) {1872 // if (variant.length() == 0)1873 // return "";1874 1875 // LocaleResources lr = LocaleProviderAdapter1876 // .getResourceBundleBased()1877 // .getLocaleResources(inLocale);1878 1879 // string names[] = getDisplayVariantArray(inLocale);1880 1881 // // Get the localized patterns for formatting a list, and use1882 // // them to format the list.1883 // return formatList(names,1884 // lr.getLocaleName("ListCompositionPattern"));1885 // }1886 1887 // /**1888 // * Returns a name for the locale that is appropriate for display to the1889 // * user. This will be the values returned by getDisplayLanguage(),1890 // * getDisplayScript(), getDisplayCountry(), getDisplayVariant() and1891 // * optional <a href="./Locale.html#def_locale_extension">Unicode extensions</a>1892 // * assembled into a single string. The non-empty values are used in order, with1893 // * the second and subsequent names in parentheses. For example:1894 // * <blockquote>1895 // * language (script, country, variant(, extension)*)<br>1896 // * language (country(, extension)*)<br>1897 // * language (variant(, extension)*)<br>1898 // * script (country(, extension)*)<br>1899 // * country (extension)*<br>1900 // * </blockquote>1901 // * depending on which fields are specified in the locale. The field1902 // * separator in the above parentheses, denoted as a comma character, may1903 // * be localized depending on the locale. If the language, script, country,1904 // * and variant fields are all empty, this function returns the empty string.1905 // *1906 // * @return The name of the locale appropriate to display.1907 // */1908 // final string getDisplayName() {1909 // return getDisplayName(getDefault(Category.DISPLAY));1910 // }1911 1912 // /**1913 // * Returns a name for the locale that is appropriate for display1914 // * to the user. This will be the values returned by1915 // * getDisplayLanguage(), getDisplayScript(),getDisplayCountry()1916 // * getDisplayVariant(), and optional <a href="./Locale.html#def_locale_extension">1917 // * Unicode extensions</a> assembled into a single string. The non-empty1918 // * values are used in order, with the second and subsequent names in1919 // * parentheses. For example:1920 // * <blockquote>1921 // * language (script, country, variant(, extension)*)<br>1922 // * language (country(, extension)*)<br>1923 // * language (variant(, extension)*)<br>1924 // * script (country(, extension)*)<br>1925 // * country (extension)*<br>1926 // * </blockquote>1927 // * depending on which fields are specified in the locale. The field1928 // * separator in the above parentheses, denoted as a comma character, may1929 // * be localized depending on the locale. If the language, script, country,1930 // * and variant fields are all empty, this function returns the empty string.1931 // *1932 // * @param inLocale The locale for which to retrieve the display name.1933 // * @return The name of the locale appropriate to display.1934 // * @throws NullPointerException if <code>inLocale</code> is <code>null</code>1935 // */1936 // string getDisplayName(Locale inLocale) {1937 // LocaleResources lr = LocaleProviderAdapter1938 // .getResourceBundleBased()1939 // .getLocaleResources(inLocale);1940 1941 // string languageName = getDisplayLanguage(inLocale);1942 // string scriptName = getDisplayScript(inLocale);1943 // string countryName = getDisplayCountry(inLocale);1944 // string[] variantNames = getDisplayVariantArray(inLocale);1945 1946 // // Get the localized patterns for formatting a display name.1947 // string displayNamePattern = lr.getLocaleName("DisplayNamePattern");1948 // string listCompositionPattern = lr.getLocaleName("ListCompositionPattern");1949 1950 // // The display name consists of a main name, followed by qualifiers.1951 // // Typically, the format is "MainName (Qualifier, Qualifier)" but this1952 // // depends on what pattern is stored in the display locale.1953 // string mainName = null;1954 // string[] qualifierNames = null;1955 1956 // // The main name is the language, or if there is no language, the script,1957 // // then if no script, the country. If there is no language/script/country1958 // // (an anomalous situation) then the display name is simply the variant's1959 // // display name.1960 // if (languageName.length() == 0 && scriptName.length() == 0 && countryName.length() == 0) {1961 // if (variantNames.length == 0) {1962 // return "";1963 // } else {1964 // return formatList(variantNames, listCompositionPattern);1965 // }1966 // }1967 // ArrayList<string> names = new ArrayList<>(4);1968 // if (languageName.length() != 0) {1969 // names.add(languageName);1970 // }1971 // if (scriptName.length() != 0) {1972 // names.add(scriptName);1973 // }1974 // if (countryName.length() != 0) {1975 // names.add(countryName);1976 // }1977 // if (variantNames.length != 0) {1978 // names.addAll(Arrays.asList(variantNames));1979 // }1980 1981 // // add Unicode extensions1982 // if (localeExtensions !is null) {1983 // localeExtensions.getUnicodeLocaleAttributes().stream()1984 // .map(key -> getDisplaystring(key, null, inLocale, DISPLAY_UEXT_KEY))1985 // .forEach(names::add);1986 // localeExtensions.getUnicodeLocaleKeys().stream()1987 // .map(key -> getDisplayKeyTypeExtensionstring(key, lr, inLocale))1988 // .forEach(names::add);1989 // }1990 1991 // // The first one in the main name1992 // mainName = names.get(0);1993 1994 // // Others are qualifiers1995 // int numNames = names.size();1996 // qualifierNames = (numNames > 1) ?1997 // names.subList(1, numNames).toArray(new string[numNames - 1]) : new string[0];1998 1999 // // Create an array whose first element is the number of remaining2000 // // elements. This serves as a selector into a ChoiceFormat pattern from2001 // // the resource. The second and third elements are the main name and2002 // // the qualifier; if there are no qualifiers, the third element is2003 // // unused by the format pattern.2004 // Object[] displayNames = {2005 // qualifierNames.length != 0 ? 2 : 1,2006 // mainName,2007 // // We could also just call formatList() and have it handle the empty2008 // // list case, but this is more efficient, and we want it to be2009 // // efficient since all the language-only locales will not have any2010 // // qualifiers.2011 // qualifierNames.length != 0 ? formatList(qualifierNames, listCompositionPattern) : null2012 // };2013 2014 // if (displayNamePattern !is null) {2015 // return new MessageFormat(displayNamePattern).format(displayNames);2016 // }2017 // else {2018 // // If we cannot get the message format pattern, then we use a simple2019 // // hard-coded pattern. This should not occur in practice unless the2020 // // installation is missing some core files (FormatData etc.).2021 // StringBuilder result = new StringBuilder();2022 // result.append((string)displayNames[1]);2023 // if (displayNames.length > 2) {2024 // result.append(" (");2025 // result.append((string)displayNames[2]);2026 // result.append(')');2027 // }2028 // return result.toString();2029 // }2030 // }2031 2032 // /**2033 // * Overrides Cloneable.2034 // */2035 // override2036 // Object clone()2037 // {2038 // try {2039 // Locale that = (Locale)super.clone();2040 // return that;2041 // } catch (CloneNotSupportedException e) {2042 // throw new InternalError(e);2043 // }2044 // }2045 2046 // /**2047 // * Override hashCode.2048 // * Since Locales are often used in hashtables, caches the value2049 // * for speed.2050 // */2051 // override2052 // int hashCode() {2053 // int hc = hashCodeValue;2054 // if (hc == 0) {2055 // hc = baseLocale.hashCode();2056 // if (localeExtensions !is null) {2057 // hc ^= localeExtensions.hashCode();2058 // }2059 // hashCodeValue = hc;2060 // }2061 // return hc;2062 // }2063 2064 // // Overrides2065 2066 // /**2067 // * Returns true if this Locale is equal to another object. A Locale is2068 // * deemed equal to another Locale with identical language, script, country,2069 // * variant and extensions, and unequal to all other objects.2070 // *2071 // * @return true if this Locale is equal to the specified object.2072 // */2073 // override2074 // bool equals(Object obj) {2075 // if (this is obj) // quick check2076 // return true;2077 // if (!(obj instanceof Locale))2078 // return false;2079 // BaseLocale otherBase = ((Locale)obj).baseLocale;2080 // if (!baseLocale.equals(otherBase)) {2081 // return false;2082 // }2083 // if (localeExtensions is null) {2084 // return ((Locale)obj).localeExtensions is null;2085 // }2086 // return localeExtensions.equals(((Locale)obj).localeExtensions);2087 // }2088 2089 // // ================= privates =====================================2090 2091 // private BaseLocale baseLocale;2092 // private LocaleExtensions localeExtensions;2093 2094 /**
2095 * Calculated hashcode
2096 */2097 privateinthashCodeValue;
2098 2099 // private __gshared Locale _defaultLocale;2100 private__gsharedLocaledefaultDisplayLocale;
2101 private__gsharedLocaledefaultFormatLocale;
2102 2103 privatestringlanguageTag;
2104 2105 // /**2106 // * Return an array of the display names of the variant.2107 // * @param bundle the ResourceBundle to use to get the display names2108 // * @return an array of display names, possible of zero length.2109 // */2110 // private string[] getDisplayVariantArray(Locale inLocale) {2111 // // Split the variant name into tokens separated by '_'.2112 // stringTokenizer tokenizer = new stringTokenizer(variant, "_");2113 // string[] names = new string[tokenizer.countTokens()];2114 2115 // // For each variant token, lookup the display name. If2116 // // not found, use the variant name itself.2117 // for (int i=0; i<names.length; ++i) {2118 // names[i] = getDisplaystring(tokenizer.nextToken(), null,2119 // inLocale, DISPLAY_VARIANT);2120 // }2121 2122 // return names;2123 // }2124 2125 // private string getDisplayKeyTypeExtensionstring(string key, LocaleResources lr, Locale inLocale) {2126 // string type = localeExtensions.getUnicodeLocaleType(key);2127 // string ret = getDisplaystring(type, key, inLocale, DISPLAY_UEXT_TYPE);2128 2129 // if (ret is null || ret.equals(type)) {2130 // // no localization for this type. try combining key/type separately2131 // string displayType = type;2132 // switch (key) {2133 // case "cu":2134 // displayType = lr.getCurrencyName(type.toLowerCase(Locale.ROOT));2135 // break;2136 // case "rg":2137 // if (type !is null &&2138 // // UN M.49 code should not be allowed here2139 // type.matches("^[a-zA-Z]{2}[zZ]{4}$")) {2140 // displayType = lr.getLocaleName(type.substring(0, 2).toUpperCase(Locale.ROOT));2141 // }2142 // break;2143 // case "tz":2144 // displayType = TimeZoneNameUtility.convertLDMLShortID(type)2145 // .map(id -> TimeZoneNameUtility.retrieveGenericDisplayName(id, TimeZone.LONG, inLocale))2146 // .orElse(type);2147 // break;2148 // }2149 // ret = MessageFormat.format(lr.getLocaleName("ListKeyTypePattern"),2150 // getDisplaystring(key, null, inLocale, DISPLAY_UEXT_KEY),2151 // Optional.ofNullable(displayType).orElse(type));2152 // }2153 2154 // return ret;2155 // }2156 2157 // /**2158 // * Format a list using given pattern strings.2159 // * If either of the patterns is null, then a the list is2160 // * formatted by concatenation with the delimiter ','.2161 // * @param stringList the list of strings to be formatted.2162 // * and formatting them into a list.2163 // * @param pattern should take 2 arguments for reduction2164 // * @return a string representing the list.2165 // */2166 // private static string formatList(string[] stringList, string pattern) {2167 // // If we have no list patterns, compose the list in a simple,2168 // // non-localized way.2169 // if (pattern is null) {2170 // return Arrays.stream(stringList).collect(Collectors.joining(","));2171 // }2172 2173 // switch (stringList.length) {2174 // case 0:2175 // return "";2176 // case 1:2177 // return stringList[0];2178 // default:2179 // return Arrays.stream(stringList).reduce("",2180 // (s1, s2) -> {2181 // if (s1.equals("")) {2182 // return s2;2183 // }2184 // if (s2.equals("")) {2185 // return s1;2186 // }2187 // return MessageFormat.format(pattern, s1, s2);2188 // });2189 // }2190 // }2191 2192 // // Duplicate of sun.util.locale.UnicodeLocaleExtension.isKey in order to2193 // // avoid its class loading.2194 // private static bool isUnicodeExtensionKey(string s) {2195 // // 2alphanum2196 // return (s.length() == 2) && LocaleUtils.isAlphaNumericstring(s);2197 // }2198 2199 // /**2200 // * @serialField language string2201 // * language subtag in lower case.2202 // * (See <a href="java.base/java/util/Locale.html#getLanguage()">getLanguage()</a>)2203 // * @serialField country string2204 // * country subtag in upper case.2205 // * (See <a href="java.base/java/util/Locale.html#getCountry()">getCountry()</a>)2206 // * @serialField variant string2207 // * variant subtags separated by LOWLINE characters.2208 // * (See <a href="java.base/java/util/Locale.html#getVariant()">getVariant()</a>)2209 // * @serialField hashcode int2210 // * deprecated, for forward compatibility only2211 // * @serialField script string2212 // * script subtag in title case2213 // * (See <a href="java.base/java/util/Locale.html#getScript()">getScript()</a>)2214 // * @serialField extensions string2215 // * canonical representation of extensions, that is,2216 // * BCP47 extensions in alphabetical order followed by2217 // * BCP47 private use subtags, all in lower case letters2218 // * separated by HYPHEN-MINUS characters.2219 // * (See <a href="java.base/java/util/Locale.html#getExtensionKeys()">getExtensionKeys()</a>,2220 // * <a href="java.base/java/util/Locale.html#getExtension(char)">getExtension(char)</a>)2221 // */2222 // private static final ObjectStreamField[] serialPersistentFields = {2223 // new ObjectStreamField("language", string.class),2224 // new ObjectStreamField("country", string.class),2225 // new ObjectStreamField("variant", string.class),2226 // new ObjectStreamField("hashcode", int.class),2227 // new ObjectStreamField("script", string.class),2228 // new ObjectStreamField("extensions", string.class),2229 // };2230 2231 // /**2232 // * Serializes this <code>Locale</code> to the specified <code>ObjectOutputStream</code>.2233 // * @param out the <code>ObjectOutputStream</code> to write2234 // * @throws IOException2235 // */2236 // private void writeObject(ObjectOutputStream out) throws IOException {2237 // ObjectOutputStream.PutField fields = out.putFields();2238 // fields.put("language", language);2239 // fields.put("script", script);2240 // fields.put("country", region);2241 // fields.put("variant", variant);2242 // fields.put("extensions", localeExtensions is null ? "" : localeExtensions.getID());2243 // fields.put("hashcode", -1); // place holder just for backward support2244 // out.writeFields();2245 // }2246 2247 // /**2248 // * Deserializes this <code>Locale</code>.2249 // * @param in the <code>ObjectInputStream</code> to read2250 // * @throws IOException2251 // * @throws ClassNotFoundException2252 // * @throws IllformedLocaleException2253 // */2254 // private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {2255 // ObjectInputStream.GetField fields = in.readFields();2256 // string language = (string)fields.get("language", "");2257 // string script = (string)fields.get("script", "");2258 // string country = (string)fields.get("country", "");2259 // string variant = (string)fields.get("variant", "");2260 // string extStr = (string)fields.get("extensions", "");2261 // baseLocale = BaseLocale.getInstance(convertOldISOCodes(language), script, country, variant);2262 // if (extStr.length() > 0) {2263 // try {2264 // InternalLocaleBuilder bldr = new InternalLocaleBuilder();2265 // bldr.setExtensions(extStr);2266 // localeExtensions = bldr.getLocaleExtensions();2267 // } catch (LocaleSyntaxException e) {2268 // throw new IllformedLocaleException(e.getMessage());2269 // }2270 // } else {2271 // localeExtensions = null;2272 // }2273 // }2274 2275 // /**2276 // * Returns a cached <code>Locale</code> instance equivalent to2277 // * the deserialized <code>Locale</code>. When serialized2278 // * language, country and variant fields read from the object data stream2279 // * are exactly "ja", "JP", "JP" or "th", "TH", "TH" and script/extensions2280 // * fields are empty, this method supplies <code>UNICODE_LOCALE_EXTENSION</code>2281 // * "ca"/"japanese" (calendar type is "japanese") or "nu"/"thai" (number script2282 // * type is "thai"). See <a href="Locale.html#special_cases_constructor">Special Cases</a>2283 // * for more information.2284 // *2285 // * @return an instance of <code>Locale</code> equivalent to2286 // * the deserialized <code>Locale</code>.2287 // * @throws java.io.ObjectStreamException2288 // */2289 // private Object readResolve() throws java.io.ObjectStreamException {2290 // return getInstance(language, script,2291 // region, variant, localeExtensions);2292 // }2293 2294 // private static string[] isoLanguages;2295 2296 // private static string[] isoCountries;2297 2298 privatestaticstringconvertOldISOCodes(stringlanguage) {
2299 // we accept both the old and the new ISO codes for the languages whose ISO2300 // codes have changed, but we always store the OLD code, for backward compatibility2301 language = language.toLower();
2302 if (language == "he") {
2303 return"iw";
2304 } elseif (language == "yi") {
2305 return"ji";
2306 } elseif (language == "id") {
2307 return"in";
2308 } else {
2309 returnlanguage;
2310 }
2311 }
2312 2313 // private static LocaleExtensions getCompatibilityExtensions(string language,2314 // string script,2315 // string country,2316 // string variant) {2317 // LocaleExtensions extensions = null;2318 // // Special cases for backward compatibility support2319 // if (LocaleUtils.caseIgnoreMatch(language, "ja")2320 // && script.length() == 02321 // && LocaleUtils.caseIgnoreMatch(country, "jp")2322 // && "JP".equals(variant)) {2323 // // ja_JP_JP -> u-ca-japanese (calendar = japanese)2324 // extensions = LocaleExtensions.CALENDAR_JAPANESE;2325 // } else if (LocaleUtils.caseIgnoreMatch(language, "th")2326 // && script.length() == 02327 // && LocaleUtils.caseIgnoreMatch(country, "th")2328 // && "TH".equals(variant)) {2329 // // th_TH_TH -> u-nu-thai (numbersystem = thai)2330 // extensions = LocaleExtensions.NUMBER_THAI;2331 // }2332 // return extensions;2333 // }2334 2335 // /**2336 // * Obtains a localized locale names from a LocaleNameProvider2337 // * implementation.2338 // */2339 // private static class LocaleNameGetter2340 // implements LocaleServiceProviderPool.LocalizedObjectGetter<LocaleNameProvider, string> {2341 // private static final LocaleNameGetter INSTANCE = new LocaleNameGetter();2342 2343 // override2344 // string getObject(LocaleNameProvider localeNameProvider,2345 // Locale locale,2346 // string key,2347 // Object... params) {2348 // assert params.length == 3;2349 // int type = (Integer)params[0];2350 // string code = (string)params[1];2351 // string cat = (string)params[2];2352 2353 // switch(type) {2354 // case DISPLAY_LANGUAGE:2355 // return localeNameProvider.getDisplayLanguage(code, locale);2356 // case DISPLAY_COUNTRY:2357 // return localeNameProvider.getDisplayCountry(code, locale);2358 // case DISPLAY_VARIANT:2359 // return localeNameProvider.getDisplayVariant(code, locale);2360 // case DISPLAY_SCRIPT:2361 // return localeNameProvider.getDisplayScript(code, locale);2362 // case DISPLAY_UEXT_KEY:2363 // return localeNameProvider.getDisplayUnicodeExtensionKey(code, locale);2364 // case DISPLAY_UEXT_TYPE:2365 // return localeNameProvider.getDisplayUnicodeExtensionType(code, cat, locale);2366 // default:2367 // assert false; // shouldn't happen2368 // }2369 2370 // return null;2371 // }2372 // }2373 2374 2375 // /**2376 // * <code>Builder</code> is used to build instances of <code>Locale</code>2377 // * from values configured by the setters. Unlike the <code>Locale</code>2378 // * constructors, the <code>Builder</code> checks if a value configured by a2379 // * setter satisfies the syntax requirements defined by the <code>Locale</code>2380 // * class. A <code>Locale</code> object created by a <code>Builder</code> is2381 // * well-formed and can be transformed to a well-formed IETF BCP 47 language tag2382 // * without losing information.2383 // *2384 // * <p><b>Note:</b> The <code>Locale</code> class does not provide any2385 // * syntactic restrictions on variant, while BCP 47 requires each variant2386 // * subtag to be 5 to 8 alphanumerics or a single numeric followed by 32387 // * alphanumerics. The method <code>setVariant</code> throws2388 // * <code>IllformedLocaleException</code> for a variant that does not satisfy2389 // * this restriction. If it is necessary to support such a variant, use a2390 // * Locale constructor. However, keep in mind that a <code>Locale</code>2391 // * object created this way might lose the variant information when2392 // * transformed to a BCP 47 language tag.2393 // *2394 // * <p>The following example shows how to create a <code>Locale</code> object2395 // * with the <code>Builder</code>.2396 // * <blockquote>2397 // * <pre>2398 // * Locale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();2399 // * </pre>2400 // * </blockquote>2401 // *2402 // * <p>Builders can be reused; <code>clear()</code> resets all2403 // * fields to their default values.2404 // *2405 // * @see Locale#forLanguageTag2406 // */2407 // static final class Builder {2408 // private final InternalLocaleBuilder localeBuilder;2409 2410 // /**2411 // * Constructs an empty Builder. The default value of all2412 // * fields, extensions, and private use information is the2413 // * empty string.2414 // */2415 // Builder() {2416 // localeBuilder = new InternalLocaleBuilder();2417 // }2418 2419 // /**2420 // * Resets the <code>Builder</code> to match the provided2421 // * <code>locale</code>. Existing state is discarded.2422 // *2423 // * <p>All fields of the locale must be well-formed, see {@link Locale}.2424 // *2425 // * <p>Locales with any ill-formed fields cause2426 // * <code>IllformedLocaleException</code> to be thrown, except for the2427 // * following three cases which are accepted for compatibility2428 // * reasons:<ul>2429 // * <li>Locale("ja", "JP", "JP") is treated as "ja-JP-u-ca-japanese"2430 // * <li>Locale("th", "TH", "TH") is treated as "th-TH-u-nu-thai"2431 // * <li>Locale("no", "NO", "NY") is treated as "nn-NO"</ul>2432 // *2433 // * @param locale the locale2434 // * @return This builder.2435 // * @throws IllformedLocaleException if <code>locale</code> has2436 // * any ill-formed fields.2437 // * @throws NullPointerException if <code>locale</code> is null.2438 // */2439 // Builder setLocale(Locale locale) {2440 // try {2441 // localeBuilder.setLocale(locale.baseLocale, locale.localeExtensions);2442 // } catch (LocaleSyntaxException e) {2443 // throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());2444 // }2445 // return this;2446 // }2447 2448 // /**2449 // * Resets the Builder to match the provided IETF BCP 472450 // * language tag. Discards the existing state. Null and the2451 // * empty string cause the builder to be reset, like {@link2452 // * #clear}. Grandfathered tags (see {@link2453 // * Locale#forLanguageTag}) are converted to their canonical2454 // * form before being processed. Otherwise, the language tag2455 // * must be well-formed (see {@link Locale}) or an exception is2456 // * thrown (unlike <code>Locale.forLanguageTag</code>, which2457 // * just discards ill-formed and following portions of the2458 // * tag).2459 // *2460 // * @param languageTag the language tag2461 // * @return This builder.2462 // * @throws IllformedLocaleException if <code>languageTag</code> is ill-formed2463 // * @see Locale#forLanguageTag(string)2464 // */2465 // Builder setLanguageTag(string languageTag) {2466 // ParseStatus sts = new ParseStatus();2467 // LanguageTag tag = LanguageTag.parse(languageTag, sts);2468 // if (sts.isError()) {2469 // throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex());2470 // }2471 // localeBuilder.setLanguageTag(tag);2472 // return this;2473 // }2474 2475 // /**2476 // * Sets the language. If <code>language</code> is the empty string or2477 // * null, the language in this <code>Builder</code> is removed. Otherwise,2478 // * the language must be <a href="./Locale.html#def_language">well-formed</a>2479 // * or an exception is thrown.2480 // *2481 // * <p>The typical language value is a two or three-letter language2482 // * code as defined in ISO639.2483 // *2484 // * @param language the language2485 // * @return This builder.2486 // * @throws IllformedLocaleException if <code>language</code> is ill-formed2487 // */2488 // Builder setLanguage(string language) {2489 // try {2490 // localeBuilder.setLanguage(language);2491 // } catch (LocaleSyntaxException e) {2492 // throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());2493 // }2494 // return this;2495 // }2496 2497 // /**2498 // * Sets the script. If <code>script</code> is null or the empty string,2499 // * the script in this <code>Builder</code> is removed.2500 // * Otherwise, the script must be <a href="./Locale.html#def_script">well-formed</a> or an2501 // * exception is thrown.2502 // *2503 // * <p>The typical script value is a four-letter script code as defined by ISO 15924.2504 // *2505 // * @param script the script2506 // * @return This builder.2507 // * @throws IllformedLocaleException if <code>script</code> is ill-formed2508 // */2509 // Builder setScript(string script) {2510 // try {2511 // localeBuilder.setScript(script);2512 // } catch (LocaleSyntaxException e) {2513 // throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());2514 // }2515 // return this;2516 // }2517 2518 // /**2519 // * Sets the region. If region is null or the empty string, the region2520 // * in this <code>Builder</code> is removed. Otherwise,2521 // * the region must be <a href="./Locale.html#def_region">well-formed</a> or an2522 // * exception is thrown.2523 // *2524 // * <p>The typical region value is a two-letter ISO 3166 code or a2525 // * three-digit UN M.49 area code.2526 // *2527 // * <p>The country value in the <code>Locale</code> created by the2528 // * <code>Builder</code> is always normalized to upper case.2529 // *2530 // * @param region the region2531 // * @return This builder.2532 // * @throws IllformedLocaleException if <code>region</code> is ill-formed2533 // */2534 // Builder setRegion(string region) {2535 // try {2536 // localeBuilder.setRegion(region);2537 // } catch (LocaleSyntaxException e) {2538 // throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());2539 // }2540 // return this;2541 // }2542 2543 // /**2544 // * Sets the variant. If variant is null or the empty string, the2545 // * variant in this <code>Builder</code> is removed. Otherwise, it2546 // * must consist of one or more <a href="./Locale.html#def_variant">well-formed</a>2547 // * subtags, or an exception is thrown.2548 // *2549 // * <p><b>Note:</b> This method checks if <code>variant</code>2550 // * satisfies the IETF BCP 47 variant subtag's syntax requirements,2551 // * and normalizes the value to lowercase letters. However,2552 // * the <code>Locale</code> class does not impose any syntactic2553 // * restriction on variant, and the variant value in2554 // * <code>Locale</code> is case sensitive. To set such a variant,2555 // * use a Locale constructor.2556 // *2557 // * @param variant the variant2558 // * @return This builder.2559 // * @throws IllformedLocaleException if <code>variant</code> is ill-formed2560 // */2561 // Builder setVariant(string variant) {2562 // try {2563 // localeBuilder.setVariant(variant);2564 // } catch (LocaleSyntaxException e) {2565 // throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());2566 // }2567 // return this;2568 // }2569 2570 // /**2571 // * Sets the extension for the given key. If the value is null or the2572 // * empty string, the extension is removed. Otherwise, the extension2573 // * must be <a href="./Locale.html#def_extensions">well-formed</a> or an exception2574 // * is thrown.2575 // *2576 // * <p><b>Note:</b> The key {@link Locale#UNICODE_LOCALE_EXTENSION2577 // * UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension.2578 // * Setting a value for this key replaces any existing Unicode locale key/type2579 // * pairs with those defined in the extension.2580 // *2581 // * <p><b>Note:</b> The key {@link Locale#PRIVATE_USE_EXTENSION2582 // * PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be2583 // * well-formed, the value for this key needs only to have subtags of one to2584 // * eight alphanumeric characters, not two to eight as in the general case.2585 // *2586 // * @param key the extension key2587 // * @param value the extension value2588 // * @return This builder.2589 // * @throws IllformedLocaleException if <code>key</code> is illegal2590 // * or <code>value</code> is ill-formed2591 // * @see #setUnicodeLocaleKeyword(string, string)2592 // */2593 // Builder setExtension(char key, string value) {2594 // try {2595 // localeBuilder.setExtension(key, value);2596 // } catch (LocaleSyntaxException e) {2597 // throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());2598 // }2599 // return this;2600 // }2601 2602 // /**2603 // * Sets the Unicode locale keyword type for the given key. If the type2604 // * is null, the Unicode keyword is removed. Otherwise, the key must be2605 // * non-null and both key and type must be <a2606 // * href="./Locale.html#def_locale_extension">well-formed</a> or an exception2607 // * is thrown.2608 // *2609 // * <p>Keys and types are converted to lower case.2610 // *2611 // * <p><b>Note</b>:Setting the 'u' extension via {@link #setExtension}2612 // * replaces all Unicode locale keywords with those defined in the2613 // * extension.2614 // *2615 // * @param key the Unicode locale key2616 // * @param type the Unicode locale type2617 // * @return This builder.2618 // * @throws IllformedLocaleException if <code>key</code> or <code>type</code>2619 // * is ill-formed2620 // * @throws NullPointerException if <code>key</code> is null2621 // * @see #setExtension(char, string)2622 // */2623 // Builder setUnicodeLocaleKeyword(string key, string type) {2624 // try {2625 // localeBuilder.setUnicodeLocaleKeyword(key, type);2626 // } catch (LocaleSyntaxException e) {2627 // throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());2628 // }2629 // return this;2630 // }2631 2632 // /**2633 // * Adds a unicode locale attribute, if not already present, otherwise2634 // * has no effect. The attribute must not be null and must be <a2635 // * href="./Locale.html#def_locale_extension">well-formed</a> or an exception2636 // * is thrown.2637 // *2638 // * @param attribute the attribute2639 // * @return This builder.2640 // * @throws NullPointerException if <code>attribute</code> is null2641 // * @throws IllformedLocaleException if <code>attribute</code> is ill-formed2642 // * @see #setExtension(char, string)2643 // */2644 // Builder addUnicodeLocaleAttribute(string attribute) {2645 // try {2646 // localeBuilder.addUnicodeLocaleAttribute(attribute);2647 // } catch (LocaleSyntaxException e) {2648 // throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());2649 // }2650 // return this;2651 // }2652 2653 // /**2654 // * Removes a unicode locale attribute, if present, otherwise has no2655 // * effect. The attribute must not be null and must be <a2656 // * href="./Locale.html#def_locale_extension">well-formed</a> or an exception2657 // * is thrown.2658 // *2659 // * <p>Attribute comparison for removal is case-insensitive.2660 // *2661 // * @param attribute the attribute2662 // * @return This builder.2663 // * @throws NullPointerException if <code>attribute</code> is null2664 // * @throws IllformedLocaleException if <code>attribute</code> is ill-formed2665 // * @see #setExtension(char, string)2666 // */2667 // Builder removeUnicodeLocaleAttribute(string attribute) {2668 // assert(attribute);2669 // try {2670 // localeBuilder.removeUnicodeLocaleAttribute(attribute);2671 // } catch (LocaleSyntaxException e) {2672 // throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());2673 // }2674 // return this;2675 // }2676 2677 // /**2678 // * Resets the builder to its initial, empty state.2679 // *2680 // * @return This builder.2681 // */2682 // Builder clear() {2683 // localeBuilder.clear();2684 // return this;2685 // }2686 2687 // /**2688 // * Resets the extensions to their initial, empty state.2689 // * Language, script, region and variant are unchanged.2690 // *2691 // * @return This builder.2692 // * @see #setExtension(char, string)2693 // */2694 // Builder clearExtensions() {2695 // localeBuilder.clearExtensions();2696 // return this;2697 // }2698 2699 // /**2700 // * Returns an instance of <code>Locale</code> created from the fields set2701 // * on this builder.2702 // *2703 // * <p>This applies the conversions listed in {@link Locale#forLanguageTag}2704 // * when constructing a Locale. (Grandfathered tags are handled in2705 // * {@link #setLanguageTag}.)2706 // *2707 // * @return A Locale.2708 // */2709 // Locale build() {2710 // BaseLocale baseloc = localeBuilder.getBaseLocale();2711 // LocaleExtensions extensions = localeBuilder.getLocaleExtensions();2712 // if (extensions is null && baseloc.getVariant().length() > 0) {2713 // extensions = getCompatibilityExtensions(baseloc.getLanguage(), baseloc.getScript(),2714 // baseloc.getRegion(), baseloc.getVariant());2715 // }2716 // return Locale.getInstance(baseloc, extensions);2717 // }2718 // }2719 2720 // /**2721 // * This enum provides constants to select a filtering mode for locale2722 // * matching. Refer to <a href="http://tools.ietf.org/html/rfc4647">RFC 46472723 // * Matching of Language Tags</a> for details.2724 // *2725 // * <p>As an example, think of two Language Priority Lists each of which2726 // * includes only one language range and a set of following language tags:2727 // *2728 // * <pre>2729 // * de (German)2730 // * de-DE (German, Germany)2731 // * de-Deva (German, in Devanagari script)2732 // * de-Deva-DE (German, in Devanagari script, Germany)2733 // * de-DE-1996 (German, Germany, orthography of 1996)2734 // * de-Latn-DE (German, in Latin script, Germany)2735 // * de-Latn-DE-1996 (German, in Latin script, Germany, orthography of 1996)2736 // * </pre>2737 // *2738 // * The filtering method will behave as follows:2739 // *2740 // * <table class="striped">2741 // * <caption>Filtering method behavior</caption>2742 // * <thead>2743 // * <tr>2744 // * <th scope="col">Filtering Mode</th>2745 // * <th scope="col">Language Priority List: {@code "de-DE"}</th>2746 // * <th scope="col">Language Priority List: {@code "de-*-DE"}</th>2747 // * </tr>2748 // * </thead>2749 // * <tbody>2750 // * <tr>2751 // * <th scope="row" style="vertical-align:top">2752 // * {@link FilteringMode#AUTOSELECT_FILTERING AUTOSELECT_FILTERING}2753 // * </th>2754 // * <td style="vertical-align:top">2755 // * Performs <em>basic</em> filtering and returns {@code "de-DE"} and2756 // * {@code "de-DE-1996"}.2757 // * </td>2758 // * <td style="vertical-align:top">2759 // * Performs <em>extended</em> filtering and returns {@code "de-DE"},2760 // * {@code "de-Deva-DE"}, {@code "de-DE-1996"}, {@code "de-Latn-DE"}, and2761 // * {@code "de-Latn-DE-1996"}.2762 // * </td>2763 // * </tr>2764 // * <tr>2765 // * <th scope="row" style="vertical-align:top">2766 // * {@link FilteringMode#EXTENDED_FILTERING EXTENDED_FILTERING}2767 // * </th>2768 // * <td style="vertical-align:top">2769 // * Performs <em>extended</em> filtering and returns {@code "de-DE"},2770 // * {@code "de-Deva-DE"}, {@code "de-DE-1996"}, {@code "de-Latn-DE"}, and2771 // * {@code "de-Latn-DE-1996"}.2772 // * </td>2773 // * <td style="vertical-align:top">Same as above.</td>2774 // * </tr>2775 // * <tr>2776 // * <th scope="row" style="vertical-align:top">2777 // * {@link FilteringMode#IGNORE_EXTENDED_RANGES IGNORE_EXTENDED_RANGES}2778 // * </th>2779 // * <td style="vertical-align:top">2780 // * Performs <em>basic</em> filtering and returns {@code "de-DE"} and2781 // * {@code "de-DE-1996"}.2782 // * </td>2783 // * <td style="vertical-align:top">2784 // * Performs <em>basic</em> filtering and returns {@code null} because2785 // * nothing matches.2786 // * </td>2787 // * </tr>2788 // * <tr>2789 // * <th scope="row" style="vertical-align:top">2790 // * {@link FilteringMode#MAP_EXTENDED_RANGES MAP_EXTENDED_RANGES}2791 // * </th>2792 // * <td style="vertical-align:top">Same as above.</td>2793 // * <td style="vertical-align:top">2794 // * Performs <em>basic</em> filtering and returns {@code "de-DE"} and2795 // * {@code "de-DE-1996"} because {@code "de-*-DE"} is mapped to2796 // * {@code "de-DE"}.2797 // * </td>2798 // * </tr>2799 // * <tr>2800 // * <th scope="row" style="vertical-align:top">2801 // * {@link FilteringMode#REJECT_EXTENDED_RANGES REJECT_EXTENDED_RANGES}2802 // * </th>2803 // * <td style="vertical-align:top">Same as above.</td>2804 // * <td style="vertical-align:top">2805 // * Throws {@link IllegalArgumentException} because {@code "de-*-DE"} is2806 // * not a valid basic language range.2807 // * </td>2808 // * </tr>2809 // * </tbody>2810 // * </table>2811 // *2812 // * @see #filter(List, Collection, FilteringMode)2813 // * @see #filterTags(List, Collection, FilteringMode)2814 // *2815 // */2816 // static enum FilteringMode {2817 // /**2818 // * Specifies automatic filtering mode based on the given Language2819 // * Priority List consisting of language ranges. If all of the ranges2820 // * are basic, basic filtering is selected. Otherwise, extended2821 // * filtering is selected.2822 // */2823 // AUTOSELECT_FILTERING,2824 2825 // /**2826 // * Specifies extended filtering.2827 // */2828 // EXTENDED_FILTERING,2829 2830 // /**2831 // * Specifies basic filtering: Note that any extended language ranges2832 // * included in the given Language Priority List are ignored.2833 // */2834 // IGNORE_EXTENDED_RANGES,2835 2836 // /**2837 // * Specifies basic filtering: If any extended language ranges are2838 // * included in the given Language Priority List, they are mapped to the2839 // * basic language range. Specifically, a language range starting with a2840 // * subtag {@code "*"} is treated as a language range {@code "*"}. For2841 // * example, {@code "*-US"} is treated as {@code "*"}. If {@code "*"} is2842 // * not the first subtag, {@code "*"} and extra {@code "-"} are removed.2843 // * For example, {@code "ja-*-JP"} is mapped to {@code "ja-JP"}.2844 // */2845 // MAP_EXTENDED_RANGES,2846 2847 // /**2848 // * Specifies basic filtering: If any extended language ranges are2849 // * included in the given Language Priority List, the list is rejected2850 // * and the filtering method throws {@link IllegalArgumentException}.2851 // */2852 // REJECT_EXTENDED_RANGES2853 // };2854 2855 // /**2856 // * This class expresses a <em>Language Range</em> defined in2857 // * <a href="http://tools.ietf.org/html/rfc4647">RFC 4647 Matching of2858 // * Language Tags</a>. A language range is an identifier which is used to2859 // * select language tag(s) meeting specific requirements by using the2860 // * mechanisms described in <a href="Locale.html#LocaleMatching">Locale2861 // * Matching</a>. A list which represents a user's preferences and consists2862 // * of language ranges is called a <em>Language Priority List</em>.2863 // *2864 // * <p>There are two types of language ranges: basic and extended. In RFC2865 // * 4647, the syntax of language ranges is expressed in2866 // * <a href="http://tools.ietf.org/html/rfc4234">ABNF</a> as follows:2867 // * <blockquote>2868 // * <pre>2869 // * basic-language-range = (1*8ALPHA *("-" 1*8alphanum)) / "*"2870 // * extended-language-range = (1*8ALPHA / "*")2871 // * *("-" (1*8alphanum / "*"))2872 // * alphanum = ALPHA / DIGIT2873 // * </pre>2874 // * </blockquote>2875 // * For example, {@code "en"} (English), {@code "ja-JP"} (Japanese, Japan),2876 // * {@code "*"} (special language range which matches any language tag) are2877 // * basic language ranges, whereas {@code "*-CH"} (any languages,2878 // * Switzerland), {@code "es-*"} (Spanish, any regions), and2879 // * {@code "zh-Hant-*"} (Traditional Chinese, any regions) are extended2880 // * language ranges.2881 // *2882 // * @see #filter2883 // * @see #filterTags2884 // * @see #lookup2885 // * @see #lookupTag2886 // *2887 // */2888 // static final class LanguageRange {2889 2890 // /**2891 // * A constant holding the maximum value of weight, 1.0, which indicates2892 // * that the language range is a good fit for the user.2893 // */2894 // static final double MAX_WEIGHT = 1.0;2895 2896 // /**2897 // * A constant holding the minimum value of weight, 0.0, which indicates2898 // * that the language range is not a good fit for the user.2899 // */2900 // static final double MIN_WEIGHT = 0.0;2901 2902 // private final string range;2903 // private final double weight;2904 2905 // private int hash;2906 2907 // /**2908 // * Constructs a {@code LanguageRange} using the given {@code range}.2909 // * Note that no validation is done against the IANA Language Subtag2910 // * Registry at time of construction.2911 // *2912 // * <p>This is equivalent to {@code LanguageRange(range, MAX_WEIGHT)}.2913 // *2914 // * @param range a language range2915 // * @throws NullPointerException if the given {@code range} is2916 // * {@code null}2917 // * @throws IllegalArgumentException if the given {@code range} does not2918 // * comply with the syntax of the language range mentioned in RFC 46472919 // */2920 // LanguageRange(string range) {2921 // this(range, MAX_WEIGHT);2922 // }2923 2924 // /**2925 // * Constructs a {@code LanguageRange} using the given {@code range} and2926 // * {@code weight}. Note that no validation is done against the IANA2927 // * Language Subtag Registry at time of construction.2928 // *2929 // * @param range a language range2930 // * @param weight a weight value between {@code MIN_WEIGHT} and2931 // * {@code MAX_WEIGHT}2932 // * @throws NullPointerException if the given {@code range} is2933 // * {@code null}2934 // * @throws IllegalArgumentException if the given {@code range} does not2935 // * comply with the syntax of the language range mentioned in RFC 46472936 // * or if the given {@code weight} is less than {@code MIN_WEIGHT}2937 // * or greater than {@code MAX_WEIGHT}2938 // */2939 // LanguageRange(string range, double weight) {2940 // if (range is null) {2941 // throw new NullPointerException();2942 // }2943 // if (weight < MIN_WEIGHT || weight > MAX_WEIGHT) {2944 // throw new IllegalArgumentException("weight=" ~ weight);2945 // }2946 2947 // range = range.toLowerCase(Locale.ROOT);2948 2949 // // Do syntax check.2950 // bool isIllFormed = false;2951 // string[] subtags = range.split("-");2952 // if (isSubtagIllFormed(subtags[0], true)2953 // || range.endsWith("-")) {2954 // isIllFormed = true;2955 // } else {2956 // for (int i = 1; i < subtags.length; i++) {2957 // if (isSubtagIllFormed(subtags[i], false)) {2958 // isIllFormed = true;2959 // break;2960 // }2961 // }2962 // }2963 // if (isIllFormed) {2964 // throw new IllegalArgumentException("range=" ~ range);2965 // }2966 2967 // this.range = range;2968 // this.weight = weight;2969 // }2970 2971 // private static bool isSubtagIllFormed(string subtag,2972 // bool isFirstSubtag) {2973 // if (subtag.equals("") || subtag.length() > 8) {2974 // return true;2975 // } else if (subtag.equals("*")) {2976 // return false;2977 // }2978 // char[] charArray = subtag.toCharArray();2979 // if (isFirstSubtag) { // ALPHA2980 // for (char c : charArray) {2981 // if (c < 'a' || c > 'z') {2982 // return true;2983 // }2984 // }2985 // } else { // ALPHA / DIGIT2986 // for (char c : charArray) {2987 // if (c < '0' || (c > '9' && c < 'a') || c > 'z') {2988 // return true;2989 // }2990 // }2991 // }2992 // return false;2993 // }2994 2995 // /**2996 // * Returns the language range of this {@code LanguageRange}.2997 // *2998 // * @return the language range.2999 // */3000 // string getRange() {3001 // return range;3002 // }3003 3004 // /**3005 // * Returns the weight of this {@code LanguageRange}.3006 // *3007 // * @return the weight value.3008 // */3009 // double getWeight() {3010 // return weight;3011 // }3012 3013 // /**3014 // * Parses the given {@code ranges} to generate a Language Priority List.3015 // *3016 // * <p>This method performs a syntactic check for each language range in3017 // * the given {@code ranges} but doesn't do validation using the IANA3018 // * Language Subtag Registry.3019 // *3020 // * <p>The {@code ranges} to be given can take one of the following3021 // * forms:3022 // *3023 // * <pre>3024 // * "Accept-Language: ja,en;q=0.4" (weighted list with Accept-Language prefix)3025 // * "ja,en;q=0.4" (weighted list)3026 // * "ja,en" (prioritized list)3027 // * </pre>3028 // *3029 // * In a weighted list, each language range is given a weight value.3030 // * The weight value is identical to the "quality value" in3031 // * <a href="http://tools.ietf.org/html/rfc2616">RFC 2616</a>, and it3032 // * expresses how much the user prefers the language. A weight value is3033 // * specified after a corresponding language range followed by3034 // * {@code ";q="}, and the default weight value is {@code MAX_WEIGHT}3035 // * when it is omitted.3036 // *3037 // * <p>Unlike a weighted list, language ranges in a prioritized list3038 // * are sorted in the descending order based on its priority. The first3039 // * language range has the highest priority and meets the user's3040 // * preference most.3041 // *3042 // * <p>In either case, language ranges are sorted in descending order in3043 // * the Language Priority List based on priority or weight. If a3044 // * language range appears in the given {@code ranges} more than once,3045 // * only the first one is included on the Language Priority List.3046 // *3047 // * <p>The returned list consists of language ranges from the given3048 // * {@code ranges} and their equivalents found in the IANA Language3049 // * Subtag Registry. For example, if the given {@code ranges} is3050 // * {@code "Accept-Language: iw,en-us;q=0.7,en;q=0.3"}, the elements in3051 // * the list to be returned are:3052 // *3053 // * <pre>3054 // * <b>Range</b> <b>Weight</b>3055 // * "iw" (older tag for Hebrew) 1.03056 // * "he" (new preferred code for Hebrew) 1.03057 // * "en-us" (English, United States) 0.73058 // * "en" (English) 0.33059 // * </pre>3060 // *3061 // * Two language ranges, {@code "iw"} and {@code "he"}, have the same3062 // * highest priority in the list. By adding {@code "he"} to the user's3063 // * Language Priority List, locale-matching method can find Hebrew as a3064 // * matching locale (or language tag) even if the application or system3065 // * offers only {@code "he"} as a supported locale (or language tag).3066 // *3067 // * @param ranges a list of comma-separated language ranges or a list of3068 // * language ranges in the form of the "Accept-Language" header3069 // * defined in <a href="http://tools.ietf.org/html/rfc2616">RFC3070 // * 2616</a>3071 // * @return a Language Priority List consisting of language ranges3072 // * included in the given {@code ranges} and their equivalent3073 // * language ranges if available. The list is modifiable.3074 // * @throws NullPointerException if {@code ranges} is null3075 // * @throws IllegalArgumentException if a language range or a weight3076 // * found in the given {@code ranges} is ill-formed3077 // */3078 // static List<LanguageRange> parse(string ranges) {3079 // return LocaleMatcher.parse(ranges);3080 // }3081 3082 // /**3083 // * Parses the given {@code ranges} to generate a Language Priority3084 // * List, and then customizes the list using the given {@code map}.3085 // * This method is equivalent to3086 // * {@code mapEquivalents(parse(ranges), map)}.3087 // *3088 // * @param ranges a list of comma-separated language ranges or a list3089 // * of language ranges in the form of the "Accept-Language" header3090 // * defined in <a href="http://tools.ietf.org/html/rfc2616">RFC3091 // * 2616</a>3092 // * @param map a map containing information to customize language ranges3093 // * @return a Language Priority List with customization. The list is3094 // * modifiable.3095 // * @throws NullPointerException if {@code ranges} is null3096 // * @throws IllegalArgumentException if a language range or a weight3097 // * found in the given {@code ranges} is ill-formed3098 // * @see #parse(string)3099 // * @see #mapEquivalents3100 // */3101 // static List<LanguageRange> parse(string ranges,3102 // Map<string, List<string>> map) {3103 // return mapEquivalents(parse(ranges), map);3104 // }3105 3106 // /**3107 // * Generates a new customized Language Priority List using the given3108 // * {@code priorityList} and {@code map}. If the given {@code map} is3109 // * empty, this method returns a copy of the given {@code priorityList}.3110 // *3111 // * <p>In the map, a key represents a language range whereas a value is3112 // * a list of equivalents of it. {@code '*'} cannot be used in the map.3113 // * Each equivalent language range has the same weight value as its3114 // * original language range.3115 // *3116 // * <pre>3117 // * An example of map:3118 // * <b>Key</b> <b>Value</b>3119 // * "zh" (Chinese) "zh",3120 // * "zh-Hans"(Simplified Chinese)3121 // * "zh-HK" (Chinese, Hong Kong) "zh-HK"3122 // * "zh-TW" (Chinese, Taiwan) "zh-TW"3123 // * </pre>3124 // *3125 // * The customization is performed after modification using the IANA3126 // * Language Subtag Registry.3127 // *3128 // * <p>For example, if a user's Language Priority List consists of five3129 // * language ranges ({@code "zh"}, {@code "zh-CN"}, {@code "en"},3130 // * {@code "zh-TW"}, and {@code "zh-HK"}), the newly generated Language3131 // * Priority List which is customized using the above map example will3132 // * consists of {@code "zh"}, {@code "zh-Hans"}, {@code "zh-CN"},3133 // * {@code "zh-Hans-CN"}, {@code "en"}, {@code "zh-TW"}, and3134 // * {@code "zh-HK"}.3135 // *3136 // * <p>{@code "zh-HK"} and {@code "zh-TW"} aren't converted to3137 // * {@code "zh-Hans-HK"} nor {@code "zh-Hans-TW"} even if they are3138 // * included in the Language Priority List. In this example, mapping3139 // * is used to clearly distinguish Simplified Chinese and Traditional3140 // * Chinese.3141 // *3142 // * <p>If the {@code "zh"}-to-{@code "zh"} mapping isn't included in the3143 // * map, a simple replacement will be performed and the customized list3144 // * won't include {@code "zh"} and {@code "zh-CN"}.3145 // *3146 // * @param priorityList user's Language Priority List3147 // * @param map a map containing information to customize language ranges3148 // * @return a new Language Priority List with customization. The list is3149 // * modifiable.3150 // * @throws NullPointerException if {@code priorityList} is {@code null}3151 // * @see #parse(string, Map)3152 // */3153 // static List<LanguageRange> mapEquivalents(3154 // List<LanguageRange>priorityList,3155 // Map<string, List<string>> map) {3156 // return LocaleMatcher.mapEquivalents(priorityList, map);3157 // }3158 3159 // /**3160 // * Returns a hash code value for the object.3161 // *3162 // * @return a hash code value for this object.3163 // */3164 // override3165 // int hashCode() {3166 // int h = hash;3167 // if (h == 0) {3168 // h = 17;3169 // h = 37*h + range.hashCode();3170 // long bitsWeight = Double.doubleToLongBits(weight);3171 // h = 37*h + (int)(bitsWeight ^ (bitsWeight >>> 32));3172 // if (h != 0) {3173 // hash = h;3174 // }3175 // }3176 // return h;3177 // }3178 3179 // /**3180 // * Compares this object to the specified object. The result is true if3181 // * and only if the argument is not {@code null} and is a3182 // * {@code LanguageRange} object that contains the same {@code range}3183 // * and {@code weight} values as this object.3184 // *3185 // * @param obj the object to compare with3186 // * @return {@code true} if this object's {@code range} and3187 // * {@code weight} are the same as the {@code obj}'s; {@code false}3188 // * otherwise.3189 // */3190 // override3191 // bool equals(Object obj) {3192 // if (this is obj) {3193 // return true;3194 // }3195 // if (!(obj instanceof LanguageRange)) {3196 // return false;3197 // }3198 // LanguageRange other = (LanguageRange)obj;3199 // return hash == other.hash3200 // && range.equals(other.range)3201 // && weight == other.weight;3202 // }3203 3204 // /**3205 // * Returns an informative string representation of this {@code LanguageRange}3206 // * object, consisting of language range and weight if the range is3207 // * weighted and the weight is less than the max weight.3208 // *3209 // * @return a string representation of this {@code LanguageRange} object.3210 // */3211 // override3212 // string toString() {3213 // return (weight == MAX_WEIGHT) ? range : range ~ ";q=" ~ weight;3214 // }3215 // }3216 3217 // /**3218 // * Returns a list of matching {@code Locale} instances using the filtering3219 // * mechanism defined in RFC 4647.3220 // *3221 // * This filter operation on the given {@code locales} ensures that only3222 // * unique matching locale(s) are returned.3223 // *3224 // * @param priorityList user's Language Priority List in which each language3225 // * tag is sorted in descending order based on priority or weight3226 // * @param locales {@code Locale} instances used for matching3227 // * @param mode filtering mode3228 // * @return a list of {@code Locale} instances for matching language tags3229 // * sorted in descending order based on priority or weight, or an empty3230 // * list if nothing matches. The list is modifiable.3231 // * @throws NullPointerException if {@code priorityList} or {@code locales}3232 // * is {@code null}3233 // * @throws IllegalArgumentException if one or more extended language ranges3234 // * are included in the given list when3235 // * {@link FilteringMode#REJECT_EXTENDED_RANGES} is specified3236 // *3237 // */3238 // static List<Locale> filter(List<LanguageRange> priorityList,3239 // Collection<Locale> locales,3240 // FilteringMode mode) {3241 // return LocaleMatcher.filter(priorityList, locales, mode);3242 // }3243 3244 // /**3245 // * Returns a list of matching {@code Locale} instances using the filtering3246 // * mechanism defined in RFC 4647. This is equivalent to3247 // * {@link #filter(List, Collection, FilteringMode)} when {@code mode} is3248 // * {@link FilteringMode#AUTOSELECT_FILTERING}.3249 // *3250 // * This filter operation on the given {@code locales} ensures that only3251 // * unique matching locale(s) are returned.3252 // *3253 // * @param priorityList user's Language Priority List in which each language3254 // * tag is sorted in descending order based on priority or weight3255 // * @param locales {@code Locale} instances used for matching3256 // * @return a list of {@code Locale} instances for matching language tags3257 // * sorted in descending order based on priority or weight, or an empty3258 // * list if nothing matches. The list is modifiable.3259 // * @throws NullPointerException if {@code priorityList} or {@code locales}3260 // * is {@code null}3261 // *3262 // */3263 // static List<Locale> filter(List<LanguageRange> priorityList,3264 // Collection<Locale> locales) {3265 // return filter(priorityList, locales, FilteringMode.AUTOSELECT_FILTERING);3266 // }3267 3268 // /**3269 // * Returns a list of matching languages tags using the basic filtering3270 // * mechanism defined in RFC 4647.3271 // *3272 // * This filter operation on the given {@code tags} ensures that only3273 // * unique matching tag(s) are returned with preserved case. In case of3274 // * duplicate matching tags with the case difference, the first matching3275 // * tag with preserved case is returned.3276 // * For example, "de-ch" is returned out of the duplicate matching tags3277 // * "de-ch" and "de-CH", if "de-ch" is checked first for matching in the3278 // * given {@code tags}. Note that if the given {@code tags} is an unordered3279 // * {@code Collection}, the returned matching tag out of duplicate tags is3280 // * subject to change, depending on the implementation of the3281 // * {@code Collection}.3282 // *3283 // * @param priorityList user's Language Priority List in which each language3284 // * tag is sorted in descending order based on priority or weight3285 // * @param tags language tags3286 // * @param mode filtering mode3287 // * @return a list of matching language tags sorted in descending order3288 // * based on priority or weight, or an empty list if nothing matches.3289 // * The list is modifiable.3290 // * @throws NullPointerException if {@code priorityList} or {@code tags} is3291 // * {@code null}3292 // * @throws IllegalArgumentException if one or more extended language ranges3293 // * are included in the given list when3294 // * {@link FilteringMode#REJECT_EXTENDED_RANGES} is specified3295 // *3296 // */3297 // static List<string> filterTags(List<LanguageRange> priorityList,3298 // Collection<string> tags,3299 // FilteringMode mode) {3300 // return LocaleMatcher.filterTags(priorityList, tags, mode);3301 // }3302 3303 // /**3304 // * Returns a list of matching languages tags using the basic filtering3305 // * mechanism defined in RFC 4647. This is equivalent to3306 // * {@link #filterTags(List, Collection, FilteringMode)} when {@code mode}3307 // * is {@link FilteringMode#AUTOSELECT_FILTERING}.3308 // *3309 // * This filter operation on the given {@code tags} ensures that only3310 // * unique matching tag(s) are returned with preserved case. In case of3311 // * duplicate matching tags with the case difference, the first matching3312 // * tag with preserved case is returned.3313 // * For example, "de-ch" is returned out of the duplicate matching tags3314 // * "de-ch" and "de-CH", if "de-ch" is checked first for matching in the3315 // * given {@code tags}. Note that if the given {@code tags} is an unordered3316 // * {@code Collection}, the returned matching tag out of duplicate tags is3317 // * subject to change, depending on the implementation of the3318 // * {@code Collection}.3319 // *3320 // * @param priorityList user's Language Priority List in which each language3321 // * tag is sorted in descending order based on priority or weight3322 // * @param tags language tags3323 // * @return a list of matching language tags sorted in descending order3324 // * based on priority or weight, or an empty list if nothing matches.3325 // * The list is modifiable.3326 // * @throws NullPointerException if {@code priorityList} or {@code tags} is3327 // * {@code null}3328 // *3329 // */3330 // static List<string> filterTags(List<LanguageRange> priorityList,3331 // Collection<string> tags) {3332 // return filterTags(priorityList, tags, FilteringMode.AUTOSELECT_FILTERING);3333 // }3334 3335 // /**3336 // * Returns a {@code Locale} instance for the best-matching language3337 // * tag using the lookup mechanism defined in RFC 4647.3338 // *3339 // * @param priorityList user's Language Priority List in which each language3340 // * tag is sorted in descending order based on priority or weight3341 // * @param locales {@code Locale} instances used for matching3342 // * @return the best matching <code>Locale</code> instance chosen based on3343 // * priority or weight, or {@code null} if nothing matches.3344 // * @throws NullPointerException if {@code priorityList} or {@code tags} is3345 // * {@code null}3346 // *3347 // */3348 // static Locale lookup(List<LanguageRange> priorityList,3349 // Collection<Locale> locales) {3350 // return LocaleMatcher.lookup(priorityList, locales);3351 // }3352 3353 // /**3354 // * Returns the best-matching language tag using the lookup mechanism3355 // * defined in RFC 4647.3356 // *3357 // * This lookup operation on the given {@code tags} ensures that the3358 // * first matching tag with preserved case is returned.3359 // *3360 // * @param priorityList user's Language Priority List in which each language3361 // * tag is sorted in descending order based on priority or weight3362 // * @param tags language tangs used for matching3363 // * @return the best matching language tag chosen based on priority or3364 // * weight, or {@code null} if nothing matches.3365 // * @throws NullPointerException if {@code priorityList} or {@code tags} is3366 // * {@code null}3367 // *3368 // */3369 // static string lookupTag(List<LanguageRange> priorityList,3370 // Collection<string> tags) {3371 // return LocaleMatcher.lookupTag(priorityList, tags);3372 // }3373 3374 }
3375 3376 /**
3377 * Enum for locale categories. These locale categories are used to get/set
3378 * the default locale for the specific functionality represented by the
3379 * category.
3380 *
3381 * @see #getDefault(LocaleCategory)
3382 * @see #setDefault(LocaleCategory, Locale)
3383 */3384 structLocaleCategory {
3385 3386 /**
3387 * Category used to represent the default locale for
3388 * displaying user interfaces.
3389 */3390 enumLocaleCategoryDISPLAY = LocaleCategory("user.language.display",
3391 "user.script.display",
3392 "user.country.display",
3393 "user.variant.display",
3394 "user.extensions.display");
3395 3396 /**
3397 * Category used to represent the default locale for
3398 * formatting dates, numbers, and/or currencies.
3399 */3400 enumLocaleCategoryFORMAT = LocaleCategory("user.language.format",
3401 "user.script.format",
3402 "user.country.format",
3403 "user.variant.format",
3404 "user.extensions.format");
3405 3406 this(stringlanguageKey, stringscriptKey, stringcountryKey,
3407 stringvariantKey, stringextensionsKey) {
3408 this.languageKey = languageKey;
3409 this.scriptKey = scriptKey;
3410 this.countryKey = countryKey;
3411 this.variantKey = variantKey;
3412 this.extensionsKey = extensionsKey;
3413 }
3414 3415 stringlanguageKey;
3416 stringscriptKey;
3417 stringcountryKey;
3418 stringvariantKey;
3419 stringextensionsKey;
3420 3421 // bool opEquals(const LocaleCategory h) nothrow {3422 // return this.languageKey == h.languageKey && 3423 // // this.scriptKey == h.scriptKey &&3424 // this.countryKey == h.countryKey;3425 // }3426 3427 // bool opEquals(ref const LocaleCategory h) nothrow {3428 // return this.languageKey == h.languageKey && 3429 // // this.scriptKey == h.scriptKey &&3430 // this.countryKey == h.countryKey;3431 // }3432 }