12d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// © 2016 and later: Unicode, Inc. and others. 22d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert// License & terms of use: http://www.unicode.org/copyright.html#License 37935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/* 4f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert ****************************************************************************** 587255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * Copyright (C) 2003-2016, International Business Machines Corporation and 6f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * others. All Rights Reserved. 7f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert ****************************************************************************** 8f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert */ 97935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpackage com.ibm.icu.util; 117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.io.Serializable; 137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.lang.reflect.InvocationTargetException; 147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.lang.reflect.Method; 157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.security.AccessControlException; 167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.security.AccessController; 177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.security.PrivilegedAction; 187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.text.ParseException; 197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Iterator; 207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.List; 217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Locale; 227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Map; 237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Map.Entry; 247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.MissingResourceException; 257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.Set; 267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.TreeMap; 277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport java.util.TreeSet; 287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 292d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubertimport com.ibm.icu.impl.CacheBase; 302d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubertimport com.ibm.icu.impl.ICUData; 317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUResourceBundle; 327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.ICUResourceTableAccess; 337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.LocaleIDParser; 347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.LocaleIDs; 357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.LocaleUtility; 362d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubertimport com.ibm.icu.impl.SoftCache; 377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.locale.AsciiUtil; 387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.locale.BaseLocale; 397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.locale.Extension; 407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.locale.InternalLocaleBuilder; 417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.locale.KeyTypeData; 427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.locale.LanguageTag; 437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.locale.LocaleExtensions; 447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.locale.LocaleSyntaxException; 457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.locale.ParseStatus; 467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.impl.locale.UnicodeLocaleExtension; 477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.lang.UScript; 487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.LocaleDisplayNames; 497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertimport com.ibm.icu.text.LocaleDisplayNames.DialectHandling; 507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert/** 527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icuenhanced java.util.Locale}.{@icu _usage_} 537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A class analogous to {@link java.util.Locale} that provides additional 557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * support for ICU protocol. In ICU 3.0 this class is enhanced to support 567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * RFC 3066 language identifiers. 577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Many classes and services in ICU follow a factory idiom, in 597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * which a factory method or object responds to a client request with 607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * an object. The request includes a locale (the <i>requested</i> 617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale), and the returned object is constructed using data for that 627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale. The system may lack data for the requested locale, in 637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * which case the locale fallback mechanism will be invoked until a 647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * populated locale is found (the <i>valid</i> locale). Furthermore, 657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * even when a populated locale is found (the <i>valid</i> locale), 667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * further fallback may be required to reach a locale containing the 677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * specific data required by the service (the <i>actual</i> locale). 687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>ULocale performs <b>'normalization'</b> and <b>'canonicalization'</b> of locale ids. 707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Normalization 'cleans up' ICU locale ids as follows: 717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <ul> 727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>language, script, country, variant, and keywords are properly cased<br> 737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (lower, title, upper, upper, and lower case respectively)</li> 747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>hyphens used as separators are converted to underscores</li> 757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>three-letter language and country ids are converted to two-letter 767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * equivalents where available</li> 777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>surrounding spaces are removed from keywords and values</li> 787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>if there are multiple keywords, they are put in sorted order</li> 797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </ul> 807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Canonicalization additionally performs the following: 817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <ul> 827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>POSIX ids are converted to ICU format IDs</li> 837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>'grandfathered' 3066 ids are converted to ICU standard form</li> 847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>'PREEURO' and 'EURO' variants are converted to currency keyword form, 857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * with the currency 867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * id appropriate to the country of the locale (for PREEURO) or EUR (for EURO). 877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </ul> 887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * All ULocale constructors automatically normalize the locale id. To handle 897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * POSIX ids, <code>canonicalize</code> can be called to convert the id 907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * to canonical form, or the <code>canonicalInstance</code> factory method 919e281ba4837cba4a1cf9523d6f8b0621b150063dScott Russell * can be called. 927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 9387255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * <p>This class provides selectors {@link #VALID_LOCALE} and {@link 9487255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * #ACTUAL_LOCALE} intended for use in methods named 9587255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * <tt>getLocale()</tt>. These methods exist in several ICU classes, 9687255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * including {@link com.ibm.icu.util.Calendar}, {@link 9787255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * com.ibm.icu.util.Currency}, {@link com.ibm.icu.text.UFormat}, 9887255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * {@link com.ibm.icu.text.BreakIterator}, 9987255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * {@link com.ibm.icu.text.Collator}, 10087255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * {@link com.ibm.icu.text.DateFormatSymbols}, and {@link 10187255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * com.ibm.icu.text.DecimalFormatSymbols} and their subclasses, if 10287255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * any. Once an object of one of these classes has been created, 10387255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * <tt>getLocale()</tt> may be called on it to determine the valid and 10487255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * actual locale arrived at during the object's construction. 10587255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * 1067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Note: The <i>actual</i> locale is returned correctly, but the <i>valid</i> 1077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale is not, in most cases. 1087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 1097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see java.util.Locale 1107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author weiv 1117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author Alan Liu 1127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @author Ram Viswanadha 1137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 2.8 1147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11587255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert@SuppressWarnings("javadoc") // com.ibm.icu.text.Collator is in another project 1167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubertpublic final class ULocale implements Serializable, Comparable<ULocale> { 1177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // using serialver from jdk1.4.2_05 1187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final long serialVersionUID = 3715177670352309217L; 1197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1202d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert private static CacheBase<String, String, Void> nameCache = new SoftCache<String, String, Void>() { 1212d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 1222d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert protected String createInstance(String tmpLocaleID, Void unused) { 1232d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return new LocaleIDParser(tmpLocaleID).getName(); 1242d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 1252d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert }; 126f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 1277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for language. 1297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 1307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale ENGLISH = new ULocale("en", Locale.ENGLISH); 1327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for language. 1357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 1367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale FRENCH = new ULocale("fr", Locale.FRENCH); 1387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for language. 1417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 1427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale GERMAN = new ULocale("de", Locale.GERMAN); 1447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for language. 1477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 1487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale ITALIAN = new ULocale("it", Locale.ITALIAN); 1507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for language. 1537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 1547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale JAPANESE = new ULocale("ja", Locale.JAPANESE); 1567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for language. 1597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 1607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale KOREAN = new ULocale("ko", Locale.KOREAN); 1627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for language. 1657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 1667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale CHINESE = new ULocale("zh", Locale.CHINESE); 1687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 169f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 170f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // Special note about static initializer for 171f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // - SIMPLIFIED_CHINESE 172f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // - TRADTIONAL_CHINESE 173f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // - CHINA 174f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // - TAIWAN 175f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // 176f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // Equivalent JDK Locale for ULocale.SIMPLIFIED_CHINESE is different 177f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // by JRE version. JRE 7 or later supports a script tag "Hans", while 178f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // JRE 6 or older does not. JDK's Locale.SIMPLIFIED_CHINESE is actually 179f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // zh_CN, not zh_Hans. This is same in Java 7 or later versions. 180f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // 181f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // ULocale#toLocale() implementation uses Java reflection to create a Locale 182f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // with a script tag. When a new ULocale is constructed with the single arg 183f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // constructor, the volatile field 'Locale locale' is initialized by 184f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // #toLocale() method. 185f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // 186f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // Because we cannot hardcode corresponding JDK Locale representation below, 187f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // SIMPLIFIED_CHINESE is constructed without JDK Locale argument, and 188f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // #toLocale() is used for resolving the best matching JDK Locale at runtime. 189f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // 190f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // The same thing applies to TRADITIONAL_CHINESE. 191f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 1927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 1937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for language. 1947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 1957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 196f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert public static final ULocale SIMPLIFIED_CHINESE = new ULocale("zh_Hans"); 197f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 1987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 1997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for language. 2017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 203f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert public static final ULocale TRADITIONAL_CHINESE = new ULocale("zh_Hant"); 2047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale FRANCE = new ULocale("fr_FR", Locale.FRANCE); 2107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale GERMANY = new ULocale("de_DE", Locale.GERMANY); 2167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale ITALY = new ULocale("it_IT", Locale.ITALY); 2227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale JAPAN = new ULocale("ja_JP", Locale.JAPAN); 2287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale KOREA = new ULocale("ko_KR", Locale.KOREA); 2347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 239f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert public static final ULocale CHINA = new ULocale("zh_Hans_CN"); 2407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale PRC = CHINA; 2467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 251f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert public static final ULocale TAIWAN = new ULocale("zh_Hant_TW"); 2527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale UK = new ULocale("en_GB", Locale.UK); 2587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale US = new ULocale("en_US", Locale.US); 2647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale CANADA = new ULocale("en_CA", Locale.CANADA); 2707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Useful constant for country/region. 2737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 2747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale CANADA_FRENCH = new ULocale("fr_CA", Locale.CANADA_FRENCH); 2767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Handy constant. 2797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String EMPTY_STRING = ""; 2817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Used in both ULocale and LocaleIDParser, so moved up here. 2837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final char UNDERSCORE = '_'; 2847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // default empty locale 2867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final Locale EMPTY_LOCALE = new Locale("", ""); 2877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // special keyword key for Unicode locale attributes 2897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String LOCALE_ATTRIBUTE_KEY = "attribute"; 2907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The root ULocale. 2937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 2.8 2947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 2957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final ULocale ROOT = new ULocale("", EMPTY_LOCALE); 2967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Enum for locale categories. These locale categories are used to get/set the default locale for 2997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the specific functionality represented by the category. 3007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 49 3017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public enum Category { 3037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Category used to represent the default locale for displaying user interfaces. 3057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 49 3067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert DISPLAY, 3087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Category used to represent the default locale for formatting date, number and/or currency. 3107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 49 3117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert FORMAT 3137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3152d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert private static final SoftCache<Locale, ULocale, Void> CACHE = new SoftCache<Locale, ULocale, Void>() { 3162d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 3172d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert protected ULocale createInstance(Locale key, Void unused) { 3182d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return JDKLocaleHelper.toULocale(key); 3192d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 3202d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert }; 3217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Cache the locale. 3247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient volatile Locale locale; 3267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The raw localeID that we were passed in. 3297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private String localeID; 3317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Cache the locale data container fields. 3347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * In future, we want to use them as the primary locale identifier storage. 3357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient volatile BaseLocale baseLocale; 3377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private transient volatile LocaleExtensions extensions; 3387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String[][] CANONICALIZE_MAP; 3417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String[][] variantsToKeywords; 3427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 3437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static void initCANONICALIZE_MAP() { 3447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (CANONICALIZE_MAP == null) { 3457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 3467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This table lists pairs of locale ids for canonicalization. The 3477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The 1st item is the normalized id. The 2nd item is the 3487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * canonicalized id. The 3rd is the keyword. The 4th is the keyword value. 3497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 3507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[][] tempCANONICALIZE_MAP = { 351f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // { EMPTY_STRING, "en_US_POSIX", null, null }, /* .NET name */ 352f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "C", "en_US_POSIX", null, null }, /* POSIX name */ 353f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "art_LOJBAN", "jbo", null, null }, /* registered name */ 354f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "az_AZ_CYRL", "az_Cyrl_AZ", null, null }, /* .NET name */ 355f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "az_AZ_LATN", "az_Latn_AZ", null, null }, /* .NET name */ 356f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "ca_ES_PREEURO", "ca_ES", "currency", "ESP" }, 357f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "cel_GAULISH", "cel__GAULISH", null, null }, /* registered name */ 358f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "de_1901", "de__1901", null, null }, /* registered name */ 359f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "de_1906", "de__1906", null, null }, /* registered name */ 360f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "de__PHONEBOOK", "de", "collation", "phonebook" }, /* Old ICU name */ 361f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "de_AT_PREEURO", "de_AT", "currency", "ATS" }, 362f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "de_DE_PREEURO", "de_DE", "currency", "DEM" }, 363f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "de_LU_PREEURO", "de_LU", "currency", "EUR" }, 364f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "el_GR_PREEURO", "el_GR", "currency", "GRD" }, 365f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "en_BOONT", "en__BOONT", null, null }, /* registered name */ 366f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "en_SCOUSE", "en__SCOUSE", null, null }, /* registered name */ 367f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "en_BE_PREEURO", "en_BE", "currency", "BEF" }, 368f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "en_IE_PREEURO", "en_IE", "currency", "IEP" }, 369f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "es__TRADITIONAL", "es", "collation", "traditional" }, /* Old ICU name */ 370f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "es_ES_PREEURO", "es_ES", "currency", "ESP" }, 371f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "eu_ES_PREEURO", "eu_ES", "currency", "ESP" }, 372f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "fi_FI_PREEURO", "fi_FI", "currency", "FIM" }, 373f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "fr_BE_PREEURO", "fr_BE", "currency", "BEF" }, 374f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "fr_FR_PREEURO", "fr_FR", "currency", "FRF" }, 375f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "fr_LU_PREEURO", "fr_LU", "currency", "LUF" }, 376f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "ga_IE_PREEURO", "ga_IE", "currency", "IEP" }, 377f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "gl_ES_PREEURO", "gl_ES", "currency", "ESP" }, 378f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "hi__DIRECT", "hi", "collation", "direct" }, /* Old ICU name */ 379f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "it_IT_PREEURO", "it_IT", "currency", "ITL" }, 380f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "ja_JP_TRADITIONAL", "ja_JP", "calendar", "japanese" }, 381f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // { "nb_NO_NY", "nn_NO", null, null }, 382f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "nl_BE_PREEURO", "nl_BE", "currency", "BEF" }, 383f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "nl_NL_PREEURO", "nl_NL", "currency", "NLG" }, 384f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "pt_PT_PREEURO", "pt_PT", "currency", "PTE" }, 385f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "sl_ROZAJ", "sl__ROZAJ", null, null }, /* registered name */ 386f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "sr_SP_CYRL", "sr_Cyrl_RS", null, null }, /* .NET name */ 387f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "sr_SP_LATN", "sr_Latn_RS", null, null }, /* .NET name */ 388f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "sr_YU_CYRILLIC", "sr_Cyrl_RS", null, null }, /* Linux name */ 389f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "th_TH_TRADITIONAL", "th_TH", "calendar", "buddhist" }, /* Old ICU name */ 390f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "uz_UZ_CYRILLIC", "uz_Cyrl_UZ", null, null }, /* Linux name */ 391f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "uz_UZ_CYRL", "uz_Cyrl_UZ", null, null }, /* .NET name */ 392f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "uz_UZ_LATN", "uz_Latn_UZ", null, null }, /* .NET name */ 393f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "zh_CHS", "zh_Hans", null, null }, /* .NET name */ 394f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "zh_CHT", "zh_Hant", null, null }, /* .NET name */ 395f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "zh_GAN", "zh__GAN", null, null }, /* registered name */ 396f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "zh_GUOYU", "zh", null, null }, /* registered name */ 397f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "zh_HAKKA", "zh__HAKKA", null, null }, /* registered name */ 398f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "zh_MIN", "zh__MIN", null, null }, /* registered name */ 399f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "zh_MIN_NAN", "zh__MINNAN", null, null }, /* registered name */ 400f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "zh_WUU", "zh__WUU", null, null }, /* registered name */ 401f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "zh_XIANG", "zh__XIANG", null, null }, /* registered name */ 402f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert { "zh_YUE", "zh__YUE", null, null } /* registered name */ 4037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 4047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (ULocale.class) { 4067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (CANONICALIZE_MAP == null) { 4077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert CANONICALIZE_MAP = tempCANONICALIZE_MAP; 4087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (variantsToKeywords == null) { 4127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This table lists pairs of locale ids for canonicalization. The 4147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The first item is the normalized variant id. 4157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[][] tempVariantsToKeywords = { 4177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "EURO", "currency", "EUR" }, 4187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "PINYIN", "collation", "pinyin" }, /* Solaris variant */ 4197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "STROKE", "collation", "stroke" } /* Solaris variant */ 4207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 4217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (ULocale.class) { 4237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (variantsToKeywords == null) { 4247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert variantsToKeywords = tempVariantsToKeywords; 4257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Private constructor used by static initializers. 4327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private ULocale(String localeID, Locale locale) { 4347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.localeID = localeID; 4357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.locale = locale; 4367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Construct a ULocale object from a {@link java.util.Locale}. 4402a7db240a11150ab654325587d653754c62b71a7Yoshito Umaoka * @param loc a {@link java.util.Locale} 4417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private ULocale(Locale loc) { 4437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.localeID = getName(forLocale(loc).toString()); 4447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.locale = loc; 4457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a ULocale object for a {@link java.util.Locale}. 4497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The ULocale is canonicalized. 4502a7db240a11150ab654325587d653754c62b71a7Yoshito Umaoka * @param loc a {@link java.util.Locale} 4517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.2 4527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale forLocale(Locale loc) { 4547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (loc == null) { 4557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 4567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4572d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return CACHE.getInstance(loc, null /* unused */); 4587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Constructs a ULocale from a RFC 3066 locale ID. The locale ID consists 4627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * of optional language, script, country, and variant fields in that order, 4637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * separated by underscores, followed by an optional keyword list. The 4647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * script, if present, is four characters long-- this distinguishes it 4657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * from a country code, which is two characters long. Other fields 4667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * are distinguished by position as indicated by the underscores. The 4677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * start of the keyword list is indicated by '@', and consists of two 4687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or more keyword/value pairs separated by semicolons(';'). 4692d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 4707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>This constructor does not canonicalize the localeID. So, for 4717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * example, "zh__pinyin" remains unchanged instead of converting 4727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * to "zh@collation=pinyin". By default ICU only recognizes the 4737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * latter as specifying pinyin collation. Use {@link #createCanonical} 4747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or {@link #canonicalize} if you need to canonicalize the localeID. 4757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 4767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID string representation of the locale, e.g: 4777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "en_US", "sy_Cyrl_YU", "zh__pinyin", "es_ES@currency=EUR;collation=traditional" 4787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 2.8 4797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ULocale(String localeID) { 4817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this.localeID = getName(localeID); 4827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Convenience overload of ULocale(String, String, String) for 4867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * compatibility with java.util.Locale. 4877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #ULocale(String, String, String) 4887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.4 4897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 4907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ULocale(String a, String b) { 4917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert this(a, b, null); 4927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 4937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 4947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 4957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Constructs a ULocale from a localeID constructed from the three 'fields' a, b, and 4967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * c. These fields are concatenated using underscores to form a localeID of the form 4977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a_b_c, which is then handled like the localeID passed to <code>ULocale(String 4987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * localeID)</code>. 4997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 5007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Java locale strings consisting of language, country, and 5017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * variant will be handled by this form, since the country code 5027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (being shorter than four letters long) will not be interpreted 5037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * as a script code. If a script code is present, the final 5047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * argument ('c') will be interpreted as the country code. It is 5057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * recommended that this constructor only be used to ease porting, 5067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and that clients instead use the single-argument constructor 5077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * when constructing a ULocale from a localeID. 5087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param a first component of the locale id 5097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param b second component of the locale id 5107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param c third component of the locale id 5117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #ULocale(String) 5127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 5137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ULocale(String a, String b, String c) { 5157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert localeID = getName(lscvToID(a, b, c, EMPTY_STRING)); 5167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Creates a ULocale from the id by first canonicalizing the id. 5207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param nonCanonicalID the locale id to canonicalize 5217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the locale created from the canonical version of the ID. 5227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 5237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale createCanonical(String nonCanonicalID) { 5257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new ULocale(canonicalize(nonCanonicalID), (Locale)null); 5267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String lscvToID(String lang, String script, String country, String variant) { 5297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder buf = new StringBuilder(); 5307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (lang != null && lang.length() > 0) { 5327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(lang); 5337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (script != null && script.length() > 0) { 5357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(UNDERSCORE); 5367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(script); 5377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (country != null && country.length() > 0) { 5397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(UNDERSCORE); 5407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(country); 5417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (variant != null && variant.length() > 0) { 5437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (country == null || country.length() == 0) { 5447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(UNDERSCORE); 5457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(UNDERSCORE); 5477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(variant); 5487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return buf.toString(); 5507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Converts this ULocale object to a {@link java.util.Locale}. 5542a7db240a11150ab654325587d653754c62b71a7Yoshito Umaoka * @return a {@link java.util.Locale} that either exactly represents this object 5557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or is the closest approximation. 5567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 2.8 5577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Locale toLocale() { 5597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (locale == null) { 5607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locale = JDKLocaleHelper.toLocale(this); 5617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return locale; 5637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 5667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Keep our own default ULocale. 5677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 5687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Locale defaultLocale = Locale.getDefault(); 5697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static ULocale defaultULocale; 5707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Locale[] defaultCategoryLocales = new Locale[Category.values().length]; 5727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static ULocale[] defaultCategoryULocales = new ULocale[Category.values().length]; 5737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static { 5757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultULocale = forLocale(defaultLocale); 5767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 5777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // For Java 6 or older JRE, ICU initializes the default script from 5787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // "user.script" system property. The system property was added 5797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // in Java 7. On JRE 7, Locale.getDefault() should reflect the 5807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // property value to the Locale's default. So ICU just relies on 5817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Locale.getDefault(). 582f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 5837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: The "user.script" property is only used by initialization. 5842d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert // 5859713d6ad72cf9922638a2a56f61089a3db31adabroubert if (JDKLocaleHelper.hasLocaleCategories()) { 5867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Category cat: Category.values()) { 5877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = cat.ordinal(); 5887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryLocales[idx] = JDKLocaleHelper.getDefault(cat); 5897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryULocales[idx] = forLocale(defaultCategoryLocales[idx]); 5907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 5917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 5927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Make sure the current default Locale is original. 5937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // If not, it means that someone updated the default Locale. 5947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // In this case, user.XXX properties are already out of date 5957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // and we should not use user.script. 5967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (JDKLocaleHelper.isOriginalDefaultLocale(defaultLocale)) { 5977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Use "user.script" if available 5987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String userScript = JDKLocaleHelper.getSystemProperty("user.script"); 5997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (userScript != null && LanguageTag.isScript(userScript)) { 6007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: Builder or forLanguageTag cannot be used here 6017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // when one of Locale fields is not well-formed. 6027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert BaseLocale base = defaultULocale.base(); 6037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert BaseLocale newBase = BaseLocale.getInstance(base.getLanguage(), userScript, 6047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert base.getRegion(), base.getVariant()); 6057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultULocale = getInstance(newBase, defaultULocale.extensions()); 6067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Java 6 or older does not have separated category locales, 6107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // use the non-category default for all 6117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Category cat: Category.values()) { 6127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = cat.ordinal(); 6137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryLocales[idx] = defaultLocale; 6147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryULocales[idx] = defaultULocale; 6157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the current default ULocale. 6217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 6227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The default ULocale is synchronized to the default Java Locale. This method checks 6237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the current default Java Locale and returns an equivalent ULocale. 6247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 6252a7db240a11150ab654325587d653754c62b71a7Yoshito Umaoka * <b>Note:</b> Before Java 7, the {@link java.util.Locale} was not able to represent a 6262a7db240a11150ab654325587d653754c62b71a7Yoshito Umaoka * locale's script. Therefore, the script field in the default ULocale is always empty unless 6277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a ULocale with non-empty script is explicitly set by {@link #setDefault(ULocale)} 6287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * on Java 6 or older systems. 6297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 6307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <b>Note for ICU 49 or later:</b> Some JRE implementations allow users to override the default 6312a7db240a11150ab654325587d653754c62b71a7Yoshito Umaoka * {@link java.util.Locale} using system properties - <code>user.language</code>, 6322a7db240a11150ab654325587d653754c62b71a7Yoshito Umaoka * <code>user.country</code> and <code>user.variant</code>. In addition to these system 6332a7db240a11150ab654325587d653754c62b71a7Yoshito Umaoka * properties, some Java 7 implementations support <code>user.script</code> for overriding the 6342a7db240a11150ab654325587d653754c62b71a7Yoshito Umaoka * default Locale's script. 6357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ICU 49 and later versions use the <code>user.script</code> system property on Java 6 6367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or older systems supporting other <code>user.*</code> system properties to initialize 6377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the default ULocale. The <code>user.script</code> override for default ULocale is not 6387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * used on Java 7, or if the current Java default Locale is changed after start up. 6392d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 6407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the default ULocale. 6417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 2.8 6427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale getDefault() { 6447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (ULocale.class) { 6457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (defaultULocale == null) { 6467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // When Java's default locale has extensions (such as ja-JP-u-ca-japanese), 6477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Locale -> ULocale mapping requires BCP47 keyword mapping data that is currently 6487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // stored in a resource bundle. However, UResourceBundle currently requires 6497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // non-null default ULocale. For now, this implementation returns ULocale.ROOT 6507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // to avoid the problem. 6517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO: Consider moving BCP47 mapping data out of resource bundle later. 6537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ULocale.ROOT; 6557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale currentDefault = Locale.getDefault(); 6577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!defaultLocale.equals(currentDefault)) { 6587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultLocale = currentDefault; 6597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultULocale = forLocale(currentDefault); 6607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6619713d6ad72cf9922638a2a56f61089a3db31adabroubert if (!JDKLocaleHelper.hasLocaleCategories()) { 6627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Detected Java default Locale change. 6637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // We need to update category defaults to match the 6647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Java 7's behavior on Java 6 or older environment. 6657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Category cat : Category.values()) { 6667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = cat.ordinal(); 6677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryLocales[idx] = currentDefault; 6687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryULocales[idx] = forLocale(currentDefault); 6697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return defaultULocale; 6737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 6757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 6767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 6777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets the default ULocale. This also sets the default Locale. 6787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If the caller does not have write permission to the 6797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * user.language property, a security exception will be thrown, 6807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and the default ULocale will remain unchanged. 6817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 6827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * By setting the default ULocale with this method, all of the default categoy locales 6837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * are also set to the specified default ULocale. 6847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param newLocale the new default locale 6857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws SecurityException if a security manager exists and its 6867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>checkPermission</code> method doesn't allow the operation. 6877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws NullPointerException if <code>newLocale</code> is null 6887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see SecurityManager#checkPermission(java.security.Permission) 6897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see java.util.PropertyPermission 6907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see ULocale#setDefault(Category, ULocale) 6917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 6927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 6937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static synchronized void setDefault(ULocale newLocale){ 6947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultLocale = newLocale.toLocale(); 6957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale.setDefault(defaultLocale); 6967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultULocale = newLocale; 6977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // This method also updates all category default locales 6987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Category cat : Category.values()) { 6997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert setDefault(cat, newLocale); 7007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the current default ULocale for the specified category. 7052d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 7067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param category the category 7077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the default ULocale for the specified category. 7087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 49 7097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale getDefault(Category category) { 7117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert synchronized (ULocale.class) { 7127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = category.ordinal(); 7137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (defaultCategoryULocales[idx] == null) { 7147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Just in case this method is called during ULocale class 7157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // initialization. Unlike getDefault(), we do not have 7167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // cyclic dependency for category default. 7177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ULocale.ROOT; 7187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7199713d6ad72cf9922638a2a56f61089a3db31adabroubert if (JDKLocaleHelper.hasLocaleCategories()) { 7207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale currentCategoryDefault = JDKLocaleHelper.getDefault(category); 7217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!defaultCategoryLocales[idx].equals(currentCategoryDefault)) { 7227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryLocales[idx] = currentCategoryDefault; 7237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryULocales[idx] = forLocale(currentCategoryDefault); 7247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 7267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // java.util.Locale.setDefault(Locale) in Java 7 updates 7277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // category locale defaults. On Java 6 or older environment, 7287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ICU4J checks if the default locale has changed and update 7297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // category ULocales here if necessary. 730f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 7317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: When java.util.Locale.setDefault(Locale) is called 7327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // with a Locale same with the previous one, Java 7 still 7337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // updates category locale defaults. On Java 6 or older env, 7347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // there is no good way to detect the event, ICU4J simply 7357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // check if the default Java Locale has changed since last 7367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // time. 7377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale currentDefault = Locale.getDefault(); 7397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!defaultLocale.equals(currentDefault)) { 7407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultLocale = currentDefault; 7417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultULocale = forLocale(currentDefault); 7427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Category cat : Category.values()) { 7447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int tmpIdx = cat.ordinal(); 7457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryLocales[tmpIdx] = currentDefault; 7467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryULocales[tmpIdx] = forLocale(currentDefault); 7477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 749f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 7507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // No synchronization with JDK Locale, because category default 7517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // is not supported in Java 6 or older versions 7527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return defaultCategoryULocales[idx]; 7547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets the default <code>ULocale</code> for the specified <code>Category</code>. 7597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This also sets the default <code>Locale</code> for the specified <code>Category</code> 7607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * of the JVM. If the caller does not have write permission to the 7617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * user.language property, a security exception will be thrown, 7627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and the default ULocale for the specified Category will remain unchanged. 7632d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 7647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param category the specified category to set the default locale 7657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param newLocale the new default locale 7667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see SecurityManager#checkPermission(java.security.Permission) 7677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see java.util.PropertyPermission 7687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 49 7697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static synchronized void setDefault(Category category, ULocale newLocale) { 7717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale newJavaDefault = newLocale.toLocale(); 7727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = category.ordinal(); 7737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryULocales[idx] = newLocale; 7747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert defaultCategoryLocales[idx] = newJavaDefault; 7757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert JDKLocaleHelper.setDefault(category, newJavaDefault); 7767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is for compatibility with Locale-- in actuality, since ULocale is 7807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * immutable, there is no reason to clone it, so this API returns 'this'. 7817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 7827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7832d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 7847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Object clone() { 7857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 7867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the hashCode. 7907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 7917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 7922d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 7937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int hashCode() { 7947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return localeID.hashCode(); 7957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 7967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 7977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 7987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns true if the other object is another ULocale with the 7997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * same full name. 8007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Note that since names are not canonicalized, two ULocales that 8017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * function identically might not compare equal. 8027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 8037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return true if this Locale is equal to the specified object. 8047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 8057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8062d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 8077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean equals(Object obj) { 8087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (this == obj) { 8097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return true; 8107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (obj instanceof ULocale) { 8127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return localeID.equals(((ULocale)obj).localeID); 8137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 8157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Compares two ULocale for ordering. 8199e281ba4837cba4a1cf9523d6f8b0621b150063dScott Russell * <p><b>Note:</b> The order might change in future. 8202d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 8217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param other the ULocale to be compared. 8227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return a negative integer, zero, or a positive integer as this ULocale is less than, equal to, or greater 8237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * than the specified ULocale. 8247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws NullPointerException if <code>other</code> is null. 8252d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 826f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 53 8277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 8282d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 8297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int compareTo(ULocale other) { 8307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (this == other) { 8317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; 8327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int cmp = 0; 8357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Language 8377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = getLanguage().compareTo(other.getLanguage()); 8387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cmp == 0) { 8397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Script 8407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = getScript().compareTo(other.getScript()); 8417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cmp == 0) { 8427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Region 8437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = getCountry().compareTo(other.getCountry()); 8447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cmp == 0) { 8457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Variant 8467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = getVariant().compareTo(other.getVariant()); 8477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cmp == 0) { 8487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Keywords 8497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Iterator<String> thisKwdItr = getKeywords(); 8507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Iterator<String> otherKwdItr = other.getKeywords(); 8517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (thisKwdItr == null) { 8537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = otherKwdItr == null ? 0 : -1; 8547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (otherKwdItr == null) { 8557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = 1; 8567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 8577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Both have keywords 8587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (cmp == 0 && thisKwdItr.hasNext()) { 8597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!otherKwdItr.hasNext()) { 8607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = 1; 8617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 8627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Compare keyword keys 8647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String thisKey = thisKwdItr.next(); 8657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String otherKey = otherKwdItr.next(); 8667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = thisKey.compareTo(otherKey); 8677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cmp == 0) { 8687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Compare keyword values 8697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String thisVal = getKeywordValue(thisKey); 8707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String otherVal = other.getKeywordValue(otherKey); 8717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (thisVal == null) { 8727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = otherVal == null ? 0 : -1; 8737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (otherVal == null) { 8747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = 1; 8757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 8767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = thisVal.compareTo(otherVal); 8777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cmp == 0 && otherKwdItr.hasNext()) { 8817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cmp = -1; 8827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Normalize the result value: 8907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: String.compareTo() may return value other than -1, 0, 1. 8917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // A value other than those are OK by the definition, but we don't want 8927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // associate any semantics other than negative/zero/positive. 8937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return (cmp < 0) ? -1 : ((cmp > 0) ? 1 : 0); 8947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 8957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 8967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 8977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icunote} Unlike the Locale API, this returns an array of <code>ULocale</code>, 8987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * not <code>Locale</code>. Returns a list of all installed locales. 8997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 9007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale[] getAvailableLocales() { 9027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ICUResourceBundle.getAvailableULocales(); 9037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a list of all 2-letter country codes defined in ISO 3166. 9077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Can be used to create Locales. 9087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 9097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String[] getISOCountries() { 9117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleIDs.getISOCountries(); 9127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a list of all 2-letter language codes defined in ISO 639. 9167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Can be used to create Locales. 9177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * [NOTE: ISO 639 is not a stable standard-- some languages' codes have changed. 9187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The list this function returns includes both the new and the old codes for the 9197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * languages whose codes have changed.] 9207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 9217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String[] getISOLanguages() { 9237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleIDs.getISOLanguages(); 9247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the language code for this locale, which will either be the empty string 9287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or a lowercase ISO 639 code. 9297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayLanguage() 9307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayLanguage(ULocale) 9317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 9327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getLanguage() { 9347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return base().getLanguage(); 9357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the language code for the locale ID, 9397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * which will either be the empty string 9407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or a lowercase ISO 639 code. 9417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayLanguage() 9427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayLanguage(ULocale) 9437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 9447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getLanguage(String localeID) { 9467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new LocaleIDParser(localeID).getLanguage(); 9477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the script code for this locale, which might be the empty string. 9517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayScript() 9527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayScript(ULocale) 9537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 9547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getScript() { 9567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return base().getScript(); 9577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the script code for the specified locale, which might be the empty 9617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * string. 9627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayScript() 9637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayScript(ULocale) 9647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 9657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getScript(String localeID) { 9677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new LocaleIDParser(localeID).getScript(); 9687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the country/region code for this locale, which will either be the empty string 9727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or an uppercase ISO 3166 2-letter code. 9737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayCountry() 9747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayCountry(ULocale) 9757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 9767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getCountry() { 9787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return base().getRegion(); 9797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 9827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the country/region code for this locale, which will either be the empty string 9837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or an uppercase ISO 3166 2-letter code. 9847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID The locale identification string. 9857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayCountry() 9867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayCountry(ULocale) 9877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 9887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 9897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getCountry(String localeID) { 9907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new LocaleIDParser(localeID).getCountry(); 9917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 9927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 9937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 99487255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * {@icu} Get the region to use for supplemental data lookup. 99587255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * Uses 99687255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * (1) any region specified by locale tag "rg"; if none then 99787255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * (2) any unicode_region_tag in the locale ID; if none then 99887255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * (3) if inferRegion is TRUE, the region suggested by 99987255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * getLikelySubtags on the localeID. 100087255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * If no region is found, returns empty string "" 100187255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * 100287255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * @param locale 100387255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * The locale (includes any keywords) from which 100487255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * to get the region to use for supplemental data. 100587255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * @param inferRegion 100687255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * If TRUE, will try to infer region from other 100787255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * locale elements if not found any other way. 100887255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * @return 100987255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * String with region to use ("" if none found). 101087255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * @internal ICU 57 101187255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert * @deprecated This API is ICU internal only. 101287255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert */ 101387255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert @Deprecated 101487255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert public static String getRegionForSupplementalData( 101587255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert ULocale locale, boolean inferRegion) { 101687255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert String region = locale.getKeywordValue("rg"); 101787255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert if (region != null && region.length() == 6) { 101887255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert String regionUpper = AsciiUtil.toUpperString(region); 101987255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert if (regionUpper.endsWith("ZZZZ")) { 102087255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert return regionUpper.substring(0,2); 102187255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert } 102287255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert } 102387255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert region = locale.getCountry(); 102487255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert if (region.length() == 0 && inferRegion) { 102587255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert ULocale maximized = addLikelySubtags(locale); 102687255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert region = maximized.getCountry(); 102787255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert } 102887255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert return region; 102987255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert } 103087255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert 103187255a3fc79cc94374b5b8adc76a86e251ac7d3eFredrik Roubert /** 10327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the variant code for this locale, which might be the empty string. 10337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayVariant() 10347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayVariant(ULocale) 10357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 10367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getVariant() { 10387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return base().getVariant(); 10397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the variant code for the specified locale, which might be the empty string. 10437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayVariant() 10447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getDisplayVariant(ULocale) 10457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 10467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getVariant(String localeID) { 10487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new LocaleIDParser(localeID).getVariant(); 10497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the fallback locale for the specified locale, which might be the 10537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * empty string. 10547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.2 10557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getFallback(String localeID) { 10577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getFallbackString(getName(localeID)); 10587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the fallback locale for this locale. If this locale is root, 10627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * returns null. 10637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.2 10647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ULocale getFallback() { 10667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (localeID.length() == 0 || localeID.charAt(0) == '@') { 10677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 10687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new ULocale(getFallbackString(localeID), (Locale)null); 10707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the given (canonical) locale id minus the last part before the tags. 10747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 10757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getFallbackString(String fallback) { 10767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int extStart = fallback.indexOf('@'); 10777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (extStart == -1) { 10787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert extStart = fallback.length(); 10797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int last = fallback.lastIndexOf('_', extStart); 10817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (last == -1) { 10827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert last = 0; 10837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 10847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // truncate empty segment 10857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (last > 0) { 10867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (fallback.charAt(last - 1) != '_') { 10877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 10887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert last--; 10907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return fallback.substring(0, last) + fallback.substring(extStart); 10937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 10947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 10957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 10967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the (normalized) base name for this locale, 10977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * like {@link #getName()}, but without keywords. 10987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 10997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the base name as a String. 11007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 11017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getBaseName() { 11037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getBaseName(localeID); 11047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the (normalized) base name for the specified locale, 11087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * like {@link #getName(String)}, but without keywords. 11097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 11107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the locale ID as a string 11117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the base name as a String. 11127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 11137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getBaseName(String localeID){ 11157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (localeID.indexOf('@') == -1) { 11167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return localeID; 11177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new LocaleIDParser(localeID).getBaseName(); 11197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the (normalized) full name for this locale. 11237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 11247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return String the full name of the localeID 11257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 11267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getName() { 11287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return localeID; // always normalized 11297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1130f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 11317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Gets the shortest length subtag's size. 11337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 11347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID 11357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The size of the shortest length subtag 11367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 11377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static int getShortestSubtagLength(String localeID) { 11387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int localeIDLength = localeID.length(); 11397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int length = localeIDLength; 11407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean reset = true; 11417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int tmpLength = 0; 1142f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 11437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < localeIDLength; i++) { 11447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (localeID.charAt(i) != '_' && localeID.charAt(i) != '-') { 11457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (reset) { 11467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert reset = false; 11477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tmpLength = 0; 11487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tmpLength++; 11507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 11517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tmpLength != 0 && tmpLength < length) { 11527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert length = tmpLength; 11537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert reset = true; 11557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 1157f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 11587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return length; 11597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the (normalized) full name for the specified locale. 11637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 11647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the localeID as a string 11657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return String the full name of the localeID 11667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 11677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getName(String localeID){ 11697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tmpLocaleID; 11707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Convert BCP47 id if necessary 11717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (localeID != null && !localeID.contains("@") && getShortestSubtagLength(localeID) == 1) { 11727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tmpLocaleID = forLanguageTag(localeID).getName(); 11737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tmpLocaleID.length() == 0) { 11747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tmpLocaleID = localeID; 11757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 11777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tmpLocaleID = localeID; 11787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11792d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return nameCache.getInstance(tmpLocaleID, null /* unused */); 11807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a string representation of this object. 11847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 11857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11862d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 11877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toString() { 11887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return localeID; 11897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 11907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 11917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 11927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns an iterator over keywords for this locale. If there 11937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * are no keywords, returns null. 11947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return iterator over keywords, or null if there are no keywords. 11957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 11967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 11977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Iterator<String> getKeywords() { 11987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getKeywords(localeID); 11997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 12027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns an iterator over keywords for the specified locale. If there 12037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * are no keywords, returns null. 12047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return an iterator over the keywords in the specified locale, or null 12057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * if there are no keywords. 12067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 12077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static Iterator<String> getKeywords(String localeID){ 12097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new LocaleIDParser(localeID).getKeywords(); 12107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 12137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the value for a keyword in this locale. If the keyword is not 12147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * defined, returns null. 12157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keywordName name of the keyword whose value is desired. Case insensitive. 12167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the value of the keyword, or null. 12177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 12187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getKeywordValue(String keywordName){ 12207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getKeywordValue(localeID, keywordName); 12217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 12247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the value for a keyword in the specified locale. If the keyword is 12257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * not defined, returns null. The locale name does not need to be normalized. 12267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keywordName name of the keyword whose value is desired. Case insensitive. 12277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return String the value of the keyword as a string 12287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 12297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getKeywordValue(String localeID, String keywordName) { 12317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new LocaleIDParser(localeID).getKeywordValue(keywordName); 12327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 12357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the canonical name for the specified locale ID. This is used to 12367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * convert POSIX and other grandfathered IDs to standard ICU form. 12377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the locale id 12387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the canonicalized id 12397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 12407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 12417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String canonicalize(String localeID){ 12427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleIDParser parser = new LocaleIDParser(localeID, true); 12437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String baseName = parser.getBaseName(); 12447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean foundVariant = false; 12457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // formerly, we always set to en_US_POSIX if the basename was empty, but 12477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // now we require that the entire id be empty, so that "@foo=bar" 12487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // will pass through unchanged. 12497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // {dlf} I'd rather keep "" unchanged. 12507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (localeID.equals("")) { 12517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return ""; 1252f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // return "en_US_POSIX"; 12537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // we have an ID in the form xx_Yyyy_ZZ_KKKKK 12567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert initCANONICALIZE_MAP(); 12587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* convert the variants to appropriate ID */ 12607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < variantsToKeywords.length; i++) { 12617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] vals = variantsToKeywords[i]; 12627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int idx = baseName.lastIndexOf("_" + vals[0]); 12637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (idx > -1) { 12647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert foundVariant = true; 12657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert baseName = baseName.substring(0, idx); 12677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (baseName.endsWith("_")) { 12687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert baseName = baseName.substring(0, --idx); 12697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert parser.setBaseName(baseName); 12717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert parser.defaultKeywordValue(vals[1], vals[2]); 12727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 12737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* See if this is an already known locale */ 12777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < CANONICALIZE_MAP.length; i++) { 12787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (CANONICALIZE_MAP[i][0].equals(baseName)) { 12797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert foundVariant = true; 12807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] vals = CANONICALIZE_MAP[i]; 12827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert parser.setBaseName(vals[1]); 12837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (vals[2] != null) { 12847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert parser.defaultKeywordValue(vals[2], vals[3]); 12857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 12877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* total mondo hack for Norwegian, fortunately the main NY case is handled earlier */ 12917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!foundVariant) { 12927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (parser.getLanguage().equals("nb") && parser.getVariant().equals("NY")) { 12937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert parser.setBaseName(lscvToID("nn", parser.getScript(), parser.getCountry(), null)); 12947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 12977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return parser.getName(); 12987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 12997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 13017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Given a keyword and a value, return a new locale with an updated 13027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword and value. If the keyword is null, this removes all keywords from the locale id. 13037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Otherwise, if the value is null, this removes the value for this keyword from the 13047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale id. Otherwise, this adds/replaces the value for this keyword in the locale id. 13057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The keyword and value must not be empty. 13067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 13077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Related: {@link #getBaseName()} returns the locale ID string with all keywords removed. 13087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 13097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword to add/remove, or null to remove all keywords. 13107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param value the value to add/set, or null to remove this particular keyword. 13117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the updated locale 13127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.2 13137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ULocale setKeywordValue(String keyword, String value) { 13157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new ULocale(setKeywordValue(localeID, keyword, value), (Locale)null); 13167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 13197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Given a locale id, a keyword, and a value, return a new locale id with an updated 13207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword and value. If the keyword is null, this removes all keywords from the locale id. 13217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Otherwise, if the value is null, this removes the value for this keyword from the 13227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale id. Otherwise, this adds/replaces the value for this keyword in the locale id. 13237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The keyword and value must not be empty. 13247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 13257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Related: {@link #getBaseName(String)} returns the locale ID string with all keywords removed. 13267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 13277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the locale id to modify 13287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword to add/remove, or null to remove all keywords. 13297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param value the value to add/set, or null to remove this particular keyword. 13307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the updated locale id 13317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.2 13327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String setKeywordValue(String localeID, String keyword, String value) { 13347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleIDParser parser = new LocaleIDParser(localeID); 13357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert parser.setKeywordValue(keyword, value); 13367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return parser.getName(); 13377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 13407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Given a locale id, a keyword, and a value, return a new locale id with an updated 13417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword and value, if the keyword does not already have a value. The keyword and 13427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * value must not be null or empty. 13437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the locale id to modify 13447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword to add, if not already present 13457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param value the value to add, if not already present 13467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the updated locale id 13477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 1348f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert /* private static String defaultKeywordValue(String localeID, String keyword, String value) { 13497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleIDParser parser = new LocaleIDParser(localeID); 13507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert parser.defaultKeywordValue(keyword, value); 13517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return parser.getName(); 13527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }*/ 13537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 13557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a three-letter abbreviation for this locale's language. If the locale 13567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * doesn't specify a language, returns the empty string. Otherwise, returns 13577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a lowercase ISO 639-2/T language code. 13587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The ISO 639-2 language codes can be found on-line at 13597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <a href="ftp://dkuug.dk/i18n/iso-639-2.txt"><code>ftp://dkuug.dk/i18n/iso-639-2.txt</code></a> 13607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @exception MissingResourceException Throws MissingResourceException if the 13617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * three-letter language abbreviation is not available for this locale. 13627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 13637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getISO3Language(){ 13657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getISO3Language(localeID); 13667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 13697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a three-letter abbreviation for this locale's language. If the locale 13707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * doesn't specify a language, returns the empty string. Otherwise, returns 13717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a lowercase ISO 639-2/T language code. 13727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The ISO 639-2 language codes can be found on-line at 13737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <a href="ftp://dkuug.dk/i18n/iso-639-2.txt"><code>ftp://dkuug.dk/i18n/iso-639-2.txt</code></a> 13747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @exception MissingResourceException Throws MissingResourceException if the 13757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * three-letter language abbreviation is not available for this locale. 13767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 13777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getISO3Language(String localeID) { 13797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleIDs.getISO3Language(getLanguage(localeID)); 13807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 13837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a three-letter abbreviation for this locale's country/region. If the locale 13847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * doesn't specify a country, returns the empty string. Otherwise, returns 13857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * an uppercase ISO 3166 3-letter country code. 13867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @exception MissingResourceException Throws MissingResourceException if the 13877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * three-letter country abbreviation is not available for this locale. 13887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 13897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 13907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getISO3Country() { 13917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getISO3Country(localeID); 13927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 13937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 13947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 13957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a three-letter abbreviation for this locale's country/region. If the locale 13967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * doesn't specify a country, returns the empty string. Otherwise, returns 13977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * an uppercase ISO 3166 3-letter country code. 13987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @exception MissingResourceException Throws MissingResourceException if the 13997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * three-letter country abbreviation is not available for this locale. 14007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 14017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 14027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getISO3Country(String localeID) { 14037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleIDs.getISO3Country(getCountry(localeID)); 14047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 14077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Pairs of (language subtag, + or -) for finding out fast if common languages 14087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * are LTR (minus) or RTL (plus). 14097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 14107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String LANG_DIR_STRING = 14117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert "root-en-es-pt-zh-ja-ko-de-fr-it-ar+he+fa+ru-nl-pl-th-tr-"; 14127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 14147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns whether this locale's script is written right-to-left. 14157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If there is no script subtag, then the likely script is used, 14167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * see {@link #addLikelySubtags(ULocale)}. 14177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If no likely script is known, then false is returned. 14187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 14197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>A script is right-to-left according to the CLDR script metadata 14207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * which corresponds to whether the script's letters have Bidi_Class=R or AL. 14217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 14227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Returns true for "ar" and "en-Hebr", false for "zh" and "fa-Cyrl". 14237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 14247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return true if the locale's script is written right-to-left 1425bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * @stable ICU 54 14267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 14277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public boolean isRightToLeft() { 14287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String script = getScript(); 14297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (script.length() == 0) { 14307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Fastpath: We know the likely scripts and their writing direction 14317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for some common languages. 14327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String lang = getLanguage(); 14337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (lang.length() == 0) { 14347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 14357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int langIndex = LANG_DIR_STRING.indexOf(lang); 14377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (langIndex >= 0) { 14387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (LANG_DIR_STRING.charAt(langIndex + lang.length())) { 14397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case '-': return false; 14407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case '+': return true; 14417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert default: break; // partial match of a longer code 14427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Otherwise, find the likely script. 14457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale likely = addLikelySubtags(this); 14467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert script = likely.getScript(); 14477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (script.length() == 0) { 14487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 14497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int scriptCode = UScript.getCodeFromName(script); 14527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return UScript.isRightToLeft(scriptCode); 14537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // display names 14567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 14587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns this locale's language localized for display in the default <code>DISPLAY</code> locale. 14597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized language name. 14607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#DISPLAY 14617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 14627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 14637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayLanguage() { 14647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayLanguageInternal(this, getDefault(Category.DISPLAY), false); 14657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 14687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns this locale's language localized for display in the provided locale. 14697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 14707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized language name. 14717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 14727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 14737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayLanguage(ULocale displayLocale) { 14747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayLanguageInternal(this, displayLocale, false); 14757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 14787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's language localized for display in the provided locale. 14797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 14807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose language will be displayed 14817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocaleID the id of the locale in which to display the name. 14827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized language name. 14837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 14847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 14857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayLanguage(String localeID, String displayLocaleID) { 14867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayLanguageInternal(new ULocale(localeID), new ULocale(displayLocaleID), 14877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert false); 14887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 14897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 14907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 14917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's language localized for display in the provided locale. 14927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 14937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose language will be displayed. 14947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 14957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized language name. 14967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 14977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 14987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayLanguage(String localeID, ULocale displayLocale) { 14997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayLanguageInternal(new ULocale(localeID), displayLocale, false); 15007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 15027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns this locale's language localized for display in the default <code>DISPLAY</code> locale. 15037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If a dialect name is present in the data, then it is returned. 15047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized language name. 15057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#DISPLAY 15067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 15077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 15087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayLanguageWithDialect() { 15097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayLanguageInternal(this, getDefault(Category.DISPLAY), true); 15107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 15137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns this locale's language localized for display in the provided locale. 15147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If a dialect name is present in the data, then it is returned. 15157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 15167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized language name. 15177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 15187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 15197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayLanguageWithDialect(ULocale displayLocale) { 15207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayLanguageInternal(this, displayLocale, true); 15217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 15247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's language localized for display in the provided locale. 15257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If a dialect name is present in the data, then it is returned. 15267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 15277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose language will be displayed 15287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocaleID the id of the locale in which to display the name. 15297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized language name. 15307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 15317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 15327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayLanguageWithDialect(String localeID, String displayLocaleID) { 15337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayLanguageInternal(new ULocale(localeID), new ULocale(displayLocaleID), 15347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert true); 15357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 15387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's language localized for display in the provided locale. 15397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If a dialect name is present in the data, then it is returned. 15407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 15417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose language will be displayed. 15427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 15437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized language name. 15447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 15457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 15467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayLanguageWithDialect(String localeID, ULocale displayLocale) { 15477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayLanguageInternal(new ULocale(localeID), displayLocale, true); 15487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getDisplayLanguageInternal(ULocale locale, ULocale displayLocale, 15517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean useDialect) { 15527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String lang = useDialect ? locale.getBaseName() : locale.getLanguage(); 15537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleDisplayNames.getInstance(displayLocale).languageDisplayName(lang); 15547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 15577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns this locale's script localized for display in the default <code>DISPLAY</code> locale. 15587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized script name. 15597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#DISPLAY 15607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 15617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 15627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayScript() { 15637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayScriptInternal(this, getDefault(Category.DISPLAY)); 15647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 15677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns this locale's script localized for display in the default <code>DISPLAY</code> locale. 15687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized script name. 15697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#DISPLAY 15707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 15717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 15727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 15737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 15747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayScriptInContext() { 15757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayScriptInContextInternal(this, getDefault(Category.DISPLAY)); 15767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 15797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns this locale's script localized for display in the provided locale. 15807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 15817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized script name. 15827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 15837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 15847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayScript(ULocale displayLocale) { 15857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayScriptInternal(this, displayLocale); 15867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 15887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 15897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns this locale's script localized for display in the provided locale. 15907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 15917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized script name. 15927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 15937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 15947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 15957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 15967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayScriptInContext(ULocale displayLocale) { 15977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayScriptInContextInternal(this, displayLocale); 15987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 15997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's script localized for display in the provided locale. 16027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 16037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose script will be displayed 16047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocaleID the id of the locale in which to display the name. 16057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized script name. 16067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 16077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayScript(String localeID, String displayLocaleID) { 16097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayScriptInternal(new ULocale(localeID), new ULocale(displayLocaleID)); 16107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's script localized for display in the provided locale. 16137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 16147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose script will be displayed 16157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocaleID the id of the locale in which to display the name. 16167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized script name. 16177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 16187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 16197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 16217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayScriptInContext(String localeID, String displayLocaleID) { 16227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayScriptInContextInternal(new ULocale(localeID), new ULocale(displayLocaleID)); 16237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's script localized for display in the provided locale. 16277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose script will be displayed. 16287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 16297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized script name. 16307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 16317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayScript(String localeID, ULocale displayLocale) { 16337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayScriptInternal(new ULocale(localeID), displayLocale); 16347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's script localized for display in the provided locale. 16377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose script will be displayed. 16387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 16397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized script name. 16407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @internal 16417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @deprecated This API is ICU internal only. 16427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @Deprecated 16447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayScriptInContext(String localeID, ULocale displayLocale) { 16457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayScriptInContextInternal(new ULocale(localeID), displayLocale); 16467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // displayLocaleID is canonical, localeID need not be since parsing will fix this. 16497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getDisplayScriptInternal(ULocale locale, ULocale displayLocale) { 16507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleDisplayNames.getInstance(displayLocale) 1651f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert .scriptDisplayName(locale.getScript()); 16527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getDisplayScriptInContextInternal(ULocale locale, ULocale displayLocale) { 16557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleDisplayNames.getInstance(displayLocale) 1656f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert .scriptDisplayNameInContext(locale.getScript()); 16577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns this locale's country localized for display in the default <code>DISPLAY</code> locale. 1661f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * <b>Warning: </b>this is for the region part of a valid locale ID; it cannot just be the region code (like "FR"). 1662f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * To get the display name for a region alone, or for other options, use {@link LocaleDisplayNames} instead. 16637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized country name. 16647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#DISPLAY 16657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 16667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayCountry() { 16687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayCountryInternal(this, getDefault(Category.DISPLAY)); 16697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns this locale's country localized for display in the provided locale. 1673f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * <b>Warning: </b>this is for the region part of a valid locale ID; it cannot just be the region code (like "FR"). 1674f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * To get the display name for a region alone, or for other options, use {@link LocaleDisplayNames} instead. 16757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 16767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized country name. 16777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 16787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayCountry(ULocale displayLocale){ 16807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayCountryInternal(this, displayLocale); 16817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's country localized for display in the provided locale. 1685f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * <b>Warning: </b>this is for the region part of a valid locale ID; it cannot just be the region code (like "FR"). 1686f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * To get the display name for a region alone, or for other options, use {@link LocaleDisplayNames} instead. 16877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 16887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose country will be displayed 16897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocaleID the id of the locale in which to display the name. 16907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized country name. 16917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 16927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 16937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayCountry(String localeID, String displayLocaleID) { 16947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayCountryInternal(new ULocale(localeID), new ULocale(displayLocaleID)); 16957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 16967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 16977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 16987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's country localized for display in the provided locale. 1699f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * <b>Warning: </b>this is for the region part of a valid locale ID; it cannot just be the region code (like "FR"). 1700f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * To get the display name for a region alone, or for other options, use {@link LocaleDisplayNames} instead. 17017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 17027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose country will be displayed. 17037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 17047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized country name. 17057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 17067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 17077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayCountry(String localeID, ULocale displayLocale) { 17087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayCountryInternal(new ULocale(localeID), displayLocale); 17097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // displayLocaleID is canonical, localeID need not be since parsing will fix this. 17127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getDisplayCountryInternal(ULocale locale, ULocale displayLocale) { 17137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleDisplayNames.getInstance(displayLocale) 1714f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert .regionDisplayName(locale.getCountry()); 17157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 17187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns this locale's variant localized for display in the default <code>DISPLAY</code> locale. 17197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized variant name. 17207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#DISPLAY 17217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 17227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 17237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayVariant() { 17247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayVariantInternal(this, getDefault(Category.DISPLAY)); 17257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 17287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns this locale's variant localized for display in the provided locale. 17297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 17307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized variant name. 17317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 17327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 17337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayVariant(ULocale displayLocale) { 17347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayVariantInternal(this, displayLocale); 17357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 17387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's variant localized for display in the provided locale. 17397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 17407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose variant will be displayed 17417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocaleID the id of the locale in which to display the name. 17427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized variant name. 17437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 17447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 17457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayVariant(String localeID, String displayLocaleID){ 17467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayVariantInternal(new ULocale(localeID), new ULocale(displayLocaleID)); 17477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 17507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a locale's variant localized for display in the provided locale. 17517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 17527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose variant will be displayed. 17537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the name. 17547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized variant name. 17557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 17567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 17577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayVariant(String localeID, ULocale displayLocale) { 17587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayVariantInternal(new ULocale(localeID), displayLocale); 17597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getDisplayVariantInternal(ULocale locale, ULocale displayLocale) { 17627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleDisplayNames.getInstance(displayLocale) 1763f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert .variantDisplayName(locale.getVariant()); 17647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 17677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a keyword localized for display in the default <code>DISPLAY</code> locale. 17687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword to be displayed. 17697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized keyword name. 17707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getKeywords() 17717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#DISPLAY 17727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 17737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 17747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayKeyword(String keyword) { 17757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayKeywordInternal(keyword, getDefault(Category.DISPLAY)); 17767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 17797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a keyword localized for display in the specified locale. 17807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword to be displayed. 17817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocaleID the id of the locale in which to display the keyword. 17827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized keyword name. 17837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getKeywords(String) 17847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 17857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 17867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayKeyword(String keyword, String displayLocaleID) { 17877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayKeywordInternal(keyword, new ULocale(displayLocaleID)); 17887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 17897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 17907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 17917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a keyword localized for display in the specified locale. 17927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword to be displayed. 17937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the keyword. 17947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized keyword name. 17957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getKeywords(String) 17967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 17977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 17987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayKeyword(String keyword, ULocale displayLocale) { 17997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayKeywordInternal(keyword, displayLocale); 18007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getDisplayKeywordInternal(String keyword, ULocale displayLocale) { 18037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleDisplayNames.getInstance(displayLocale).keyDisplayName(keyword); 18047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a keyword value localized for display in the default <code>DISPLAY</code> locale. 18087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword whose value is to be displayed. 18097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized value name. 18107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#DISPLAY 18117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 18127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayKeywordValue(String keyword) { 18147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayKeywordValueInternal(this, keyword, getDefault(Category.DISPLAY)); 18157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a keyword value localized for display in the specified locale. 18197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword whose value is to be displayed. 18207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the value. 18217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized value name. 18227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 18237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayKeywordValue(String keyword, ULocale displayLocale) { 18257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayKeywordValueInternal(this, keyword, displayLocale); 18267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a keyword value localized for display in the specified locale. 18307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 18317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose keyword value is to be displayed. 18327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword whose value is to be displayed. 18337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocaleID the id of the locale in which to display the value. 18347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized value name. 18357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 18367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayKeywordValue(String localeID, String keyword, 18387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String displayLocaleID) { 18397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayKeywordValueInternal(new ULocale(localeID), keyword, 18407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new ULocale(displayLocaleID)); 18417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns a keyword value localized for display in the specified locale. 18457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 18467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the id of the locale whose keyword value is to be displayed. 18477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the keyword whose value is to be displayed. 18487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the id of the locale in which to display the value. 18497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized value name. 18507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 18517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayKeywordValue(String localeID, String keyword, 18537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale displayLocale) { 18547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayKeywordValueInternal(new ULocale(localeID), keyword, displayLocale); 18557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // displayLocaleID is canonical, localeID need not be since parsing will fix this. 18587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getDisplayKeywordValueInternal(ULocale locale, String keyword, 18597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale displayLocale) { 18607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keyword = AsciiUtil.toLowerString(keyword.trim()); 18617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String value = locale.getKeywordValue(keyword); 18627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleDisplayNames.getInstance(displayLocale).keyValueDisplayName(keyword, value); 18637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns this locale name localized for display in the default <code>DISPLAY</code> locale. 18677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized locale name. 18687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#DISPLAY 18697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 18707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayName() { 18727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayNameInternal(this, getDefault(Category.DISPLAY)); 18737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns this locale name localized for display in the provided locale. 18777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the locale name. 18787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized locale name. 18797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 18807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayName(ULocale displayLocale) { 18827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayNameInternal(this, displayLocale); 18837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the locale ID localized for display in the provided locale. 18877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 18887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the locale whose name is to be displayed. 18897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocaleID the id of the locale in which to display the locale name. 18907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized locale name. 18917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 18927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 18937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayName(String localeID, String displayLocaleID) { 18947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayNameInternal(new ULocale(localeID), new ULocale(displayLocaleID)); 18957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 18967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 18977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 18987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the locale ID localized for display in the provided locale. 18997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 19007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the locale whose name is to be displayed. 19017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the locale name. 19027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized locale name. 19037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 3.0 19047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayName(String localeID, ULocale displayLocale) { 19067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayNameInternal(new ULocale(localeID), displayLocale); 19077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getDisplayNameInternal(ULocale locale, ULocale displayLocale) { 19107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleDisplayNames.getInstance(displayLocale).localeDisplayName(locale); 19117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns this locale name localized for display in the default <code>DISPLAY</code> locale. 19157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If a dialect name is present in the locale data, then it is returned. 19167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized locale name. 19177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Category#DISPLAY 19187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 19197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayNameWithDialect() { 19217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayNameWithDialectInternal(this, getDefault(Category.DISPLAY)); 19227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns this locale name localized for display in the provided locale. 19267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If a dialect name is present in the locale data, then it is returned. 19277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the locale name. 19287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized locale name. 19297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 19307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getDisplayNameWithDialect(ULocale displayLocale) { 19327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayNameWithDialectInternal(this, displayLocale); 19337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the locale ID localized for display in the provided locale. 19377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If a dialect name is present in the locale data, then it is returned. 19387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 19397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the locale whose name is to be displayed. 19407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocaleID the id of the locale in which to display the locale name. 19417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized locale name. 19427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 19437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayNameWithDialect(String localeID, String displayLocaleID) { 19457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayNameWithDialectInternal(new ULocale(localeID), 19467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert new ULocale(displayLocaleID)); 19477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns the locale ID localized for display in the provided locale. 19517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If a dialect name is present in the locale data, then it is returned. 19527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This is a cover for the ICU4C API. 19537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID the locale whose name is to be displayed. 19547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param displayLocale the locale in which to display the locale name. 19557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the localized locale name. 19567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 19577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getDisplayNameWithDialect(String localeID, ULocale displayLocale) { 19597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getDisplayNameWithDialectInternal(new ULocale(localeID), displayLocale); 19607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String getDisplayNameWithDialectInternal(ULocale locale, ULocale displayLocale) { 19637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return LocaleDisplayNames.getInstance(displayLocale, DialectHandling.DIALECT_NAMES) 1964f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert .localeDisplayName(locale); 19657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns this locale's layout orientation for characters. The possible 19697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * values are "left-to-right", "right-to-left", "top-to-bottom" or 19707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "bottom-to-top". 19717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The locale's layout orientation for characters. 19727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.0 19737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getCharacterOrientation() { 19752d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return ICUResourceTableAccess.getTableString(ICUData.ICU_BASE_NAME, this, 19762d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert "layout", "characters", "characters"); 19777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Returns this locale's layout orientation for lines. The possible 19817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * values are "left-to-right", "right-to-left", "top-to-bottom" or 19827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "bottom-to-top". 19837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The locale's layout orientation for lines. 19847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.0 19857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 19867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getLineOrientation() { 19872d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return ICUResourceTableAccess.getTableString(ICUData.ICU_BASE_NAME, this, 19882d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert "layout", "lines", "lines"); 19897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 19907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 19917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 19927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Selector for <tt>getLocale()</tt> indicating the locale of the 19937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * resource containing the data. This is always at or above the 19947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * valid locale. If the valid locale does not contain the 19957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * specific data being requested, then the actual locale will be 19967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * above the valid locale. If the object was not constructed from 19977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale data, then the valid locale is <i>null</i>. 19987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 19997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 (retain) 20007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 20017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 20027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static Type ACTUAL_LOCALE = new Type(); 20037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 20057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Selector for <tt>getLocale()</tt> indicating the most specific 20067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale for which any data exists. This is always at or above 20077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the requested locale, and at or below the actual locale. If 20087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the requested locale does not correspond to any resource data, 20097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * then the valid locale will be above the requested locale. If 20107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the object was not constructed from locale data, then the 20117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * actual locale is <i>null</i>. 20127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 20137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Note: The valid locale will be returned correctly in ICU 20147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 3.0 or later. In ICU 2.8, it is not returned correctly. 20157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 (retain) 20167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 20177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 20187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static Type VALID_LOCALE = new Type(); 20197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 20217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Opaque selector enum for <tt>getLocale()</tt>. 20227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.ULocale 20237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.ULocale#ACTUAL_LOCALE 20247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see com.ibm.icu.util.ULocale#VALID_LOCALE 20257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @draft ICU 2.8 (retainAll) 20267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @provisional This API might change or be removed in a future release. 20277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 20287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final class Type { 20297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private Type() {} 20307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2032f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert /** 2033f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * {@icu} Based on a HTTP formatted list of acceptable locales, determine an available 2034f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * locale for the user. NullPointerException is thrown if acceptLanguageList or 2035f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * availableLocales is null. If fallback is non-null, it will contain true if a 2036f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * fallback locale (one not in the acceptLanguageList) was returned. The value on 2037f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * entry is ignored. ULocale will be one of the locales in availableLocales, or the 2038f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * ROOT ULocale if if a ROOT locale was used as a fallback (because nothing else in 2039f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * availableLocales matched). No ULocale array element should be null; behavior is 2040f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * undefined if this is the case. 2041f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param acceptLanguageList list in HTTP "Accept-Language:" format of acceptable locales 2042f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param availableLocales list of available locales. One of these will be returned. 2043f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param fallback if non-null, a 1-element array containing a boolean to be set with 2044f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * the fallback status 2045f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @return one of the locales from the availableLocales list, or null if none match 2046f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 3.4 2047f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert */ 20487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale acceptLanguage(String acceptLanguageList, ULocale[] availableLocales, 2049f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert boolean[] fallback) { 20507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (acceptLanguageList == null) { 20517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new NullPointerException(); 20527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale acceptList[] = null; 20547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 20557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert acceptList = parseAcceptLanguage(acceptLanguageList, true); 20567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (ParseException pe) { 20577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert acceptList = null; 20587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (acceptList == null) { 20607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 20617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return acceptLanguage(acceptList, availableLocales, fallback); 20637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 2066f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * {@icu} Based on a list of acceptable locales, determine an available locale for the 2067f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * user. NullPointerException is thrown if acceptLanguageList or availableLocales is 2068f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * null. If fallback is non-null, it will contain true if a fallback locale (one not 2069f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * in the acceptLanguageList) was returned. The value on entry is ignored. ULocale 2070f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * will be one of the locales in availableLocales, or the ROOT ULocale if if a ROOT 2071f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * locale was used as a fallback (because nothing else in availableLocales matched). 2072f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * No ULocale array element should be null; behavior is undefined if this is the case. 2073f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param acceptLanguageList list of acceptable locales 2074f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param availableLocales list of available locales. One of these will be returned. 2075f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param fallback if non-null, a 1-element array containing a boolean to be set with 2076f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * the fallback status 2077f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @return one of the locales from the availableLocales list, or null if none match 2078f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 3.4 2079f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert */ 20807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 20817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale acceptLanguage(ULocale[] acceptLanguageList, ULocale[] 2082f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert availableLocales, boolean[] fallback) { 20837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // fallbacklist 20847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int i,j; 20857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(fallback != null) { 20867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fallback[0]=true; 20877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(i=0;i<acceptLanguageList.length;i++) { 20897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale aLocale = acceptLanguageList[i]; 20907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean[] setFallback = fallback; 20917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert do { 20927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for(j=0;j<availableLocales.length;j++) { 20937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(availableLocales[j].equals(aLocale)) { 20947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(setFallback != null) { 20957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert setFallback[0]=false; // first time with this locale - not a fallback. 20967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return availableLocales[j]; 20987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 20997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // compare to scriptless alias, so locales such as 21007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // zh_TW, zh_CN are considered as available locales - see #7190 21017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (aLocale.getScript().length() == 0 21027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && availableLocales[j].getScript().length() > 0 21037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && availableLocales[j].getLanguage().equals(aLocale.getLanguage()) 21047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && availableLocales[j].getCountry().equals(aLocale.getCountry()) 21057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && availableLocales[j].getVariant().equals(aLocale.getVariant())) { 21067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale minAvail = ULocale.minimizeSubtags(availableLocales[j]); 21077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (minAvail.getScript().length() == 0) { 21087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(setFallback != null) { 21097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert setFallback[0] = false; // not a fallback. 21107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return aLocale; 21127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale loc = aLocale.toLocale(); 21167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale parent = LocaleUtility.fallback(loc); 21177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if(parent != null) { 21187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert aLocale = new ULocale(parent); 21197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 21207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert aLocale = null; 21217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert setFallback = null; // Do not set fallback in later iterations 21237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } while (aLocale != null); 21247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 21267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 2128f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert /** 2129f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * {@icu} Based on a HTTP formatted list of acceptable locales, determine an available 2130f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * locale for the user. NullPointerException is thrown if acceptLanguageList or 2131f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * availableLocales is null. If fallback is non-null, it will contain true if a 2132f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * fallback locale (one not in the acceptLanguageList) was returned. The value on 2133f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * entry is ignored. ULocale will be one of the locales in availableLocales, or the 2134f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * ROOT ULocale if if a ROOT locale was used as a fallback (because nothing else in 2135f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * availableLocales matched). No ULocale array element should be null; behavior is 2136f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * undefined if this is the case. This function will choose a locale from the 2137f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * ULocale.getAvailableLocales() list as available. 2138f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param acceptLanguageList list in HTTP "Accept-Language:" format of acceptable locales 2139f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param fallback if non-null, a 1-element array containing a boolean to be set with 2140f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * the fallback status 2141f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @return one of the locales from the ULocale.getAvailableLocales() list, or null if 2142f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * none match 2143f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 3.4 2144f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert */ 21457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale acceptLanguage(String acceptLanguageList, boolean[] fallback) { 21467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return acceptLanguage(acceptLanguageList, ULocale.getAvailableLocales(), 2147f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert fallback); 2148f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert } 2149f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 2150f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert /** 2151f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * {@icu} Based on an ordered array of acceptable locales, determine an available 2152f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * locale for the user. NullPointerException is thrown if acceptLanguageList or 2153f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * availableLocales is null. If fallback is non-null, it will contain true if a 2154f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * fallback locale (one not in the acceptLanguageList) was returned. The value on 2155f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * entry is ignored. ULocale will be one of the locales in availableLocales, or the 2156f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * ROOT ULocale if if a ROOT locale was used as a fallback (because nothing else in 2157f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * availableLocales matched). No ULocale array element should be null; behavior is 2158f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * undefined if this is the case. This function will choose a locale from the 2159f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * ULocale.getAvailableLocales() list as available. 2160f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param acceptLanguageList ordered array of acceptable locales (preferred are listed first) 2161f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @param fallback if non-null, a 1-element array containing a boolean to be set with 2162f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * the fallback status 2163f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @return one of the locales from the ULocale.getAvailableLocales() list, or null if none match 2164f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @stable ICU 3.4 2165f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert */ 21667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale acceptLanguage(ULocale[] acceptLanguageList, boolean[] fallback) { 21677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return acceptLanguage(acceptLanguageList, ULocale.getAvailableLocales(), 21687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert fallback); 21697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 21717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 21727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Package local method used for parsing Accept-Language string 21737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 21742d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert static ULocale[] parseAcceptLanguage(String acceptLanguage, boolean isLenient) 2175f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert throws ParseException { 21767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert class ULocaleAcceptLanguageQ implements Comparable<ULocaleAcceptLanguageQ> { 21777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private double q; 21787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private double serial; 21797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ULocaleAcceptLanguageQ(double theq, int theserial) { 21807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert q = theq; 21817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert serial = theserial; 21827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21832d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 21847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public int compareTo(ULocaleAcceptLanguageQ other) { 21857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (q > other.q) { // reverse - to sort in descending order 21867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return -1; 21877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (q < other.q) { 21887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 1; 21897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (serial < other.serial) { 21917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return -1; 21927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (serial > other.serial) { 21937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 1; 21947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 21957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return 0; // same object 21967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 21997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 22007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // parse out the acceptLanguage into an array 22012d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert TreeMap<ULocaleAcceptLanguageQ, ULocale> map = 2202f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert new TreeMap<ULocaleAcceptLanguageQ, ULocale>(); 22037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder languageRangeBuf = new StringBuilder(); 22047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder qvalBuf = new StringBuilder(); 22057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int state = 0; 22067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert acceptLanguage += ","; // append comma to simplify the parsing code 22077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int n; 22087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean subTag = false; 22097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean q1 = false; 22107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (n = 0; n < acceptLanguage.length(); n++) { 22117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean gotLanguageQ = false; 22127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert char c = acceptLanguage.charAt(n); 22137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (state) { 22147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 0: // before language-range start 22157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) { 22167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // in language-range 22177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert languageRangeBuf.append(c); 22187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 1; 22197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert subTag = false; 22207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == '*') { 22217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert languageRangeBuf.append(c); 22227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 2; 22237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c != ' ' && c != '\t') { 22247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid character 22257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 22267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 22287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 1: // in language-range 22297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')) { 22307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert languageRangeBuf.append(c); 22317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == '-') { 22327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert subTag = true; 22337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert languageRangeBuf.append(c); 22347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == '_') { 22357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isLenient) { 22367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert subTag = true; 22377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert languageRangeBuf.append(c); 22387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 22397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 22407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if ('0' <= c && c <= '9') { 22427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (subTag) { 22437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert languageRangeBuf.append(c); 22447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 22457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // DIGIT is allowed only in language sub tag 22467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 22477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == ',') { 22497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // language-q end 22507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gotLanguageQ = true; 22517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == ' ' || c == '\t') { 22527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // language-range end 22537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 3; 22547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == ';') { 22557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // before q 22567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 4; 22577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 22587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid character for language-range 22597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 22607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 22627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 2: // saw wild card range 22637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (c == ',') { 22647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // language-q end 22657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gotLanguageQ = true; 22667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == ' ' || c == '\t') { 22677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // language-range end 22687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 3; 22697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == ';') { 22707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // before q 22717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 4; 22727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 22737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid 22747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 22757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 22777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 3: // language-range end 22787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (c == ',') { 22797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // language-q end 22807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gotLanguageQ = true; 22817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == ';') { 22827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // before q 22837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state =4; 22847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c != ' ' && c != '\t') { 22857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid 22867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 22877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 22897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 4: // before q 22907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (c == 'q') { 22917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // before equal 22927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 5; 22937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c != ' ' && c != '\t') { 22947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid 22957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 22967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 22977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 22987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 5: // before equal 22997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (c == '=') { 23007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // before q value 23017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 6; 23027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c != ' ' && c != '\t') { 23037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid 23047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 23057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 23077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 6: // before q value 23087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (c == '0') { 23097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // q value start with 0 23107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert q1 = false; 23117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert qvalBuf.append(c); 23127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 7; 23137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == '1') { 23147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // q value start with 1 23157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert qvalBuf.append(c); 23167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 7; 23177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == '.') { 23187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isLenient) { 23197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert qvalBuf.append(c); 23207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 8; 23217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 23227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 23237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c != ' ' && c != '\t') { 23257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid 23267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 23277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 23297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 7: // q value start 23307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (c == '.') { 23317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // before q value fraction part 23327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert qvalBuf.append(c); 23337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 8; 23347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == ',') { 23357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // language-q end 23367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gotLanguageQ = true; 23377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == ' ' || c == '\t') { 23387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // after q value 23397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 10; 23407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 23417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid 23427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 23437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 23457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 8: // before q value fraction part 23462d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if ('0' <= c && c <= '9') { 23477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (q1 && c != '0' && !isLenient) { 23487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if q value starts with 1, the fraction part must be 0 23497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 23507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 23517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // in q value fraction part 23527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert qvalBuf.append(c); 23537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 9; 23547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 23567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid 23577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 23587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 23607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 9: // in q value fraction part 23617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if ('0' <= c && c <= '9') { 23627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (q1 && c != '0') { 23637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // if q value starts with 1, the fraction part must be 0 23647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 23657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 23667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert qvalBuf.append(c); 23677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == ',') { 23697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // language-q end 23707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gotLanguageQ = true; 23717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c == ' ' || c == '\t') { 23727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // after q value 23737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 10; 23747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 23757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid 23767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 23777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 23797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case 10: // after q value 23807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (c == ',') { 23817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // language-q end 23827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert gotLanguageQ = true; 23837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (c != ' ' && c != '\t') { 23847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // invalid 23857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = -1; 23867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 23887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (state == -1) { 23907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // error state 23917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new ParseException("Invalid Accept-Language", n); 23927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 23937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (gotLanguageQ) { 23947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert double q = 1.0; 23957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (qvalBuf.length() != 0) { 23967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 23977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert q = Double.parseDouble(qvalBuf.toString()); 23987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (NumberFormatException nfe) { 23997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Already validated, so it should never happen 24007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert q = 1.0; 24017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (q > 1.0) { 24037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert q = 1.0; 24047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (languageRangeBuf.charAt(0) != '*') { 24077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int serial = map.size(); 24087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocaleAcceptLanguageQ entry = new ULocaleAcceptLanguageQ(q, serial); 24097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // sort in reverse order.. 1.0, 0.9, 0.8 .. etc 24107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert map.put(entry, new ULocale(canonicalize(languageRangeBuf.toString()))); 24117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 24137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // reset buffer and parse state 24147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert languageRangeBuf.setLength(0); 24157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert qvalBuf.setLength(0); 24167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert state = 0; 24177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (state != 0) { 24207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Well, the parser should handle all cases. So just in case. 24217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new ParseException("Invalid AcceptlLanguage", n); 24227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 24247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // pull out the map 24257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale acceptList[] = map.values().toArray(new ULocale[map.size()]); 24267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return acceptList; 24277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 24297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String UNDEFINED_LANGUAGE = "und"; 24307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String UNDEFINED_SCRIPT = "Zzzz"; 24317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String UNDEFINED_REGION = "ZZ"; 24327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 24337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 24347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Adds the likely subtags for a provided locale ID, per the algorithm 24357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * described in the following CLDR technical report: 24367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * http://www.unicode.org/reports/tr35/#Likely_Subtags 24387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If the provided ULocale instance is already in the maximal form, or there is no 24407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * data available available for maximization, it will be returned. For example, 24417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "und-Zzzz" cannot be maximized, since there is no reasonable maximization. 24427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Otherwise, a new ULocale instance with the maximal form is returned. 24437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Examples: 24457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "en" maximizes to "en_Latn_US" 24477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "de" maximizes to "de_Latn_US" 24497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "sr" maximizes to "sr_Cyrl_RS" 24517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "sh" maximizes to "sr_Latn_RS" (Note this will not reverse.) 24537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "zh_Hani" maximizes to "zh_Hans_CN" (Note this will not reverse.) 24557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param loc The ULocale to maximize 24577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The maximized ULocale instance. 24587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.0 24597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 24607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale addLikelySubtags(ULocale loc) { 24617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] tags = new String[3]; 24627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String trailing = null; 24637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 24647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int trailingIndex = parseTagString( 2465f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert loc.localeID, 2466f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tags); 24677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 24687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (trailingIndex < loc.localeID.length()) { 24697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert trailing = loc.localeID.substring(trailingIndex); 24707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 24727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String newLocaleID = 2473f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert createLikelySubtagsString( 2474f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tags[0], 2475f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tags[1], 2476f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tags[2], 2477f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert trailing); 24787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 24797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return newLocaleID == null ? loc : new ULocale(newLocaleID); 24807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 24817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 24827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 24837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Minimizes the subtags for a provided locale ID, per the algorithm described 24847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in the following CLDR technical report:<blockquote> 24857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <a href="http://www.unicode.org/reports/tr35/#Likely_Subtags" 24877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert *>http://www.unicode.org/reports/tr35/#Likely_Subtags</a></blockquote> 24887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If the provided ULocale instance is already in the minimal form, or there 24907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is no data available for minimization, it will be returned. Since the 24917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * minimization algorithm relies on proper maximization, see the comments 24927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for addLikelySubtags for reasons why there might not be any data. 24937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Examples:<pre> 24957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "en_Latn_US" minimizes to "en" 24977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 24987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "de_Latn_US" minimizes to "de" 24997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 25007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "sr_Cyrl_RS" minimizes to "sr" 25017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 25027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "zh_Hant_TW" minimizes to "zh_TW" (The region is preferred to the 25037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * script, and minimizing to "zh" would imply "zh_Hans_CN".) </pre> 25047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 25057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param loc The ULocale to minimize 25067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The minimized ULocale instance. 25077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.0 25087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 25097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale minimizeSubtags(ULocale loc) { 25102d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return minimizeSubtags(loc, Minimize.FAVOR_REGION); 25112d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 2512f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 25132d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert /** 25142d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * Options for minimizeSubtags. 2515f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @internal 2516f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @deprecated This API is ICU internal only. 25172d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert */ 2518f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert @Deprecated 25192d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert public enum Minimize { 25202d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert /** 2521f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * Favor including the script, when either the region <b>or</b> the script could be suppressed, but not both. 2522f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @internal 2523f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @deprecated This API is ICU internal only. 2524f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert */ 2525f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert @Deprecated 25262d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert FAVOR_SCRIPT, 2527f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert /** 2528f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * Favor including the region, when either the region <b>or</b> the script could be suppressed, but not both. 2529f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @internal 2530f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @deprecated This API is ICU internal only. 2531f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert */ 2532f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert @Deprecated 25332d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert FAVOR_REGION 25342d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 25352d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 25362d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert /** 25372d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * {@icu} Minimizes the subtags for a provided locale ID, per the algorithm described 25382d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * in the following CLDR technical report:<blockquote> 25392d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 25402d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * <a href="http://www.unicode.org/reports/tr35/#Likely_Subtags" 25412d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert *>http://www.unicode.org/reports/tr35/#Likely_Subtags</a></blockquote> 25422d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 25432d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * If the provided ULocale instance is already in the minimal form, or there 25442d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * is no data available for minimization, it will be returned. Since the 25452d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * minimization algorithm relies on proper maximization, see the comments 25462d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * for addLikelySubtags for reasons why there might not be any data. 25472d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 25482d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * Examples:<pre> 25492d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 25502d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * "en_Latn_US" minimizes to "en" 25512d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 25522d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * "de_Latn_US" minimizes to "de" 25532d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 25542d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * "sr_Cyrl_RS" minimizes to "sr" 25552d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 25562d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * "zh_Hant_TW" minimizes to "zh_TW" if fieldToFavor == {@link Minimize#FAVOR_REGION} 25572d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * "zh_Hant_TW" minimizes to "zh_Hant" if fieldToFavor == {@link Minimize#FAVOR_SCRIPT} 25582d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * </pre> 25592d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * The fieldToFavor only has an effect if either the region or the script could be suppressed, but not both. 25602d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * @param loc The ULocale to minimize 25612d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * @param fieldToFavor Indicate which should be preferred, when either the region <b>or</b> the script could be suppressed, but not both. 25622d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * @return The minimized ULocale instance. 2563f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @internal 2564f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert * @deprecated This API is ICU internal only. 25652d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert */ 2566f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert @Deprecated 25672d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert public static ULocale minimizeSubtags(ULocale loc, Minimize fieldToFavor) { 25687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] tags = new String[3]; 25697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 25707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int trailingIndex = parseTagString( 25717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert loc.localeID, 25727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tags); 25737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 25747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String originalLang = tags[0]; 25757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String originalScript = tags[1]; 25767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String originalRegion = tags[2]; 25777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String originalTrailing = null; 25787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 25797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (trailingIndex < loc.localeID.length()) { 25807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 25817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a String that contains everything 25827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * after the language, script, and region. 25837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 25847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert originalTrailing = loc.localeID.substring(trailingIndex); 25857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 25867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 25877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 25887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * First, we need to first get the maximization 25897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * by adding any likely subtags. 25907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 25917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String maximizedLocaleID = 2592f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert createLikelySubtagsString( 2593f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert originalLang, 2594f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert originalScript, 2595f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert originalRegion, 2596f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null); 25977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 25987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 25997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If maximization fails, there's nothing 26007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * we can do. 26017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 26027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isEmptyString(maximizedLocaleID)) { 26037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return loc; 26047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 26057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else { 26067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 26077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Start first with just the language. 26087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 26097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tag = 2610f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert createLikelySubtagsString( 2611f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert originalLang, 2612f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 2613f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 2614f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null); 26157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 26167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (tag.equals(maximizedLocaleID)) { 26177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String newLocaleID = 2618f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert createTagString( 2619f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert originalLang, 2620f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 2621f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 2622f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert originalTrailing); 26237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 26247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new ULocale(newLocaleID); 26257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 26267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 26277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 26287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 26297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Next, try the language and region. 26307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 26312d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (fieldToFavor == Minimize.FAVOR_REGION) { 26322d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (originalRegion.length() != 0) { 26332d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert String tag = 26342d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert createLikelySubtagsString( 26352d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalLang, 26362d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null, 26372d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalRegion, 26382d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null); 26392d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 26402d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (tag.equals(maximizedLocaleID)) { 26412d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert String newLocaleID = 26422d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert createTagString( 26432d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalLang, 26442d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null, 26452d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalRegion, 26462d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalTrailing); 26472d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 26482d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return new ULocale(newLocaleID); 26492d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 26502d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 26512d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (originalScript.length() != 0){ 26522d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert String tag = 26532d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert createLikelySubtagsString( 26542d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalLang, 26552d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalScript, 26562d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null, 26572d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null); 26582d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 26592d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (tag.equals(maximizedLocaleID)) { 26602d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert String newLocaleID = 26612d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert createTagString( 26622d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalLang, 26632d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalScript, 26642d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null, 26652d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalTrailing); 26662d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 26672d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return new ULocale(newLocaleID); 26682d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 26692d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 26702d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } else { // FAVOR_SCRIPT, so 26712d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (originalScript.length() != 0){ 26722d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert String tag = 26732d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert createLikelySubtagsString( 26742d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalLang, 26752d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalScript, 26762d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null, 26772d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null); 26782d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 26792d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (tag.equals(maximizedLocaleID)) { 26802d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert String newLocaleID = 26812d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert createTagString( 26822d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalLang, 26832d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalScript, 26842d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null, 26852d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalTrailing); 26862d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 26872d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return new ULocale(newLocaleID); 26882d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 26892d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 26902d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (originalRegion.length() != 0) { 26912d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert String tag = 26922d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert createLikelySubtagsString( 26932d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalLang, 26942d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null, 26952d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalRegion, 26962d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null); 26972d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 26982d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert if (tag.equals(maximizedLocaleID)) { 26992d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert String newLocaleID = 27002d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert createTagString( 27012d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalLang, 27022d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert null, 27032d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalRegion, 27042d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert originalTrailing); 27052d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert 27062d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert return new ULocale(newLocaleID); 27072d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 27082d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 27092d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert } 27107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return loc; 27117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 27127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 27137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 27147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * A trivial utility function that checks for a null 27157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * reference or checks the length of the supplied String. 27167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 27177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param string The string to check 27187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 27197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return true if the String is empty, or if the reference is null. 27207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 27217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static boolean isEmptyString(String string) { 2722f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert return string == null || string.length() == 0; 27237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 27247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 27257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 27267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Append a tag to a StringBuilder, adding the separator if necessary.The tag must 27277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * not be a zero-length string. 27287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 27297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param tag The tag to add. 27307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param buffer The output buffer. 27317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 27327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static void appendTag(String tag, StringBuilder buffer) { 27337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (buffer.length() != 0) { 27347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buffer.append(UNDERSCORE); 27357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 27367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 27377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buffer.append(tag); 27387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 27397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 27407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 27417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a tag string from the supplied parameters. The lang, script and region 27427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * parameters may be null references. 27437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 27447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If any of the language, script or region parameters are empty, and the alternateTags 27457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * parameter is not null, it will be parsed for potential language, script and region tags 27467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * to be used when constructing the new tag. If the alternateTags parameter is null, or 27477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * it contains no language tag, the default tag for the unknown language is used. 27487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 27497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param lang The language tag to use. 27507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param script The script tag to use. 27517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param region The region tag to use. 27527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param trailing Any trailing data to append to the new tag. 27537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param alternateTags A string containing any alternate tags. 27547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The new tag string. 27557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 27567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String createTagString(String lang, String script, String region, 2757f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert String trailing, String alternateTags) { 27587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 27597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleIDParser parser = null; 27607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean regionAppended = false; 27617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 27627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder tag = new StringBuilder(); 27637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 27647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isEmptyString(lang)) { 27657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTag( 2766f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert lang, 2767f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tag); 27687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 27697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else if (isEmptyString(alternateTags)) { 27707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 27717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Append the value for an unknown language, if 27727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * we found no language. 27737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 27747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTag( 2775f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert UNDEFINED_LANGUAGE, 2776f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tag); 27777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 27787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else { 27797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert parser = new LocaleIDParser(alternateTags); 27807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 27817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String alternateLang = parser.getLanguage(); 27827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 27837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 27847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Append the value for an unknown language, if 27857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * we found no language. 27867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 27877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTag( 2788f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert !isEmptyString(alternateLang) ? alternateLang : UNDEFINED_LANGUAGE, 2789f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tag); 27907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 27917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 27927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isEmptyString(script)) { 27937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTag( 2794f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert script, 2795f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tag); 27967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 27977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else if (!isEmptyString(alternateTags)) { 27987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 27997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Parse the alternateTags string for the script. 28007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 28017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (parser == null) { 28027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert parser = new LocaleIDParser(alternateTags); 28037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String alternateScript = parser.getScript(); 28067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isEmptyString(alternateScript)) { 28087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTag( 2809f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert alternateScript, 2810f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tag); 28117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isEmptyString(region)) { 28157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTag( 2816f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert region, 2817f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tag); 28187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert regionAppended = true; 28207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else if (!isEmptyString(alternateTags)) { 28227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 28237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Parse the alternateTags string for the region. 28247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 28257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (parser == null) { 28267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert parser = new LocaleIDParser(alternateTags); 28277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String alternateRegion = parser.getCountry(); 28307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isEmptyString(alternateRegion)) { 28327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert appendTag( 2833f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert alternateRegion, 2834f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert tag); 28357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert regionAppended = true; 28377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (trailing != null && trailing.length() > 1) { 28417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 28427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The current ICU format expects two underscores 28437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * will separate the variant from the preceeding 28447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * parts of the tag, if there is no region. 28457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 28467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int separators = 0; 28477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (trailing.charAt(0) == UNDERSCORE) { 28497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (trailing.charAt(1) == UNDERSCORE) { 28507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert separators = 2; 28517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 2852f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert } 2853f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert else { 2854f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert separators = 1; 2855f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert } 28567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (regionAppended) { 28587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 28597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If we appended a region, we may need to strip 28607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the extra separator from the variant portion. 28617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 28627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (separators == 2) { 28637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tag.append(trailing.substring(1)); 28647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else { 28667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tag.append(trailing); 28677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else { 28707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 28717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If we did not append a region, we may need to add 28727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * an extra separator to the variant portion. 28737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 28747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (separators == 1) { 28757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tag.append(UNDERSCORE); 28767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tag.append(trailing); 28787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return tag.toString(); 28827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 28857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Create a tag string from the supplied parameters. The lang, script and region 28867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * parameters may be null references.If the lang parameter is an empty string, the 28877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * default value for an unknown language is written to the output buffer. 28887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 28897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param lang The language tag to use. 28907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param script The script tag to use. 28917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param region The region tag to use. 28927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param trailing Any trailing data to append to the new tag. 28937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The new String. 28947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 28957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static String createTagString(String lang, String script, String region, String trailing) { 28967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return createTagString(lang, script, region, trailing, null); 28977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 28987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 28997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 29007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Parse the language, script, and region subtags from a tag string, and return the results. 29017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 29027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This function does not return the canonical strings for the unknown script and region. 29037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 29047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param localeID The locale ID to parse. 29057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param tags An array of three String references to return the subtag strings. 29067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The number of chars of the localeID parameter consumed. 29077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 29087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static int parseTagString(String localeID, String tags[]) { 29097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleIDParser parser = new LocaleIDParser(localeID); 29107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String lang = parser.getLanguage(); 29127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String script = parser.getScript(); 29137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String region = parser.getCountry(); 29147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (isEmptyString(lang)) { 29167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tags[0] = UNDEFINED_LANGUAGE; 29177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else { 29197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tags[0] = lang; 29207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (script.equals(UNDEFINED_SCRIPT)) { 29237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tags[1] = ""; 29247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else { 29267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tags[1] = script; 29277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (region.equals(UNDEFINED_REGION)) { 29307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tags[2] = ""; 29317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else { 29337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tags[2] = region; 29347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 29377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Search for the variant. If there is one, then return the index of 29387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the preceeding separator. 29397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * If there's no variant, search for the keyword delimiter, 29407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and return its index. Otherwise, return the length of the 29417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * string. 29427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 29437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * $TOTO(dbertoni) we need to take into account that we might 29447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * find a part of the language as the variant, since it can 29457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * can have a variant portion that is long enough to contain 29467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the same characters as the variant. 29477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 29487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String variant = parser.getVariant(); 29497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isEmptyString(variant)){ 29517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int index = localeID.indexOf(variant); 29527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return index > 0 ? index - 1 : index; 29557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else 29577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 29587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert int index = localeID.indexOf('@'); 29597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return index == -1 ? localeID.length() : index; 29617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String lookupLikelySubtags(String localeId) { 29657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UResourceBundle bundle = 2966f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert UResourceBundle.getBundleInstance( 29672d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert ICUData.ICU_BASE_NAME, "likelySubtags"); 29687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 29697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return bundle.getString(localeId); 29707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert catch(MissingResourceException e) { 29727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 29737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static String createLikelySubtagsString(String lang, String script, String region, 2977f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert String variants) { 29787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 29807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Try the language with the script and region first. 29817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 29827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isEmptyString(script) && !isEmptyString(region)) { 29837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String searchTag = 2985f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert createTagString( 2986f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert lang, 2987f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert script, 2988f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert region, 2989f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null); 29907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String likelySubtags = lookupLikelySubtags(searchTag); 29927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 29937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 29947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (likelySubtags == null) { 29957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (likelySubtags2 != null) { 29967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert System.err.println("Tag mismatch: \"(null)\" \"" + likelySubtags2 + "\""); 29977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 29997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else if (likelySubtags2 == null) { 30007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert System.err.println("Tag mismatch: \"" + likelySubtags + "\" \"(null)\""); 30017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 30027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert else if (!likelySubtags.equals(likelySubtags2)) { 30032d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert System.err.println("Tag mismatch: \"" + likelySubtags + "\" \"" + likelySubtags2 30047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert + "\""); 30057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3006f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert */ 30077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (likelySubtags != null) { 30087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Always use the language tag from the 30097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // maximal string, since it may be more 30107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // specific than the one provided. 30117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return createTagString( 3012f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3013f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3014f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3015f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert variants, 3016f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert likelySubtags); 30177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 30187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 30197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 30217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Try the language with just the script. 30227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 30237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isEmptyString(script)) { 30247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String searchTag = 3026f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert createTagString( 3027f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert lang, 3028f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert script, 3029f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3030f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null); 30317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String likelySubtags = lookupLikelySubtags(searchTag); 30337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (likelySubtags != null) { 30347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Always use the language tag from the 30357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // maximal string, since it may be more 30367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // specific than the one provided. 30377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return createTagString( 3038f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3039f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3040f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert region, 3041f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert variants, 3042f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert likelySubtags); 30437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 30447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 30457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 30477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Try the language with just the region. 30487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 30497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!isEmptyString(region)) { 30507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String searchTag = 3052f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert createTagString( 3053f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert lang, 3054f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3055f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert region, 3056f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null); 30577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String likelySubtags = lookupLikelySubtags(searchTag); 30597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (likelySubtags != null) { 30617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Always use the language tag from the 30627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // maximal string, since it may be more 30637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // specific than the one provided. 30647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return createTagString( 3065f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3066f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert script, 3067f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3068f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert variants, 3069f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert likelySubtags); 30707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 30717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 30727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 30747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Finally, try just the language. 30757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert **/ 30767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { 30777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String searchTag = 3078f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert createTagString( 3079f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert lang, 3080f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3081f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3082f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null); 30837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String likelySubtags = lookupLikelySubtags(searchTag); 30857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (likelySubtags != null) { 30877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Always use the language tag from the 30887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // maximal string, since it may be more 30897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // specific than the one provided. 30907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return createTagString( 3091f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert null, 3092f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert script, 3093f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert region, 3094f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert variants, 3095f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert likelySubtags); 30967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 30977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 30987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 30997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return null; 31007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 31017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 31027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // -------------------------------- 31037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // BCP47/OpenJDK APIs 31047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // -------------------------------- 31057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 31067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 31077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The key for the private use locale extension ('x'). 31087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 31097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getExtension(char) 31107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Builder#setExtension(char, String) 31117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 31127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 31137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 31147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final char PRIVATE_USE_EXTENSION = 'x'; 31157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 31167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 31177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The key for Unicode locale extension ('u'). 31187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 31197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #getExtension(char) 31207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see Builder#setExtension(char, String) 31217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 31227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 31237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 31247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final char UNICODE_LOCALE_EXTENSION = 'u'; 31257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 31267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 31277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the extension (or private use) value associated with 31287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the specified key, or null if there is no extension 31297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * associated with the key. To be well-formed, the key must be one 31307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * of <code>[0-9A-Za-z]</code>. Keys are case-insensitive, so 31317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for example 'z' and 'Z' represent the same extension. 31327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 31337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param key the extension key 31347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The extension, or null if this locale defines no 31357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * extension for the specified key. 31367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllegalArgumentException if key is not well-formed 31377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #PRIVATE_USE_EXTENSION 31387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #UNICODE_LOCALE_EXTENSION 31397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 31407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 31417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 31427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getExtension(char key) { 31437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!LocaleExtensions.isValidKey(key)) { 31447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Invalid extension key: " + key); 31457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 31467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return extensions().getExtensionValue(key); 31477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 31487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 31497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 31507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the set of extension keys associated with this locale, or the 31517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * empty set if it has no extensions. The returned set is unmodifiable. 31527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * The keys will all be lower-case. 31537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 31547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the set of extension keys, or the empty set if this locale has 31557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * no extensions 31567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 31577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 31587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Set<Character> getExtensionKeys() { 31597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return extensions().getKeys(); 31607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 31617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 31627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 31637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the set of unicode locale attributes associated with 31647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * this locale, or the empty set if it has no attributes. The 31657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * returned set is unmodifiable. 31667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 31677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The set of attributes. 31687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.6 31697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 31707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Set<String> getUnicodeLocaleAttributes() { 31717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return extensions().getUnicodeLocaleAttributes(); 31727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 31737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 31747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 31757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the Unicode locale type associated with the specified Unicode locale key 31767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * for this locale. Returns the empty string for keys that are defined with no type. 31777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns null if the key is not defined. Keys are case-insensitive. The key must 31787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * be two alphanumeric characters ([0-9a-zA-Z]), or an IllegalArgumentException is 31797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * thrown. 31807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 31817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param key the Unicode locale key 31827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The Unicode locale type associated with the key, or null if the 31837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale does not define the key. 31847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllegalArgumentException if the key is not well-formed 31857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws NullPointerException if <code>key</code> is null 31862d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 31877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 31887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 31897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String getUnicodeLocaleType(String key) { 31907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!LocaleExtensions.isValidUnicodeLocaleKey(key)) { 31917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllegalArgumentException("Invalid Unicode locale key: " + key); 31927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 31937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return extensions().getUnicodeLocaleType(key); 31947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 31957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 31967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 31977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns the set of Unicode locale keys defined by this locale, or the empty set if 31987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * this locale has none. The returned set is immutable. Keys are all lower case. 31997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 32007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The set of Unicode locale keys, or the empty set if this locale has 32017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * no Unicode locale keywords. 32022d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 32037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 32047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 32057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Set<String> getUnicodeLocaleKeys() { 32067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return extensions().getUnicodeLocaleKeys(); 32077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 32087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 32097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 32107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a well-formed IETF BCP 47 language tag representing 32117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * this locale. 32127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 32137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>If this <code>ULocale</code> has a language, script, country, or 32147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * variant that does not satisfy the IETF BCP 47 language tag 32157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * syntax requirements, this method handles these fields as 32167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * described below: 32177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 32187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Language:</b> If language is empty, or not well-formed 32197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (for example "a" or "e2"), it will be emitted as "und" (Undetermined). 32207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 32217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Script:</b> If script is not well-formed (for example "12" 32227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or "Latin"), it will be omitted. 32232d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 32247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Country:</b> If country is not well-formed (for example "12" 32257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or "USA"), it will be omitted. 32267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 32277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Variant:</b> If variant <b>is</b> well-formed, each sub-segment 32287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (delimited by '-' or '_') is emitted as a subtag. Otherwise: 32297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <ul> 32307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 32317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>if all sub-segments match <code>[0-9a-zA-Z]{1,8}</code> 32327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first 32337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ill-formed sub-segment and all following will be appended to 32347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the private use subtag. The first appended subtag will be 32357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "lvariant", followed by the sub-segments in order, separated by 32367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * hyphen. For example, "x-lvariant-WIN", 32377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "Oracle-x-lvariant-JDK-Standard-Edition". 32387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 32397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>if any sub-segment does not match 32407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>[0-9a-zA-Z]{1,8}</code>, the variant will be truncated 32417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and the problematic sub-segment and all following sub-segments 32427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * will be omitted. If the remainder is non-empty, it will be 32437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * emitted as a private use subtag as above (even if the remainder 32447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * turns out to be well-formed). For example, 32457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "Solaris_isjustthecoolestthing" is emitted as 32467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "x-lvariant-Solaris", not as "solaris".</li></ul> 32477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 32487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Note:</b> Although the language tag created by this 32497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * method is well-formed (satisfies the syntax requirements 32507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * defined by the IETF BCP 47 specification), it is not 32517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * necessarily a valid BCP 47 language tag. For example, 32527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 32537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * new Locale("xx", "YY").toLanguageTag();</pre> 32542d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 32557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * will return "xx-YY", but the language subtag "xx" and the 32567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * region subtag "YY" are invalid because they are not registered 32577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in the IANA Language Subtag Registry. 32587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 32597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return a BCP47 language tag representing the locale 32607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #forLanguageTag(String) 32617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 32627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 32637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 32647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String toLanguageTag() { 32657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert BaseLocale base = base(); 32667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleExtensions exts = extensions(); 32677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 32687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (base.getVariant().equalsIgnoreCase("POSIX")) { 32697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // special handling for variant POSIX 32707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert base = BaseLocale.getInstance(base.getLanguage(), base.getScript(), base.getRegion(), ""); 32717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (exts.getUnicodeLocaleType("va") == null) { 32727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // add va-posix 32737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert InternalLocaleBuilder ilocbld = new InternalLocaleBuilder(); 32747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 32757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ilocbld.setLocale(BaseLocale.ROOT, exts); 32767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ilocbld.setUnicodeLocaleKeyword("va", "posix"); 32777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert exts = ilocbld.getLocaleExtensions(); 32787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 32797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // this should not happen 32807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new RuntimeException(e); 32817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 32827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 32837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 32847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 32857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LanguageTag tag = LanguageTag.parseLocale(base, exts); 32867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 32877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder buf = new StringBuilder(); 32887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String subtag = tag.getLanguage(); 32897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (subtag.length() > 0) { 32907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.canonicalizeLanguage(subtag)); 32917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 3292f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 32937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert subtag = tag.getScript(); 32947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (subtag.length() > 0) { 32957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.SEP); 32967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.canonicalizeScript(subtag)); 32977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 32987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 32997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert subtag = tag.getRegion(); 33007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (subtag.length() > 0) { 33017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.SEP); 33027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.canonicalizeRegion(subtag)); 33037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 33047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 33057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert List<String>subtags = tag.getVariants(); 33067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String s : subtags) { 33077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.SEP); 33087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.canonicalizeVariant(s)); 33097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 33107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 33117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert subtags = tag.getExtensions(); 33127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String s : subtags) { 33137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.SEP); 33147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.canonicalizeExtension(s)); 33157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 33167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 33177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert subtag = tag.getPrivateuse(); 33187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (subtag.length() > 0) { 33197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (buf.length() > 0) { 33207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.SEP); 33217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 33227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.PRIVATEUSE).append(LanguageTag.SEP); 33237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(LanguageTag.canonicalizePrivateuse(subtag)); 33247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 33257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 33267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return buf.toString(); 33277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 33287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 33297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 33307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns a locale for the specified IETF BCP 47 language tag string. 33317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>If the specified language tag contains any ill-formed subtags, 33337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the first such subtag and all following subtags are ignored. Compare 33347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * to {@link ULocale.Builder#setLanguageTag} which throws an exception 33357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in this case. 33367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33379e281ba4837cba4a1cf9523d6f8b0621b150063dScott Russell * <p>The following <b>conversions</b> are performed: 33389e281ba4837cba4a1cf9523d6f8b0621b150063dScott Russell * <ul> 33397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>The language code "und" is mapped to language "". 33417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>The portion of a private use subtag prefixed by "lvariant", 33437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * if any, is removed and appended to the variant field in the 33447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * result locale (without case normalization). If it is then 33457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * empty, the private use subtag is discarded: 33467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 33487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ULocale loc; 33497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * loc = ULocale.forLanguageTag("en-US-x-lvariant-icu4j); 33507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * loc.getVariant(); // returns "ICU4J" 33517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * loc.getExtension('x'); // returns null 33527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * loc = Locale.forLanguageTag("de-icu4j-x-URP-lvariant-Abc-Def"); 33547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * loc.getVariant(); // returns "ICU4J_ABC_DEF" 33557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * loc.getExtension('x'); // returns "urp" 33567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 33577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>When the languageTag argument contains an extlang subtag, 33597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the first such subtag is used as the language, and the primary 33607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * language subtag and other extlang subtags are ignored: 33617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 33637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ULocale.forLanguageTag("ar-aao").getLanguage(); // returns "aao" 33647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ULocale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US" 33657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 33667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <li>Case is normalized. Language is normalized to lower case, 33687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * script to title case, country to upper case, variant to upper case, 33697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and extensions to lower case. 33707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33719e281ba4837cba4a1cf9523d6f8b0621b150063dScott Russell * </ul> 33729e281ba4837cba4a1cf9523d6f8b0621b150063dScott Russell * 33737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>This implements the 'Language-Tag' production of BCP47, and 33747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * so supports grandfathered (regular and irregular) as well as 33757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * private use language tags. Stand alone private use tags are 33767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * represented as empty language and extension 'x-whatever', 33777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and grandfathered tags are converted to their canonical replacements 33782d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * where they exist. 33797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Grandfathered tags with canonical replacements are as follows: 33817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 33827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <table> 33837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tbody align="center"> 33847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><th>grandfathered tag</th><th> </th><th>modern replacement</th></tr> 33857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>art-lojban</td><td> </td><td>jbo</td></tr> 33867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-ami</td><td> </td><td>ami</td></tr> 33877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-bnn</td><td> </td><td>bnn</td></tr> 33887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-hak</td><td> </td><td>hak</td></tr> 33897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-klingon</td><td> </td><td>tlh</td></tr> 33907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-lux</td><td> </td><td>lb</td></tr> 33917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-navajo</td><td> </td><td>nv</td></tr> 33927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-pwn</td><td> </td><td>pwn</td></tr> 33937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-tao</td><td> </td><td>tao</td></tr> 33947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-tay</td><td> </td><td>tay</td></tr> 33957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-tsu</td><td> </td><td>tsu</td></tr> 33967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>no-bok</td><td> </td><td>nb</td></tr> 33977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>no-nyn</td><td> </td><td>nn</td></tr> 33987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>sgn-BE-FR</td><td> </td><td>sfb</td></tr> 33997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>sgn-BE-NL</td><td> </td><td>vgt</td></tr> 34007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>sgn-CH-DE</td><td> </td><td>sgg</td></tr> 34017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>zh-guoyu</td><td> </td><td>cmn</td></tr> 34027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>zh-hakka</td><td> </td><td>hak</td></tr> 34037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>zh-min-nan</td><td> </td><td>nan</td></tr> 34047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>zh-xiang</td><td> </td><td>hsn</td></tr> 34057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </tbody> 34067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </table> 34077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 34087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Grandfathered tags with no modern replacement will be 34097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * converted as follows: 34107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 34117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <table> 34127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tbody align="center"> 34137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><th>grandfathered tag</th><th> </th><th>converts to</th></tr> 34147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>cel-gaulish</td><td> </td><td>xtg-x-cel-gaulish</td></tr> 34157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>en-GB-oed</td><td> </td><td>en-GB-x-oed</td></tr> 34167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-default</td><td> </td><td>en-x-i-default</td></tr> 34177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-enochian</td><td> </td><td>und-x-i-enochian</td></tr> 34187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>i-mingo</td><td> </td><td>see-x-i-mingo</td></tr> 34197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <tr><td>zh-min</td><td> </td><td>nan-x-zh-min</td></tr> 34207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </tbody> 34217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </table> 34227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 34237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>For a list of all grandfathered tags, see the 34247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * IANA Language Subtag Registry (search for "Type: grandfathered"). 34257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 34267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Note</b>: there is no guarantee that <code>toLanguageTag</code> 34277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and <code>forLanguageTag</code> will round-trip. 34287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 34297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param languageTag the language tag 34307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return The locale that best represents the language tag. 34317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws NullPointerException if <code>languageTag</code> is <code>null</code> 34327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #toLanguageTag() 34337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see ULocale.Builder#setLanguageTag(String) 34347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 34357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 34367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 34377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale forLanguageTag(String languageTag) { 34387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LanguageTag tag = LanguageTag.parse(languageTag, null); 34397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert InternalLocaleBuilder bldr = new InternalLocaleBuilder(); 34407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bldr.setLanguageTag(tag); 34417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getInstance(bldr.getBaseLocale(), bldr.getLocaleExtensions()); 34427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 34437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 34447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 34457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Converts the specified keyword (legacy key, or BCP 47 Unicode locale 34467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * extension key) to the equivalent BCP 47 Unicode locale extension key. 34477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For example, BCP 47 Unicode locale extension key "co" is returned for 34487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the input keyword "collation". 34497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 34507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * When the specified keyword is unknown, but satisfies the BCP syntax, 34517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * then the lower-case version of the input keyword will be returned. 34527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For example, 34537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>toUnicodeLocaleKey("ZZ")</code> returns "zz". 34542d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 34557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the input locale keyword (either legacy key 34567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * such as "collation" or BCP 47 Unicode locale extension 34577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * key such as "co"). 34587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the well-formed BCP 47 Unicode locale extension key, 34597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or null if the specified locale keyword cannot be mapped 34602d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * to a well-formed BCP 47 Unicode locale extension key. 34617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #toLegacyKey(String) 3462bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * @stable ICU 54 34637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 34647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String toUnicodeLocaleKey(String keyword) { 34657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String bcpKey = KeyTypeData.toBcpKey(keyword); 34667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (bcpKey == null && UnicodeLocaleExtension.isKey(keyword)) { 34677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // unknown keyword, but syntax is fine.. 34687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bcpKey = AsciiUtil.toLowerString(keyword); 34697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 34707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return bcpKey; 34717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 34727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 34737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 34747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Converts the specified keyword value (legacy type, or BCP 47 34757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Unicode locale extension type) to the well-formed BCP 47 Unicode locale 34767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * extension type for the specified keyword (category). For example, BCP 47 34777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Unicode locale extension type "phonebk" is returned for the input 34787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword value "phonebook", with the keyword "collation" (or "co"). 34797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 34807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * When the specified keyword is not recognized, but the specified value 34817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * satisfies the syntax of the BCP 47 Unicode locale extension type, 34827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or when the specified keyword allows 'variable' type and the specified 34837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * value satisfies the syntax, the lower-case version of the input value 34847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * will be returned. For example, 34857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>toUnicodeLocaleType("Foo", "Bar")</code> returns "bar", 34867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>toUnicodeLocaleType("variableTop", "00A4")</code> returns "00a4". 34872d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 34887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the locale keyword (either legacy key such as 34897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "collation" or BCP 47 Unicode locale extension 34907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * key such as "co"). 34917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param value the locale keyword value (either legacy type 34927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * such as "phonebook" or BCP 47 Unicode locale extension 34937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * type such as "phonebk"). 34947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the well-formed BCP47 Unicode locale extension type, 34957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or null if the locale keyword value cannot be mapped to 34967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * a well-formed BCP 47 Unicode locale extension type. 34977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #toLegacyType(String, String) 3498bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * @stable ICU 54 34997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 35007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String toUnicodeLocaleType(String keyword, String value) { 35017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String bcpType = KeyTypeData.toBcpType(keyword, value, null, null); 35027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (bcpType == null && UnicodeLocaleExtension.isType(value)) { 35037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // unknown keyword, but syntax is fine.. 35047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert bcpType = AsciiUtil.toLowerString(value); 35057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 35067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return bcpType; 35077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 35087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 35097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 35107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Converts the specified keyword (BCP 47 Unicode locale extension key, or 35117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * legacy key) to the legacy key. For example, legacy key "collation" is 35127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * returned for the input BCP 47 Unicode locale extension key "co". 35132d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert * 35147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the input locale keyword (either BCP 47 Unicode locale 35157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * extension key or legacy key). 35167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the well-formed legacy key, or null if the specified 35177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword cannot be mapped to a well-formed legacy key. 35187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #toUnicodeLocaleKey(String) 3519bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * @stable ICU 54 35207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 35217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String toLegacyKey(String keyword) { 35227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String legacyKey = KeyTypeData.toLegacyKey(keyword); 35237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (legacyKey == null) { 35247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Checks if the specified locale key is well-formed with the legacy locale syntax. 35257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 35267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: 35277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Neither ICU nor LDML/CLDR provides the definition of keyword syntax. 35287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // However, a key should not contain '=' obviously. For now, all existing 35297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // keys are using ASCII alphabetic letters only. We won't add any new key 35307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // that is not compatible with the BCP 47 syntax. Therefore, we assume 35317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // a valid key consist from [0-9a-zA-Z], no symbols. 35327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keyword.matches("[0-9a-zA-Z]+")) { 35337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert legacyKey = AsciiUtil.toLowerString(keyword); 35347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 35357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 35367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return legacyKey; 35377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 35387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 35397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 35407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * {@icu} Converts the specified keyword value (BCP 47 Unicode locale extension type, 35417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or legacy type or type alias) to the canonical legacy type. For example, 35427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the legacy type "phonebook" is returned for the input BCP 47 Unicode 35437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * locale extension type "phonebk" with the keyword "collation" (or "co"). 35447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p> 35457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * When the specified keyword is not recognized, but the specified value 35467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * satisfies the syntax of legacy key, or when the specified keyword 35477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * allows 'variable' type and the specified value satisfies the syntax, 35487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the lower-case version of the input value will be returned. 35497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For example, 35507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>toLegacyType("Foo", "Bar")</code> returns "bar", 35517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>toLegacyType("vt", "00A4")</code> returns "00a4". 35527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 35537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param keyword the locale keyword (either legacy keyword such as 35547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * "collation" or BCP 47 Unicode locale extension 35557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * key such as "co"). 35567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param value the locale keyword value (either BCP 47 Unicode locale 35577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * extension type such as "phonebk" or legacy keyword value 35587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * such as "phonebook"). 35597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return the well-formed legacy type, or null if the specified 35607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * keyword value cannot be mapped to a well-formed legacy 35617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * type. 35627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #toUnicodeLocaleType(String, String) 3563bd1cbb618dcaa1ac6ba7c77dece35cb79593a5d7Fredrik Roubert * @stable ICU 54 35647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 35657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String toLegacyType(String keyword, String value) { 35667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String legacyType = KeyTypeData.toLegacyType(keyword, value, null, null); 35677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (legacyType == null) { 35687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Checks if the specified locale type is well-formed with the legacy locale syntax. 35697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 35707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: 35717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Neither ICU nor LDML/CLDR provides the definition of keyword syntax. 35727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // However, a type should not contain '=' obviously. For now, all existing 35737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // types are using ASCII alphabetic letters with a few symbol letters. We won't 35747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // add any new type that is not compatible with the BCP 47 syntax except timezone 35757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // IDs. For now, we assume a valid type start with [0-9a-zA-Z], but may contain 35767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // '-' '_' '/' in the middle. 35777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (value.matches("[0-9a-zA-Z]+([_/\\-][0-9a-zA-Z]+)*")) { 35787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert legacyType = AsciiUtil.toLowerString(value); 35797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 35807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 35817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return legacyType; 35827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 35837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 35847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 35857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>Builder</code> is used to build instances of <code>ULocale</code> 35867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * from values configured by the setters. Unlike the <code>ULocale</code> 35877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * constructors, the <code>Builder</code> checks if a value configured by a 35887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * setter satisfies the syntax requirements defined by the <code>ULocale</code> 35897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * class. A <code>ULocale</code> object created by a <code>Builder</code> is 35907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * well-formed and can be transformed to a well-formed IETF BCP 47 language tag 35917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * without losing information. 35927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 35937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Note:</b> The <code>ULocale</code> class does not provide any 35947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * syntactic restrictions on variant, while BCP 47 requires each variant 35957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * subtag to be 5 to 8 alphanumerics or a single numeric followed by 3 35967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * alphanumerics. The method <code>setVariant</code> throws 35977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>IllformedLocaleException</code> for a variant that does not satisfy 35987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * this restriction. If it is necessary to support such a variant, use a 35997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ULocale constructor. However, keep in mind that a <code>ULocale</code> 36007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * object created this way might lose the variant information when 36017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * transformed to a BCP 47 language tag. 36027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>The following example shows how to create a <code>Locale</code> object 36047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * with the <code>Builder</code>. 36057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <blockquote> 36067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <pre> 36077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ULocale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build(); 36087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </pre> 36097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * </blockquote> 36107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Builders can be reused; <code>clear()</code> resets all 36127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * fields to their default values. 36137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see ULocale#toLanguageTag() 36157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 36177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 36187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static final class Builder { 36197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 36207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private final InternalLocaleBuilder _locbld; 36217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 36227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 36237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Constructs an empty Builder. The default value of all 36247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * fields, extensions, and private use information is the 36257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * empty string. 36267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 36287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 36297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder() { 36307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld = new InternalLocaleBuilder(); 36317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 36327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 36337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 36347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Resets the <code>Builder</code> to match the provided 36357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>locale</code>. Existing state is discarded. 36367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>All fields of the locale must be well-formed, see {@link Locale}. 36387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Locales with any ill-formed fields cause 36407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>IllformedLocaleException</code> to be thrown. 36417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param locale the locale 36437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return This builder. 36447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllformedLocaleException if <code>locale</code> has 36457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * any ill-formed fields. 36467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws NullPointerException if <code>locale</code> is null. 36477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 36497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 36507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder setLocale(ULocale locale) { 36517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 36527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.setLocale(locale.base(), locale.extensions()); 36537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 36547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); 36557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 36567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 36577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 36587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 36597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 36607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Resets the Builder to match the provided IETF BCP 47 36617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * language tag. Discards the existing state. Null and the 36627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * empty string cause the builder to be reset, like {@link 36637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * #clear}. Grandfathered tags (see {@link 36647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * ULocale#forLanguageTag}) are converted to their canonical 36657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * form before being processed. Otherwise, the language tag 36667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * must be well-formed (see {@link ULocale}) or an exception is 36677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * thrown (unlike <code>ULocale.forLanguageTag</code>, which 36687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * just discards ill-formed and following portions of the 36697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * tag). 36707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param languageTag the language tag 36727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return This builder. 36737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllformedLocaleException if <code>languageTag</code> is ill-formed 36747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see ULocale#forLanguageTag(String) 36757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 36777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 36787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder setLanguageTag(String languageTag) { 36797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ParseStatus sts = new ParseStatus(); 36807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LanguageTag tag = LanguageTag.parse(languageTag, sts); 36817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (sts.isError()) { 36827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex()); 36837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 36847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.setLanguageTag(tag); 36857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 36867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 36877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 36887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 36897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 36907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets the language. If <code>language</code> is the empty string or 36917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * null, the language in this <code>Builder</code> is removed. Otherwise, 36927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the language must be <a href="./Locale.html#def_language">well-formed</a> 36937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or an exception is thrown. 36947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>The typical language value is a two or three-letter language 36967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * code as defined in ISO639. 36977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 36987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param language the language 36997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return This builder. 37007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllformedLocaleException if <code>language</code> is ill-formed 37017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 37037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 37047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder setLanguage(String language) { 37057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 37067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.setLanguage(language); 37077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 37087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); 37097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 37107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 37117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 37127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 37137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 37147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets the script. If <code>script</code> is null or the empty string, 37157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the script in this <code>Builder</code> is removed. 37167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Otherwise, the script must be well-formed or an exception is thrown. 37177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>The typical script value is a four-letter script code as defined by ISO 15924. 37197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param script the script 37217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return This builder. 37227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllformedLocaleException if <code>script</code> is ill-formed 37237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 37257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 37267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder setScript(String script) { 37277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 37287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.setScript(script); 37297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 37307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); 37317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 37327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 37337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 37347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 37357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 37367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets the region. If region is null or the empty string, the region 37377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * in this <code>Builder</code> is removed. Otherwise, 37387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the region must be well-formed or an exception is thrown. 37397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>The typical region value is a two-letter ISO 3166 code or a 37417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * three-digit UN M.49 area code. 37427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>The country value in the <code>Locale</code> created by the 37447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <code>Builder</code> is always normalized to upper case. 37457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param region the region 37477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return This builder. 37487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllformedLocaleException if <code>region</code> is ill-formed 37497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 37517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 37527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder setRegion(String region) { 37537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 37547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.setRegion(region); 37557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 37567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); 37577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 37587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 37597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 37607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 37617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 37627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets the variant. If variant is null or the empty string, the 37637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * variant in this <code>Builder</code> is removed. Otherwise, it 37647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * must consist of one or more well-formed subtags, or an exception is thrown. 37657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Note:</b> This method checks if <code>variant</code> 37677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * satisfies the IETF BCP 47 variant subtag's syntax requirements, 37687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * and normalizes the value to lowercase letters. However, 37697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * the <code>ULocale</code> class does not impose any syntactic 37707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * restriction on variant. To set such a variant, 37717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * use a ULocale constructor. 37727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param variant the variant 37747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return This builder. 37757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllformedLocaleException if <code>variant</code> is ill-formed 37767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 37787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 37797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder setVariant(String variant) { 37807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 37817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.setVariant(variant); 37827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 37837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); 37847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 37857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 37867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 37877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 37887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 37897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets the extension for the given key. If the value is null or the 37907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * empty string, the extension is removed. Otherwise, the extension 37917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * must be well-formed or an exception is thrown. 37927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Note:</b> The key {@link ULocale#UNICODE_LOCALE_EXTENSION 37947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension. 37957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Setting a value for this key replaces any existing Unicode locale key/type 37967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * pairs with those defined in the extension. 37977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 37987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Note:</b> The key {@link ULocale#PRIVATE_USE_EXTENSION 37997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be 38007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * well-formed, the value for this key needs only to have subtags of one to 38017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * eight alphanumeric characters, not two to eight as in the general case. 38027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param key the extension key 38047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param value the extension value 38057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return This builder. 38067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllformedLocaleException if <code>key</code> is illegal 38077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or <code>value</code> is ill-formed 38087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #setUnicodeLocaleKeyword(String, String) 38097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 38117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 38127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder setExtension(char key, String value) { 38137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 38147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.setExtension(key, value); 38157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 38167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); 38177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 38187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 38197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 38207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 38217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 38227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Sets the Unicode locale keyword type for the given key. If the type 38237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is null, the Unicode keyword is removed. Otherwise, the key must be 38247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * non-null and both key and type must be well-formed or an exception 38257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is thrown. 38267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Keys and types are converted to lower case. 38287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p><b>Note</b>:Setting the 'u' extension via {@link #setExtension} 38307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * replaces all Unicode locale keywords with those defined in the 38317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * extension. 38327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param key the Unicode locale key 38347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param type the Unicode locale type 38357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return This builder. 38367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllformedLocaleException if <code>key</code> or <code>type</code> 38377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * is ill-formed 38387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws NullPointerException if <code>key</code> is null 38397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #setExtension(char, String) 38407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 38427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 38437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder setUnicodeLocaleKeyword(String key, String type) { 38447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 38457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.setUnicodeLocaleKeyword(key, type); 38467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 38477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); 38487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 38497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 38507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 38517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 38527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 38537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Adds a unicode locale attribute, if not already present, otherwise 38547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * has no effect. The attribute must not be null and must be well-formed 38557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or an exception is thrown. 38567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param attribute the attribute 38587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return This builder. 38597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws NullPointerException if <code>attribute</code> is null 38607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllformedLocaleException if <code>attribute</code> is ill-formed 38617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #setExtension(char, String) 38627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.6 38647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 38657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder addUnicodeLocaleAttribute(String attribute) { 38667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 38677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.addUnicodeLocaleAttribute(attribute); 38687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 38697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); 38707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 38717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 38727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 38737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 38747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 38757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Removes a unicode locale attribute, if present, otherwise has no 38767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * effect. The attribute must not be null and must be well-formed 38777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * or an exception is thrown. 38787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <p>Attribute comparision for removal is case-insensitive. 38807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @param attribute the attribute 38827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return This builder. 38837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws NullPointerException if <code>attribute</code> is null 38847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @throws IllformedLocaleException if <code>attribute</code> is ill-formed 38857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #setExtension(char, String) 38867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 38877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.6 38887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 38897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder removeUnicodeLocaleAttribute(String attribute) { 38907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 38917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.removeUnicodeLocaleAttribute(attribute); 38927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 38937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex()); 38947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 38957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 38967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 38977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 38987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 38997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Resets the builder to its initial, empty state. 39007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 39017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return this builder 39027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 39037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 39047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 39057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder clear() { 39067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.clear(); 39077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 39087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 39107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 39117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Resets the extensions to their initial, empty state. 39127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Language, script, region and variant are unchanged. 39137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 39147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return this builder 39157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @see #setExtension(char, String) 39167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 39177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.2 39187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 39197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public Builder clearExtensions() { 39207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert _locbld.clearExtensions(); 39217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return this; 39227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 39247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /** 39257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * Returns an instance of <code>ULocale</code> created from the fields set 39267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * on this builder. 39277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 39287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @return a new Locale 39297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 39307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * @stable ICU 4.4 39317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 39327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public ULocale build() { 39337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return getInstance(_locbld.getBaseLocale(), _locbld.getLocaleExtensions()); 39347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 39377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static ULocale getInstance(BaseLocale base, LocaleExtensions exts) { 39387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String id = lscvToID(base.getLanguage(), base.getScript(), base.getRegion(), 39397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert base.getVariant()); 39407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 39417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<Character> extKeys = exts.getKeys(); 39427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!extKeys.isEmpty()) { 39437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // legacy locale ID assume Unicode locale keywords and 39447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // other extensions are at the same level. 39457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // e.g. @a=ext-for-aa;calendar=japanese;m=ext-for-mm;x=priv-use 39467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 39477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert TreeMap<String, String> kwds = new TreeMap<String, String>(); 39487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Character key : extKeys) { 39497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Extension ext = exts.getExtension(key); 39507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (ext instanceof UnicodeLocaleExtension) { 39517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert UnicodeLocaleExtension uext = (UnicodeLocaleExtension)ext; 39527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> ukeys = uext.getUnicodeLocaleKeys(); 39537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String bcpKey : ukeys) { 39547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String bcpType = uext.getUnicodeLocaleType(bcpKey); 39557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // convert to legacy key/type 39567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String lkey = toLegacyKey(bcpKey); 39577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String ltype = toLegacyType(bcpKey, ((bcpType.length() == 0) ? "yes" : bcpType)); // use "yes" as the value of typeless keywords 39587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // special handling for u-va-posix, since this is a variant, not a keyword 39597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (lkey.equals("va") && ltype.equals("posix") && base.getVariant().length() == 0) { 39607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert id = id + "_POSIX"; 39617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 39627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert kwds.put(lkey, ltype); 39637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Mapping Unicode locale attribute to the special keyword, attribute=xxx-yyy 39667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> uattributes = uext.getUnicodeLocaleAttributes(); 39677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (uattributes.size() > 0) { 39687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder attrbuf = new StringBuilder(); 39697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String attr : uattributes) { 39707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (attrbuf.length() > 0) { 39717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert attrbuf.append('-'); 39727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert attrbuf.append(attr); 39747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert kwds.put(LOCALE_ATTRIBUTE_KEY, attrbuf.toString()); 39767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 39787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert kwds.put(String.valueOf(key), ext.getValue()); 39797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 39827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!kwds.isEmpty()) { 39837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder buf = new StringBuilder(id); 39847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append("@"); 39857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<Map.Entry<String, String>> kset = kwds.entrySet(); 39867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean insertSep = false; 39877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Map.Entry<String, String> kwd : kset) { 39887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (insertSep) { 39897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(";"); 39907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 39917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert insertSep = true; 39927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(kwd.getKey()); 39947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append("="); 39957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(kwd.getValue()); 39967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 39977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 39987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert id = buf.toString(); 39997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new ULocale(id); 40027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 40047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private BaseLocale base() { 40057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (baseLocale == null) { 40067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String language, script, region, variant; 40077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert language = script = region = variant = ""; 40087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!equals(ULocale.ROOT)) { 40097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleIDParser lp = new LocaleIDParser(localeID); 40107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert language = lp.getLanguage(); 40117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert script = lp.getScript(); 40127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert region = lp.getCountry(); 40137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert variant = lp.getVariant(); 40147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert baseLocale = BaseLocale.getInstance(language, script, region, variant); 40167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return baseLocale; 40187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 40207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private LocaleExtensions extensions() { 40217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (extensions == null) { 40227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Iterator<String> kwitr = getKeywords(); 40237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (kwitr == null) { 40247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert extensions = LocaleExtensions.EMPTY_EXTENSIONS; 40257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 40267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert InternalLocaleBuilder intbld = new InternalLocaleBuilder(); 40277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert while (kwitr.hasNext()) { 40287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String key = kwitr.next(); 40297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (key.equals(LOCALE_ATTRIBUTE_KEY)) { 40307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // special keyword used for representing Unicode locale attributes 40317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] uattributes = getKeywordValue(key).split("[-_]"); 40327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String uattr : uattributes) { 40337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 40347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert intbld.addUnicodeLocaleAttribute(uattr); 40357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 40367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ignore and fall through 40377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (key.length() >= 2) { 40407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String bcpKey = toUnicodeLocaleKey(key); 40417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String bcpType = toUnicodeLocaleType(key, getKeywordValue(key)); 40427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (bcpKey != null && bcpType != null) { 40437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 40447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert intbld.setUnicodeLocaleKeyword(bcpKey, bcpType); 40457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 40467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ignore and fall through 40477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (key.length() == 1 && (key.charAt(0) != UNICODE_LOCALE_EXTENSION)) { 40507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 40517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert intbld.setExtension(key.charAt(0), getKeywordValue(key).replace("_", 40527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LanguageTag.SEP)); 40537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (LocaleSyntaxException e) { 40547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ignore and fall through 40557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert extensions = intbld.getLocaleExtensions(); 40597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return extensions; 40627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 40637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 40647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 40657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * JDK Locale Helper 40667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 40677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final class JDKLocaleHelper { 40689713d6ad72cf9922638a2a56f61089a3db31adabroubert private static boolean hasScriptsAndUnicodeExtensions = false; 40699713d6ad72cf9922638a2a56f61089a3db31adabroubert private static boolean hasLocaleCategories = false; 40707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 40717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 40727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * New methods in Java 7 Locale class 40737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 40747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Method mGetScript; 40757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Method mGetExtensionKeys; 40767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Method mGetExtension; 40777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Method mGetUnicodeLocaleKeys; 40787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Method mGetUnicodeLocaleAttributes; 40797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Method mGetUnicodeLocaleType; 40807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Method mForLanguageTag; 40817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 40827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Method mGetDefault; 40837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Method mSetDefault; 40847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Object eDISPLAY; 40857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Object eFORMAT; 40867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 40877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert /* 40887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * This table is used for mapping between ICU and special Java 40897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * 6 locales. When an ICU locale matches <minumum base> with 40907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * <keyword>/<value>, the ICU locale is mapped to <Java> locale. 40917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * For example, both ja_JP@calendar=japanese and ja@calendar=japanese 40927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * are mapped to Java locale "ja_JP_JP". ICU locale "nn" is mapped 40937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert * to Java locale "no_NO_NY". 40947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert */ 40957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static final String[][] JAVA6_MAPDATA = { 4096f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert // { <Java>, <ICU base>, <keyword>, <value>, <minimum base> 40977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "ja_JP_JP", "ja_JP", "calendar", "japanese", "ja"}, 40987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "no_NO_NY", "nn_NO", null, null, "nn"}, 40997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert { "th_TH_TH", "th_TH", "numbers", "thai", "th"}, 41007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }; 41017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 41027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert static { 41037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert do { 41047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 41057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mGetScript = Locale.class.getMethod("getScript", (Class[]) null); 41067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mGetExtensionKeys = Locale.class.getMethod("getExtensionKeys", (Class[]) null); 41077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mGetExtension = Locale.class.getMethod("getExtension", char.class); 41087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mGetUnicodeLocaleKeys = Locale.class.getMethod("getUnicodeLocaleKeys", (Class[]) null); 41097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mGetUnicodeLocaleAttributes = Locale.class.getMethod("getUnicodeLocaleAttributes", (Class[]) null); 41107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mGetUnicodeLocaleType = Locale.class.getMethod("getUnicodeLocaleType", String.class); 41117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mForLanguageTag = Locale.class.getMethod("forLanguageTag", String.class); 4112f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 41139713d6ad72cf9922638a2a56f61089a3db31adabroubert hasScriptsAndUnicodeExtensions = true; 41149713d6ad72cf9922638a2a56f61089a3db31adabroubert } catch (NoSuchMethodException e) { 41159713d6ad72cf9922638a2a56f61089a3db31adabroubert } catch (IllegalArgumentException e) { 41169713d6ad72cf9922638a2a56f61089a3db31adabroubert } catch (SecurityException e) { 41179713d6ad72cf9922638a2a56f61089a3db31adabroubert // TODO : report? 41189713d6ad72cf9922638a2a56f61089a3db31adabroubert } 41199713d6ad72cf9922638a2a56f61089a3db31adabroubert 41209713d6ad72cf9922638a2a56f61089a3db31adabroubert try { 41217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Class<?> cCategory = null; 41227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Class<?>[] classes = Locale.class.getDeclaredClasses(); 41237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Class<?> c : classes) { 41247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (c.getName().equals("java.util.Locale$Category")) { 41257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cCategory = c; 41267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 41277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cCategory == null) { 41307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 41317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mGetDefault = Locale.class.getDeclaredMethod("getDefault", cCategory); 41337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mSetDefault = Locale.class.getDeclaredMethod("setDefault", cCategory, Locale.class); 4134f716bda031dccdec5e47bb40e758c5901d209729Fredrik Roubert 41357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Method mName = cCategory.getMethod("name", (Class[]) null); 41367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object[] enumConstants = cCategory.getEnumConstants(); 41377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Object e : enumConstants) { 41387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String catVal = (String)mName.invoke(e, (Object[])null); 41397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (catVal.equals("DISPLAY")) { 41407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert eDISPLAY = e; 41417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else if (catVal.equals("FORMAT")) { 41427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert eFORMAT = e; 41437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (eDISPLAY == null || eFORMAT == null) { 41467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 41479713d6ad72cf9922638a2a56f61089a3db31adabroubert } 41489713d6ad72cf9922638a2a56f61089a3db31adabroubert 41499713d6ad72cf9922638a2a56f61089a3db31adabroubert hasLocaleCategories = true; 41507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (NoSuchMethodException e) { 41517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (IllegalArgumentException e) { 41527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (IllegalAccessException e) { 41537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (InvocationTargetException e) { 41547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (SecurityException e) { 41557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // TODO : report? 41567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } while (false); 41587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 41607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private JDKLocaleHelper() { 41617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 41639713d6ad72cf9922638a2a56f61089a3db31adabroubert public static boolean hasLocaleCategories() { 41649713d6ad72cf9922638a2a56f61089a3db31adabroubert return hasLocaleCategories; 41657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 41677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static ULocale toULocale(Locale loc) { 41689713d6ad72cf9922638a2a56f61089a3db31adabroubert return hasScriptsAndUnicodeExtensions ? toULocale7(loc) : toULocale6(loc); 41697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 41717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static Locale toLocale(ULocale uloc) { 41729713d6ad72cf9922638a2a56f61089a3db31adabroubert return hasScriptsAndUnicodeExtensions ? toLocale7(uloc) : toLocale6(uloc); 41737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 41747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 41757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static ULocale toULocale7(Locale loc) { 41767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String language = loc.getLanguage(); 41777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String script = ""; 41787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String country = loc.getCountry(); 41797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String variant = loc.getVariant(); 41807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 41817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> attributes = null; 41827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Map<String, String> keywords = null; 41837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 41847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 41857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert script = (String) mGetScript.invoke(loc, (Object[]) null); 41867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unchecked") 41877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<Character> extKeys = (Set<Character>) mGetExtensionKeys.invoke(loc, (Object[]) null); 41887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!extKeys.isEmpty()) { 41897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Character extKey : extKeys) { 41907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (extKey.charValue() == 'u') { 41917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Found Unicode locale extension 41927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 41937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // attributes 41947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unchecked") 41957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> uAttributes = (Set<String>) mGetUnicodeLocaleAttributes.invoke(loc, (Object[]) null); 41967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (!uAttributes.isEmpty()) { 41977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert attributes = new TreeSet<String>(); 41987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String attr : uAttributes) { 41997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert attributes.add(attr); 42007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // keywords 42047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert @SuppressWarnings("unchecked") 42057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Set<String> uKeys = (Set<String>) mGetUnicodeLocaleKeys.invoke(loc, (Object[]) null); 42067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String kwKey : uKeys) { 42077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String kwVal = (String) mGetUnicodeLocaleType.invoke(loc, kwKey); 42087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (kwVal != null) { 42097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (kwKey.equals("va")) { 42107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // va-* is interpreted as a variant 42117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert variant = (variant.length() == 0) ? kwVal : kwVal + "_" + variant; 42127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 42137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keywords == null) { 42147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keywords = new TreeMap<String, String>(); 42157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keywords.put(kwKey, kwVal); 42177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 42217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String extVal = (String) mGetExtension.invoke(loc, extKey); 42227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (extVal != null) { 42237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keywords == null) { 42247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keywords = new TreeMap<String, String>(); 42257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keywords.put(String.valueOf(extKey), extVal); 42277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (IllegalAccessException e) { 42327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new RuntimeException(e); 42337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (InvocationTargetException e) { 42347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new RuntimeException(e); 42357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // JDK locale no_NO_NY is not interpreted as Nynorsk by ICU, 42387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // and it should be transformed to nn_NO. 42397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Note: JDK7+ unerstand both no_NO_NY and nn_NO. When convert 42417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ICU locale to JDK, we do not need to map nn_NO back to no_NO_NY. 42427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (language.equals("no") && country.equals("NO") && variant.equals("NY")) { 42447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert language = "nn"; 42457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert variant = ""; 42467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Constructing ID 42497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder buf = new StringBuilder(language); 42507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (script.length() > 0) { 42527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('_'); 42537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(script); 42547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (country.length() > 0) { 42577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('_'); 42587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(country); 42597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (variant.length() > 0) { 42627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (country.length() == 0) { 42637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('_'); 42647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('_'); 42667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(variant); 42677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (attributes != null) { 42707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // transform Unicode attributes into a keyword 42717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert StringBuilder attrBuf = new StringBuilder(); 42727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (String attr : attributes) { 42737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (attrBuf.length() != 0) { 42747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert attrBuf.append('-'); 42757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert attrBuf.append(attr); 42777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keywords == null) { 42797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keywords = new TreeMap<String, String>(); 42807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert keywords.put(LOCALE_ATTRIBUTE_KEY, attrBuf.toString()); 42827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (keywords != null) { 42857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('@'); 42867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert boolean addSep = false; 42877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (Entry<String, String> kwEntry : keywords.entrySet()) { 42887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String kwKey = kwEntry.getKey(); 42897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String kwVal = kwEntry.getValue(); 42907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (kwKey.length() != 1) { 42927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Unicode locale key 42937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert kwKey = toLegacyKey(kwKey); 42947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // use "yes" as the value of typeless keywords 42957935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert kwVal = toLegacyType(kwKey, ((kwVal.length() == 0) ? "yes" : kwVal)); 42967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 42977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 42987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (addSep) { 42997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(';'); 43007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 43017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert addSep = true; 43027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(kwKey); 43047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append('='); 43057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert buf.append(kwVal); 43067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 43097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new ULocale(getName(buf.toString()), loc); 43107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 43127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static ULocale toULocale6(Locale loc) { 43137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert ULocale uloc = null; 43147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String locStr = loc.toString(); 43157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (locStr.length() == 0) { 43167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert uloc = ULocale.ROOT; 43177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 43187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < JAVA6_MAPDATA.length; i++) { 43197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (JAVA6_MAPDATA[i][0].equals(locStr)) { 43207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleIDParser p = new LocaleIDParser(JAVA6_MAPDATA[i][1]); 43217935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert p.setKeywordValue(JAVA6_MAPDATA[i][2], JAVA6_MAPDATA[i][3]); 43227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locStr = p.getName(); 43237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 43247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert uloc = new ULocale(getName(locStr), loc); 43277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return uloc; 43297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 43317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Locale toLocale7(ULocale uloc) { 43327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale loc = null; 43337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String ulocStr = uloc.getName(); 43347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (uloc.getScript().length() > 0 || ulocStr.contains("@")) { 43357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // With script or keywords available, the best way 43367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // to get a mapped Locale is to go through a language tag. 43377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // A Locale with script or keywords can only have variants 43387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // that is 1 to 8 alphanum. If this ULocale has a variant 43397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // subtag not satisfying the criteria, the variant subtag 43407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // will be lost. 43417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String tag = uloc.toLanguageTag(); 43427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 43437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Workaround for variant casing problem: 43447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 43457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // The variant field in ICU is case insensitive and normalized 43467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // to upper case letters by getVariant(), while 43477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // the variant field in JDK Locale is case sensitive. 43487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ULocale#toLanguageTag use lower case characters for 43497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // BCP 47 variant and private use x-lvariant. 43507935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // 43517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Locale#forLanguageTag in JDK preserves character casing 43527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // for variant. Because ICU always normalizes variant to 43537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // upper case, we convert language tag to upper case here. 43547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert tag = AsciiUtil.toUpperString(tag); 43557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 43567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 43577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert loc = (Locale)mForLanguageTag.invoke(null, tag); 43587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (IllegalAccessException e) { 43597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new RuntimeException(e); 43607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (InvocationTargetException e) { 43617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert throw new RuntimeException(e); 43627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (loc == null) { 43657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Without script or keywords, use a Locale constructor, 43667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // so we can preserve any ill-formed variants. 43677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert loc = new Locale(uloc.getLanguage(), uloc.getCountry(), uloc.getVariant()); 43687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return loc; 43707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 43727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert private static Locale toLocale6(ULocale uloc) { 43737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String locstr = uloc.getBaseName(); 43747935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert for (int i = 0; i < JAVA6_MAPDATA.length; i++) { 43757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (locstr.equals(JAVA6_MAPDATA[i][1]) || locstr.equals(JAVA6_MAPDATA[i][4])) { 43767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (JAVA6_MAPDATA[i][2] != null) { 43777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String val = uloc.getKeywordValue(JAVA6_MAPDATA[i][2]); 43787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (val != null && val.equals(JAVA6_MAPDATA[i][3])) { 43797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locstr = JAVA6_MAPDATA[i][0]; 43807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 43817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 43837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert locstr = JAVA6_MAPDATA[i][0]; 43847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 43857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert LocaleIDParser p = new LocaleIDParser(locstr); 43897935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String[] names = p.getLanguageScriptCountryVariant(); 43907935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return new Locale(names[0], names[2], names[3]); 43917935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 43927935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 43937935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static Locale getDefault(Category category) { 43947935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Locale loc = Locale.getDefault(); 43959713d6ad72cf9922638a2a56f61089a3db31adabroubert if (hasLocaleCategories) { 43967935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object cat = null; 43977935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (category) { 43987935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case DISPLAY: 43997935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cat = eDISPLAY; 44007935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 44017935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case FORMAT: 44027935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cat = eFORMAT; 44037935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 44047935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44057935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cat != null) { 44067935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 44077935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert loc = (Locale)mGetDefault.invoke(null, cat); 44087935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (InvocationTargetException e) { 44097935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // fall through - use the base default 44107935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (IllegalArgumentException e) { 44117935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // fall through - use the base default 44127935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (IllegalAccessException e) { 44137935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // fall through - use the base default 44147935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44157935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44167935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44177935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return loc; 44187935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44197935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 44207935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static void setDefault(Category category, Locale newLocale) { 44219713d6ad72cf9922638a2a56f61089a3db31adabroubert if (hasLocaleCategories) { 44227935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert Object cat = null; 44237935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert switch (category) { 44247935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case DISPLAY: 44257935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cat = eDISPLAY; 44267935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 44277935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert case FORMAT: 44287935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert cat = eFORMAT; 44297935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert break; 44307935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44317935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (cat != null) { 44327935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 44337935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert mSetDefault.invoke(null, cat, newLocale); 44347935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (InvocationTargetException e) { 44357935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // fall through - no effects 44367935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (IllegalArgumentException e) { 44377935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // fall through - no effects 44387935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (IllegalAccessException e) { 44397935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // fall through - no effects 44407935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44417935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44427935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44437935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44447935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 44457935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // Returns true if the given Locale matches the original 44467935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // default locale initialized by JVM by checking user.XXX 44477935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // system properties. When the system properties are not accessible, 44487935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // this method returns false. 44497935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static boolean isOriginalDefaultLocale(Locale loc) { 44509713d6ad72cf9922638a2a56f61089a3db31adabroubert if (hasScriptsAndUnicodeExtensions) { 44517935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String script = ""; 44527935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 44537935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert script = (String) mGetScript.invoke(loc, (Object[]) null); 44547935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (Exception e) { 44557935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return false; 44567935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44577935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 44587935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return loc.getLanguage().equals(getSystemProperty("user.language")) 44597935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && loc.getCountry().equals(getSystemProperty("user.country")) 44607935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && loc.getVariant().equals(getSystemProperty("user.variant")) 44617935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && script.equals(getSystemProperty("user.script")); 44627935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44637935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return loc.getLanguage().equals(getSystemProperty("user.language")) 44647935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && loc.getCountry().equals(getSystemProperty("user.country")) 44657935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert && loc.getVariant().equals(getSystemProperty("user.variant")); 44667935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44677935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert 44687935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public static String getSystemProperty(String key) { 44697935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert String val = null; 44707935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert final String fkey = key; 44717935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert if (System.getSecurityManager() != null) { 44727935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert try { 44737935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert val = AccessController.doPrivileged(new PrivilegedAction<String>() { 44742d2bb24f747c65578da13d5b13b82f0669690461Fredrik Roubert @Override 44757935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert public String run() { 44767935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return System.getProperty(fkey); 44777935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44787935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert }); 44797935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } catch (AccessControlException e) { 44807935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert // ignore 44817935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44827935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } else { 44837935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert val = System.getProperty(fkey); 44847935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44857935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert return val; 44867935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44877935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert } 44887935b1839a081ed19ae0d33029ad3c09632a2caaFredrik Roubert} 4489