/* GENERATED SOURCE. DO NOT MODIFY. */ // © 2016 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html /* ****************************************************************************** * Copyright (C) 2003-2016, International Business Machines Corporation and * others. All Rights Reserved. ****************************************************************************** */ package android.icu.util; import java.io.Serializable; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.MissingResourceException; import java.util.Objects; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; import android.icu.impl.CacheBase; import android.icu.impl.ICUData; import android.icu.impl.ICUResourceBundle; import android.icu.impl.ICUResourceTableAccess; import android.icu.impl.LocaleIDParser; import android.icu.impl.LocaleIDs; import android.icu.impl.SoftCache; import android.icu.impl.Utility; import android.icu.impl.locale.AsciiUtil; import android.icu.impl.locale.BaseLocale; import android.icu.impl.locale.Extension; import android.icu.impl.locale.InternalLocaleBuilder; import android.icu.impl.locale.KeyTypeData; import android.icu.impl.locale.LSR; import android.icu.impl.locale.LanguageTag; import android.icu.impl.locale.LikelySubtags; import android.icu.impl.locale.LocaleExtensions; import android.icu.impl.locale.LocaleSyntaxException; import android.icu.impl.locale.ParseStatus; import android.icu.impl.locale.UnicodeLocaleExtension; import android.icu.lang.UScript; import android.icu.text.LocaleDisplayNames; import android.icu.text.LocaleDisplayNames.DialectHandling; /** * [icu enhancement] ICU's replacement for {@link java.util.Locale}. Methods, fields, and other functionality specific to ICU are labeled '[icu]'. * * A class analogous to {@link java.util.Locale} that provides additional * support for ICU protocol. In ICU 3.0 this class is enhanced to support * RFC 3066 language identifiers. * *
Many classes and services in ICU follow a factory idiom, in * which a factory method or object responds to a client request with * an object. The request includes a locale (the requested * locale), and the returned object is constructed using data for that * locale. The system may lack data for the requested locale, in * which case the locale fallback mechanism will be invoked until a * populated locale is found (the valid locale). Furthermore, * even when a populated locale is found (the valid locale), * further fallback may be required to reach a locale containing the * specific data required by the service (the actual locale). * *
ULocale performs 'normalization' and 'canonicalization' of locale ids. * Normalization 'cleans up' ICU locale ids as follows: *
canonicalize
can be called to convert the id
* to canonical form, or the canonicalInstance
factory method
* can be called.
*
* Note: The actual locale is returned correctly, but the valid
* locale is not, in most cases.
*
* @see java.util.Locale
* @author weiv
* @author Alan Liu
* @author Ram Viswanadha
*/
@SuppressWarnings("javadoc") // android.icu.text.Collator is in another project
public final class ULocale implements Serializable, Comparable This constructor does not canonicalize the localeID. So, for
* example, "zh__pinyin" remains unchanged instead of converting
* to "zh@collation=pinyin". By default ICU only recognizes the
* latter as specifying pinyin collation. Use {@link #createCanonical}
* or {@link #canonicalize} if you need to canonicalize the localeID.
*
* @param localeID string representation of the locale, e.g:
* "en_US", "sy_Cyrl_YU", "zh__pinyin", "es_ES@currency=EUR;collation=traditional"
*/
public ULocale(String localeID) {
this.localeID = getName(localeID);
}
/**
* Convenience overload of ULocale(String, String, String) for
* compatibility with java.util.Locale.
* @see #ULocale(String, String, String)
*/
public ULocale(String a, String b) {
this(a, b, null);
}
/**
* Constructs a ULocale from a localeID constructed from the three 'fields' a, b, and
* c. These fields are concatenated using underscores to form a localeID of the form
* a_b_c, which is then handled like the localeID passed to Java locale strings consisting of language, country, and
* variant will be handled by this form, since the country code
* (being shorter than four letters long) will not be interpreted
* as a script code. If a script code is present, the final
* argument ('c') will be interpreted as the country code. It is
* recommended that this constructor only be used to ease porting,
* and that clients instead use the single-argument constructor
* when constructing a ULocale from a localeID.
* @param a first component of the locale id
* @param b second component of the locale id
* @param c third component of the locale id
* @see #ULocale(String)
*/
public ULocale(String a, String b, String c) {
localeID = getName(lscvToID(a, b, c, EMPTY_STRING));
}
/**
* [icu] Creates a ULocale from the id by first canonicalizing the id according to CLDR.
* @param nonCanonicalID the locale id to canonicalize
* @return the locale created from the canonical version of the ID.
*/
public static ULocale createCanonical(String nonCanonicalID) {
return new ULocale(canonicalize(nonCanonicalID), (Locale)null);
}
/**
* Creates a ULocale from the locale by first canonicalizing the locale according to CLDR.
* @param locale the ULocale to canonicalize
* @return the ULocale created from the canonical version of the ULocale.
*/
public static ULocale createCanonical(ULocale locale) {
return createCanonical(locale.getName());
}
private static String lscvToID(String lang, String script, String country, String variant) {
StringBuilder buf = new StringBuilder();
if (lang != null && lang.length() > 0) {
buf.append(lang);
}
if (script != null && script.length() > 0) {
buf.append(UNDERSCORE);
buf.append(script);
}
if (country != null && country.length() > 0) {
buf.append(UNDERSCORE);
buf.append(country);
}
if (variant != null && variant.length() > 0) {
if (country == null || country.length() == 0) {
buf.append(UNDERSCORE);
}
buf.append(UNDERSCORE);
buf.append(variant);
}
return buf.toString();
}
/**
* [icu] Converts this ULocale object to a {@link java.util.Locale}.
* @return a {@link java.util.Locale} that either exactly represents this object
* or is the closest approximation.
*/
public Locale toLocale() {
if (locale == null) {
locale = JDKLocaleHelper.toLocale(this);
}
return locale;
}
/**
* Keep our own default ULocale.
*/
private static volatile ULocale defaultULocale;
private static Locale[] defaultCategoryLocales = new Locale[Category.values().length];
private static ULocale[] defaultCategoryULocales = new ULocale[Category.values().length];
static {
Locale defaultLocale = Locale.getDefault();
defaultULocale = forLocale(defaultLocale);
if (JDKLocaleHelper.hasLocaleCategories()) {
for (Category cat: Category.values()) {
int idx = cat.ordinal();
defaultCategoryLocales[idx] = JDKLocaleHelper.getDefault(cat);
defaultCategoryULocales[idx] = forLocale(defaultCategoryLocales[idx]);
}
} else {
// Android API level 21..23 does not have separate category locales,
// use the non-category default for all.
for (Category cat: Category.values()) {
int idx = cat.ordinal();
defaultCategoryLocales[idx] = defaultLocale;
defaultCategoryULocales[idx] = defaultULocale;
}
}
}
/**
* Returns the current default ULocale.
*
* The default ULocale is synchronized to the default Java Locale. This method checks
* the current default Java Locale and returns an equivalent ULocale.
*
* @return the default ULocale.
*/
public static ULocale getDefault() {
// Only synchronize if we must update the default locale.
ULocale currentDefaultULocale = defaultULocale;
if (currentDefaultULocale == null) {
// When Java's default locale has extensions (such as ja-JP-u-ca-japanese),
// Locale -> ULocale mapping requires BCP47 keyword mapping data that is currently
// stored in a resource bundle.
// If this happens during the class initialization's call to .forLocale(defaultLocale),
// then defaultULocale is still null until forLocale() returns.
// However, UResourceBundle currently requires non-null default ULocale.
// For now, this implementation returns ULocale.ROOT to avoid the problem.
// TODO: Consider moving BCP47 mapping data out of resource bundle later.
return ULocale.ROOT;
} else if (currentDefaultULocale.locale.equals(Locale.getDefault())) {
return currentDefaultULocale;
}
synchronized (ULocale.class) {
Locale currentDefault = Locale.getDefault();
assert currentDefault != null;
currentDefaultULocale = defaultULocale;
assert currentDefaultULocale != null;
if (currentDefaultULocale.locale.equals(currentDefault)) {
return currentDefaultULocale;
}
ULocale nextULocale = forLocale(currentDefault);
assert nextULocale != null;
if (!JDKLocaleHelper.hasLocaleCategories()) {
// Detected Java default Locale change.
// We need to update category defaults to match
// Java 7's behavior on Android API level 21..23.
for (Category cat : Category.values()) {
int idx = cat.ordinal();
defaultCategoryLocales[idx] = currentDefault;
defaultCategoryULocales[idx] = nextULocale;
}
}
return defaultULocale = nextULocale;
}
}
/**
* Sets the default ULocale. This also sets the default Locale.
* If the caller does not have write permission to the
* user.language property, a security exception will be thrown,
* and the default ULocale will remain unchanged.
*
* By setting the default ULocale with this method, all of the default category locales
* are also set to the specified default ULocale.
* @param newLocale the new default locale
* @throws SecurityException if a security manager exists and its
* Note: The order might change in future.
*
* @param other the ULocale to be compared.
* @return a negative integer, zero, or a positive integer as this ULocale is less than, equal to, or greater
* than the specified ULocale.
* @throws NullPointerException if Returns a list of all installed locales. This is equivalent to calling
* {@link #getAvailableLocalesByType} with AvailableType.DEFAULT.
*/
public static ULocale[] getAvailableLocales() {
return ICUResourceBundle.getAvailableULocales().clone();
}
/**
* Returns a list of all installed locales according to the specified type.
*/
public static Collection Related: {@link #getBaseName()} returns the locale ID string with all keywords removed.
*
* @param keyword the keyword to add/remove, or null to remove all keywords.
* @param value the value to add/set, or null to remove this particular keyword.
* @return the updated locale
*/
public ULocale setKeywordValue(String keyword, String value) {
return new ULocale(setKeywordValue(localeID, keyword, value), (Locale)null);
}
/**
* Given a locale id, a keyword, and a value, return a new locale id with an updated
* keyword and value. If the keyword is null, this removes all keywords from the locale id.
* Otherwise, if the value is null, this removes the value for this keyword from the
* locale id. Otherwise, this adds/replaces the value for this keyword in the locale id.
* The keyword and value must not be empty.
*
* Related: {@link #getBaseName(String)} returns the locale ID string with all keywords removed.
*
* @param localeID the locale id to modify
* @param keyword the keyword to add/remove, or null to remove all keywords.
* @param value the value to add/set, or null to remove this particular keyword.
* @return the updated locale id
*/
public static String setKeywordValue(String localeID, String keyword, String value) {
LocaleIDParser parser = new LocaleIDParser(localeID);
parser.setKeywordValue(keyword, value);
return parser.getName();
}
/*
* Given a locale id, a keyword, and a value, return a new locale id with an updated
* keyword and value, if the keyword does not already have a value. The keyword and
* value must not be null or empty.
* @param localeID the locale id to modify
* @param keyword the keyword to add, if not already present
* @param value the value to add, if not already present
* @return the updated locale id
*/
/* private static String defaultKeywordValue(String localeID, String keyword, String value) {
LocaleIDParser parser = new LocaleIDParser(localeID);
parser.defaultKeywordValue(keyword, value);
return parser.getName();
}*/
/**
* Returns a three-letter abbreviation for this locale's language. If the locale
* doesn't specify a language, returns the empty string. Otherwise, returns
* a lowercase ISO 639-2/T language code.
* The ISO 639-2 language codes can be found on-line at
* A script is right-to-left according to the CLDR script metadata
* which corresponds to whether the script's letters have Bidi_Class=R or AL.
*
* Returns true for "ar" and "en-Hebr", false for "zh" and "fa-Cyrl".
*
* @return true if the locale's script is written right-to-left
*/
public boolean isRightToLeft() {
String script = getScript();
if (script.length() == 0) {
// Fastpath: We know the likely scripts and their writing direction
// for some common languages.
String lang = getLanguage();
if (!lang.isEmpty()) {
int langIndex = LANG_DIR_STRING.indexOf(lang);
if (langIndex >= 0) {
switch (LANG_DIR_STRING.charAt(langIndex + lang.length())) {
case '-': return false;
case '+': return true;
default: break; // partial match of a longer code
}
}
}
// Otherwise, find the likely script.
ULocale likely = addLikelySubtags(this);
script = likely.getScript();
if (script.length() == 0) {
return false;
}
}
int scriptCode = UScript.getCodeFromName(script);
return UScript.isRightToLeft(scriptCode);
}
// display names
/**
* Returns this locale's language localized for display in the default Note: The valid locale will be returned correctly in ICU
* 3.0 or later. In ICU 2.8, it is not returned correctly.
* @hide draft / provisional / internal are hidden on Android
*/
public static Type VALID_LOCALE = new Type();
/**
* Opaque selector enum for getLocale().
* @see android.icu.util.ULocale
* @see android.icu.util.ULocale#ACTUAL_LOCALE
* @see android.icu.util.ULocale#VALID_LOCALE
* @hide Only a subset of ICU is exposed in Android
* @hide draft / provisional / internal are hidden on Android
*/
public static final class Type {
private Type() {}
}
/**
* [icu] Based on a HTTP formatted list of acceptable locales, determine an available
* locale for the user. NullPointerException is thrown if acceptLanguageList or
* availableLocales is null. If fallback is non-null, it will contain true if a
* fallback locale (one not in the acceptLanguageList) was returned. The value on
* entry is ignored. ULocale will be one of the locales in availableLocales, or the
* ROOT ULocale if if a ROOT locale was used as a fallback (because nothing else in
* availableLocales matched). No ULocale array element should be null; behavior is
* undefined if this is the case.
*
* @param acceptLanguageList list in HTTP "Accept-Language:" format of acceptable locales
* @param availableLocales list of available locales. One of these will be returned.
* @param fallback if non-null, a 1-element array containing a boolean to be set with
* the fallback status
* @return one of the locales from the availableLocales list, or null if none match
*/
public static ULocale acceptLanguage(String acceptLanguageList, ULocale[] availableLocales,
boolean[] fallback) {
if (fallback != null) {
fallback[0] = true;
}
LocalePriorityList desired;
try {
desired = LocalePriorityList.add(acceptLanguageList).build();
} catch (IllegalArgumentException e) {
return null;
}
LocaleMatcher.Builder builder = LocaleMatcher.builder();
for (ULocale locale : availableLocales) {
builder.addSupportedULocale(locale);
}
LocaleMatcher matcher = builder.build();
LocaleMatcher.Result result = matcher.getBestMatchResult(desired);
if (result.getDesiredIndex() >= 0) {
if (fallback != null && result.getDesiredULocale().equals(result.getSupportedULocale())) {
fallback[0] = false;
}
return result.getSupportedULocale();
}
return null;
}
/**
* [icu] Based on a list of acceptable locales, determine an available locale for the
* user. NullPointerException is thrown if acceptLanguageList or availableLocales is
* null. If fallback is non-null, it will contain true if a fallback locale (one not
* in the acceptLanguageList) was returned. The value on entry is ignored. ULocale
* will be one of the locales in availableLocales, or the ROOT ULocale if if a ROOT
* locale was used as a fallback (because nothing else in availableLocales matched).
* No ULocale array element should be null; behavior is undefined if this is the case.
*
* @param acceptLanguageList list of acceptable locales
* @param availableLocales list of available locales. One of these will be returned.
* @param fallback if non-null, a 1-element array containing a boolean to be set with
* the fallback status
* @return one of the locales from the availableLocales list, or null if none match
*/
public static ULocale acceptLanguage(ULocale[] acceptLanguageList, ULocale[] availableLocales,
boolean[] fallback) {
if (fallback != null) {
fallback[0] = true;
}
LocaleMatcher.Builder builder = LocaleMatcher.builder();
for (ULocale locale : availableLocales) {
builder.addSupportedULocale(locale);
}
LocaleMatcher matcher = builder.build();
LocaleMatcher.Result result;
if (acceptLanguageList.length == 1) {
result = matcher.getBestMatchResult(acceptLanguageList[0]);
} else {
result = matcher.getBestMatchResult(Arrays.asList(acceptLanguageList));
}
if (result.getDesiredIndex() >= 0) {
if (fallback != null && result.getDesiredULocale().equals(result.getSupportedULocale())) {
fallback[0] = false;
}
return result.getSupportedULocale();
}
return null;
}
/**
* [icu] Based on a HTTP formatted list of acceptable locales, determine an available
* locale for the user. NullPointerException is thrown if acceptLanguageList or
* availableLocales is null. If fallback is non-null, it will contain true if a
* fallback locale (one not in the acceptLanguageList) was returned. The value on
* entry is ignored. ULocale will be one of the locales in availableLocales, or the
* ROOT ULocale if if a ROOT locale was used as a fallback (because nothing else in
* availableLocales matched). No ULocale array element should be null; behavior is
* undefined if this is the case. This function will choose a locale from the
* ULocale.getAvailableLocales() list as available.
*
* @param acceptLanguageList list in HTTP "Accept-Language:" format of acceptable locales
* @param fallback if non-null, a 1-element array containing a boolean to be set with
* the fallback status
* @return one of the locales from the ULocale.getAvailableLocales() list, or null if
* none match
*/
public static ULocale acceptLanguage(String acceptLanguageList, boolean[] fallback) {
return acceptLanguage(acceptLanguageList, ULocale.getAvailableLocales(),
fallback);
}
/**
* [icu] Based on an ordered array of acceptable locales, determine an available
* locale for the user. NullPointerException is thrown if acceptLanguageList or
* availableLocales is null. If fallback is non-null, it will contain true if a
* fallback locale (one not in the acceptLanguageList) was returned. The value on
* entry is ignored. ULocale will be one of the locales in availableLocales, or the
* ROOT ULocale if if a ROOT locale was used as a fallback (because nothing else in
* availableLocales matched). No ULocale array element should be null; behavior is
* undefined if this is the case. This function will choose a locale from the
* ULocale.getAvailableLocales() list as available.
*
* @param acceptLanguageList ordered array of acceptable locales (preferred are listed first)
* @param fallback if non-null, a 1-element array containing a boolean to be set with
* the fallback status
* @return one of the locales from the ULocale.getAvailableLocales() list, or null if none match
*/
public static ULocale acceptLanguage(ULocale[] acceptLanguageList, boolean[] fallback) {
return acceptLanguage(acceptLanguageList, ULocale.getAvailableLocales(),
fallback);
}
private static final String UNDEFINED_LANGUAGE = "und";
private static final String UNDEFINED_SCRIPT = "Zzzz";
private static final String UNDEFINED_REGION = "ZZ";
/**
* [icu] Adds the likely subtags for a provided locale ID, per the algorithm
* described in the following CLDR technical report:
*
* http://www.unicode.org/reports/tr35/#Likely_Subtags
*
* If the provided ULocale instance is already in the maximal form, or there is no
* data available available for maximization, it will be returned. For example,
* "sh" cannot be maximized, since there is no reasonable maximization.
* Otherwise, a new ULocale instance with the maximal form is returned.
*
* Examples:
*
* "en" maximizes to "en_Latn_US"
*
* "de" maximizes to "de_Latn_DE"
*
* "sr" maximizes to "sr_Cyrl_RS"
*
* "zh_Hani" maximizes to "zh_Hani_CN"
*
* @param loc The ULocale to maximize
* @return The maximized ULocale instance.
*/
public static ULocale addLikelySubtags(ULocale loc) {
String[] tags = new String[3];
String trailing = null;
int trailingIndex = parseTagString(
loc.localeID,
tags);
if (trailingIndex < loc.localeID.length()) {
trailing = loc.localeID.substring(trailingIndex);
}
LSR max = LikelySubtags.INSTANCE.makeMaximizedLsrFrom(
new ULocale(loc.getLanguage(), loc.getScript(), loc.getCountry()), true);
String newLocaleID = createTagString(max.language, max.script, max.region,
trailing);
return newLocaleID == null ? loc : new ULocale(newLocaleID);
}
/**
* [icu] Minimizes the subtags for a provided locale ID, per the algorithm described
* in the following CLDR technical report: If this Language: If language is empty, or not well-formed
* (for example "a" or "e2"), it will be emitted as "und" (Undetermined).
*
* Script: If script is not well-formed (for example "12"
* or "Latin"), it will be omitted.
*
* Country: If country is not well-formed (for example "12"
* or "USA"), it will be omitted.
*
* Variant: If variant is well-formed, each sub-segment
* (delimited by '-' or '_') is emitted as a subtag. Otherwise:
* Note: Although the language tag created by this
* method is well-formed (satisfies the syntax requirements
* defined by the IETF BCP 47 specification), it is not
* necessarily a valid BCP 47 language tag. For example,
* If the specified language tag contains any ill-formed subtags,
* the first such subtag and all following subtags are ignored. Compare
* to {@link ULocale.Builder#setLanguageTag} which throws an exception
* in this case.
*
* The following conversions are performed:
* This implements the 'Language-Tag' production of BCP 47, and so
* supports legacy language tags (marked as “Type: grandfathered” in BCP 47)
* (regular and irregular) as well as private use language tags.
*
* Stand-alone private use tags are represented as empty language and extension 'x-whatever',
* and legacy tags are converted to their canonical replacements where they exist.
*
* Note that a few legacy tags have no modern replacement;
* these will be converted using the fallback described in
* the first paragraph, so some information might be lost.
*
* Note: there is no guarantee that
* When the specified keyword is unknown, but satisfies the BCP syntax,
* then the lower-case version of the input keyword will be returned.
* For example,
*
* When the specified keyword is not recognized, but the specified value
* satisfies the syntax of the BCP 47 Unicode locale extension type,
* or when the specified keyword allows 'variable' type and the specified
* value satisfies the syntax, the lower-case version of the input value
* will be returned. For example,
*
* When the specified keyword is not recognized, but the specified value
* satisfies the syntax of legacy key, or when the specified keyword
* allows 'variable' type and the specified value satisfies the syntax,
* the lower-case version of the input value will be returned.
* For example,
* Note: The The following example shows how to create a Builders can be reused; All fields of the locale must be well-formed, see {@link Locale}.
*
* Locales with any ill-formed fields cause
* The typical language value is a two or three-letter language
* code as defined in ISO639.
*
* @param language the language
* @return This builder.
* @throws IllformedLocaleException if The typical script value is a four-letter script code as defined by ISO 15924.
*
* @param script the script
* @return This builder.
* @throws IllformedLocaleException if The typical region value is a two-letter ISO 3166 code or a
* three-digit UN M.49 area code.
*
* The country value in the Note: This method checks if Note: The key {@link ULocale#UNICODE_LOCALE_EXTENSION
* UNICODE_LOCALE_EXTENSION} ('u') is used for the Unicode locale extension.
* Setting a value for this key replaces any existing Unicode locale key/type
* pairs with those defined in the extension.
*
* Note: The key {@link ULocale#PRIVATE_USE_EXTENSION
* PRIVATE_USE_EXTENSION} ('x') is used for the private use code. To be
* well-formed, the value for this key needs only to have subtags of one to
* eight alphanumeric characters, not two to eight as in the general case.
*
* @param key the extension key
* @param value the extension value
* @return This builder.
* @throws IllformedLocaleException if Keys and types are converted to lower case.
*
* Note:Setting the 'u' extension via {@link #setExtension}
* replaces all Unicode locale keywords with those defined in the
* extension.
*
* @param key the Unicode locale key
* @param type the Unicode locale type
* @return This builder.
* @throws IllformedLocaleException if Attribute comparison for removal is case-insensitive.
*
* @param attribute the attribute
* @return This builder.
* @throws NullPointerException if
*
*
* The locales in this set are disjoint from the ones in
* DEFAULT. To get both sets at the same time, use
* WITH_LEGACY_ALIASES.
*/
ONLY_LEGACY_ALIASES,
/**
* The union of the locales in DEFAULT and ONLY_LEGACY_ALIASES.
*/
WITH_LEGACY_ALIASES,
}
/**
* Useful constant for language.
*/
public static final ULocale ENGLISH = new ULocale("en", Locale.ENGLISH);
/**
* Useful constant for language.
*/
public static final ULocale FRENCH = new ULocale("fr", Locale.FRENCH);
/**
* Useful constant for language.
*/
public static final ULocale GERMAN = new ULocale("de", Locale.GERMAN);
/**
* Useful constant for language.
*/
public static final ULocale ITALIAN = new ULocale("it", Locale.ITALIAN);
/**
* Useful constant for language.
*/
public static final ULocale JAPANESE = new ULocale("ja", Locale.JAPANESE);
/**
* Useful constant for language.
*/
public static final ULocale KOREAN = new ULocale("ko", Locale.KOREAN);
/**
* Useful constant for language.
*/
public static final ULocale CHINESE = new ULocale("zh", Locale.CHINESE);
// Special note about static initializer for
// - SIMPLIFIED_CHINESE
// - TRADTIONAL_CHINESE
// - CHINA
// - TAIWAN
//
// Equivalent JDK Locale for ULocale.SIMPLIFIED_CHINESE is different
// by JRE version. JRE 7 or later supports a script tag "Hans", while
// JRE 6 or older does not. JDK's Locale.SIMPLIFIED_CHINESE is actually
// zh_CN, not zh_Hans. This is same in Java 7 or later versions.
//
// ULocale#toLocale() implementation create a Locale with a script tag.
// When a new ULocale is constructed with the single arg
// constructor, the volatile field 'Locale locale' is initialized by
// #toLocale() method.
//
// Because we cannot hardcode corresponding JDK Locale representation below,
// SIMPLIFIED_CHINESE is constructed without JDK Locale argument, and
// #toLocale() is used for resolving the best matching JDK Locale at runtime.
//
// The same thing applies to TRADITIONAL_CHINESE.
/**
* Useful constant for language.
*/
public static final ULocale SIMPLIFIED_CHINESE = new ULocale("zh_Hans");
/**
* Useful constant for language.
*/
public static final ULocale TRADITIONAL_CHINESE = new ULocale("zh_Hant");
/**
* Useful constant for country/region.
*/
public static final ULocale FRANCE = new ULocale("fr_FR", Locale.FRANCE);
/**
* Useful constant for country/region.
*/
public static final ULocale GERMANY = new ULocale("de_DE", Locale.GERMANY);
/**
* Useful constant for country/region.
*/
public static final ULocale ITALY = new ULocale("it_IT", Locale.ITALY);
/**
* Useful constant for country/region.
*/
public static final ULocale JAPAN = new ULocale("ja_JP", Locale.JAPAN);
/**
* Useful constant for country/region.
*/
public static final ULocale KOREA = new ULocale("ko_KR", Locale.KOREA);
/**
* Useful constant for country/region.
*/
public static final ULocale CHINA = new ULocale("zh_Hans_CN");
/**
* Useful constant for country/region.
*/
public static final ULocale PRC = CHINA;
/**
* Useful constant for country/region.
*/
public static final ULocale TAIWAN = new ULocale("zh_Hant_TW");
/**
* Useful constant for country/region.
*/
public static final ULocale UK = new ULocale("en_GB", Locale.UK);
/**
* Useful constant for country/region.
*/
public static final ULocale US = new ULocale("en_US", Locale.US);
/**
* Useful constant for country/region.
*/
public static final ULocale CANADA = new ULocale("en_CA", Locale.CANADA);
/**
* Useful constant for country/region.
*/
public static final ULocale CANADA_FRENCH = new ULocale("fr_CA", Locale.CANADA_FRENCH);
/**
* Handy constant.
*/
private static final String EMPTY_STRING = "";
// Used in both ULocale and LocaleIDParser, so moved up here.
private static final char UNDERSCORE = '_';
// default empty locale
private static final Locale EMPTY_LOCALE = new Locale("", "");
// special keyword key for Unicode locale attributes
private static final String LOCALE_ATTRIBUTE_KEY = "attribute";
/**
* The root ULocale.
*/
public static final ULocale ROOT = new ULocale("", EMPTY_LOCALE);
/**
* Enum for locale categories. These locale categories are used to get/set the default locale for
* the specific functionality represented by the category.
*/
public enum Category {
/**
* Category used to represent the default locale for displaying user interfaces.
*/
DISPLAY,
/**
* Category used to represent the default locale for formatting date, number and/or currency.
*/
FORMAT
}
private static final SoftCacheULocale(String
* localeID)
.
*
* checkPermission
method doesn't allow the operation.
* @throws NullPointerException if newLocale
is null
* @see SecurityManager#checkPermission(java.security.Permission)
* @see java.util.PropertyPermission
* @see ULocale#setDefault(Category, ULocale)
* @hide unsupported on Android
*/
public static synchronized void setDefault(ULocale newLocale){
Locale.setDefault(newLocale.toLocale());
defaultULocale = newLocale;
// This method also updates all category default locales
for (Category cat : Category.values()) {
setDefault(cat, newLocale);
}
}
/**
* Returns the current default ULocale for the specified category.
*
* @param category the category
* @return the default ULocale for the specified category.
*/
public static ULocale getDefault(Category category) {
synchronized (ULocale.class) {
int idx = category.ordinal();
if (defaultCategoryULocales[idx] == null) {
// Just in case this method is called during ULocale class
// initialization. Unlike getDefault(), we do not have
// cyclic dependency for category default.
return ULocale.ROOT;
}
if (JDKLocaleHelper.hasLocaleCategories()) {
Locale currentCategoryDefault = JDKLocaleHelper.getDefault(category);
if (!defaultCategoryLocales[idx].equals(currentCategoryDefault)) {
defaultCategoryLocales[idx] = currentCategoryDefault;
defaultCategoryULocales[idx] = forLocale(currentCategoryDefault);
}
} else {
// java.util.Locale.setDefault(Locale) in Java 7 updates
// category locale defaults. On Android API level 21..23
// ICU4J checks if the default locale has changed and update
// category ULocales here if necessary.
// Note: When java.util.Locale.setDefault(Locale) is called
// with a Locale same with the previous one, Java 7 still
// updates category locale defaults. On Android API level 21..23
// there is no good way to detect the event, ICU4J simply
// checks if the default Java Locale has changed since last
// time.
Locale currentDefault = Locale.getDefault();
if (!defaultULocale.locale.equals(currentDefault)) {
defaultULocale = forLocale(currentDefault);
for (Category cat : Category.values()) {
int tmpIdx = cat.ordinal();
defaultCategoryLocales[tmpIdx] = currentDefault;
defaultCategoryULocales[tmpIdx] = forLocale(currentDefault);
}
}
// No synchronization with JDK Locale, because category default
// is not supported in Android API level 21..23.
}
return defaultCategoryULocales[idx];
}
}
/**
* Sets the default ULocale
for the specified Category
.
* This also sets the default Locale
for the specified Category
* of the JVM. If the caller does not have write permission to the
* user.language property, a security exception will be thrown,
* and the default ULocale for the specified Category will remain unchanged.
*
* @param category the specified category to set the default locale
* @param newLocale the new default locale
* @see SecurityManager#checkPermission(java.security.Permission)
* @see java.util.PropertyPermission
* @hide unsupported on Android
*/
public static synchronized void setDefault(Category category, ULocale newLocale) {
Locale newJavaDefault = newLocale.toLocale();
int idx = category.ordinal();
defaultCategoryULocales[idx] = newLocale;
defaultCategoryLocales[idx] = newJavaDefault;
JDKLocaleHelper.setDefault(category, newJavaDefault);
}
/**
* This is for compatibility with Locale-- in actuality, since ULocale is
* immutable, there is no reason to clone it, so this API returns 'this'.
*/
@Override
public Object clone() {
return this;
}
/**
* Returns the hashCode.
* @return a hash code value for this object.
*/
@Override
public int hashCode() {
return localeID.hashCode();
}
/**
* Returns true if the other object is another ULocale with the
* same full name.
* Note that since names are not canonicalized, two ULocales that
* function identically might not compare equal.
*
* @return true if this Locale is equal to the specified object.
*/
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof ULocale) {
return localeID.equals(((ULocale)obj).localeID);
}
return false;
}
/**
* Compares two ULocale for ordering.
* other
is null.
*/
@Override
public int compareTo(ULocale other) {
if (this == other) {
return 0;
}
int cmp = 0;
// Language
cmp = getLanguage().compareTo(other.getLanguage());
if (cmp == 0) {
// Script
cmp = getScript().compareTo(other.getScript());
if (cmp == 0) {
// Region
cmp = getCountry().compareTo(other.getCountry());
if (cmp == 0) {
// Variant
cmp = getVariant().compareTo(other.getVariant());
if (cmp == 0) {
// Keywords
IteratorULocale
,
* not Locale
.
*
* ftp://dkuug.dk/i18n/iso-639-2.txt
* @exception MissingResourceException Throws MissingResourceException if the
* three-letter language abbreviation is not available for this locale.
*/
public String getISO3Language(){
return getISO3Language(localeID);
}
/**
* [icu] Returns a three-letter abbreviation for this locale's language. If the locale
* doesn't specify a language, returns the empty string. Otherwise, returns
* a lowercase ISO 639-2/T language code.
* The ISO 639-2 language codes can be found on-line at
* ftp://dkuug.dk/i18n/iso-639-2.txt
* @exception MissingResourceException Throws MissingResourceException if the
* three-letter language abbreviation is not available for this locale.
*/
public static String getISO3Language(String localeID) {
return LocaleIDs.getISO3Language(getLanguage(localeID));
}
/**
* Returns a three-letter abbreviation for this locale's country/region. If the locale
* doesn't specify a country, returns the empty string. Otherwise, returns
* an uppercase ISO 3166 3-letter country code.
* @exception MissingResourceException Throws MissingResourceException if the
* three-letter country abbreviation is not available for this locale.
*/
public String getISO3Country() {
return getISO3Country(localeID);
}
/**
* [icu] Returns a three-letter abbreviation for this locale's country/region. If the locale
* doesn't specify a country, returns the empty string. Otherwise, returns
* an uppercase ISO 3166 3-letter country code.
* @exception MissingResourceException Throws MissingResourceException if the
* three-letter country abbreviation is not available for this locale.
*/
public static String getISO3Country(String localeID) {
return LocaleIDs.getISO3Country(getCountry(localeID));
}
/**
* Pairs of (language subtag, + or -) for finding out fast if common languages
* are LTR (minus) or RTL (plus).
*/
private static final String LANG_DIR_STRING =
"root-en-es-pt-zh-ja-ko-de-fr-it-ar+he+fa+ru-nl-pl-th-tr-";
/**
* [icu] Returns whether this locale's script is written right-to-left.
* If there is no script subtag, then the likely script is used,
* see {@link #addLikelySubtags(ULocale)}.
* If no likely script is known, then false is returned.
*
* DISPLAY
locale.
* @return the localized language name.
* @see Category#DISPLAY
*/
public String getDisplayLanguage() {
return getDisplayLanguageInternal(this, getDefault(Category.DISPLAY), false);
}
/**
* Returns this locale's language localized for display in the provided locale.
* @param displayLocale the locale in which to display the name.
* @return the localized language name.
*/
public String getDisplayLanguage(ULocale displayLocale) {
return getDisplayLanguageInternal(this, displayLocale, false);
}
/**
* [icu] Returns a locale's language localized for display in the provided locale.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose language will be displayed
* @param displayLocaleID the id of the locale in which to display the name.
* @return the localized language name.
*/
public static String getDisplayLanguage(String localeID, String displayLocaleID) {
return getDisplayLanguageInternal(new ULocale(localeID), new ULocale(displayLocaleID),
false);
}
/**
* [icu] Returns a locale's language localized for display in the provided locale.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose language will be displayed.
* @param displayLocale the locale in which to display the name.
* @return the localized language name.
*/
public static String getDisplayLanguage(String localeID, ULocale displayLocale) {
return getDisplayLanguageInternal(new ULocale(localeID), displayLocale, false);
}
/**
* [icu] Returns this locale's language localized for display in the default DISPLAY
locale.
* If a dialect name is present in the data, then it is returned.
* @return the localized language name.
* @see Category#DISPLAY
*/
public String getDisplayLanguageWithDialect() {
return getDisplayLanguageInternal(this, getDefault(Category.DISPLAY), true);
}
/**
* [icu] Returns this locale's language localized for display in the provided locale.
* If a dialect name is present in the data, then it is returned.
* @param displayLocale the locale in which to display the name.
* @return the localized language name.
*/
public String getDisplayLanguageWithDialect(ULocale displayLocale) {
return getDisplayLanguageInternal(this, displayLocale, true);
}
/**
* [icu] Returns a locale's language localized for display in the provided locale.
* If a dialect name is present in the data, then it is returned.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose language will be displayed
* @param displayLocaleID the id of the locale in which to display the name.
* @return the localized language name.
*/
public static String getDisplayLanguageWithDialect(String localeID, String displayLocaleID) {
return getDisplayLanguageInternal(new ULocale(localeID), new ULocale(displayLocaleID),
true);
}
/**
* [icu] Returns a locale's language localized for display in the provided locale.
* If a dialect name is present in the data, then it is returned.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose language will be displayed.
* @param displayLocale the locale in which to display the name.
* @return the localized language name.
*/
public static String getDisplayLanguageWithDialect(String localeID, ULocale displayLocale) {
return getDisplayLanguageInternal(new ULocale(localeID), displayLocale, true);
}
private static String getDisplayLanguageInternal(ULocale locale, ULocale displayLocale,
boolean useDialect) {
String lang = useDialect ? locale.getBaseName() : locale.getLanguage();
return LocaleDisplayNames.getInstance(displayLocale).languageDisplayName(lang);
}
/**
* Returns this locale's script localized for display in the default DISPLAY
locale.
* @return the localized script name.
* @see Category#DISPLAY
*/
public String getDisplayScript() {
return getDisplayScriptInternal(this, getDefault(Category.DISPLAY));
}
/**
* [icu] Returns this locale's script localized for display in the default DISPLAY
locale.
* @return the localized script name.
* @see Category#DISPLAY
* @deprecated This API is ICU internal only.
* @hide original deprecated declaration
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
public String getDisplayScriptInContext() {
return getDisplayScriptInContextInternal(this, getDefault(Category.DISPLAY));
}
/**
* Returns this locale's script localized for display in the provided locale.
* @param displayLocale the locale in which to display the name.
* @return the localized script name.
*/
public String getDisplayScript(ULocale displayLocale) {
return getDisplayScriptInternal(this, displayLocale);
}
/**
* [icu] Returns this locale's script localized for display in the provided locale.
* @param displayLocale the locale in which to display the name.
* @return the localized script name.
* @deprecated This API is ICU internal only.
* @hide original deprecated declaration
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
public String getDisplayScriptInContext(ULocale displayLocale) {
return getDisplayScriptInContextInternal(this, displayLocale);
}
/**
* [icu] Returns a locale's script localized for display in the provided locale.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose script will be displayed
* @param displayLocaleID the id of the locale in which to display the name.
* @return the localized script name.
*/
public static String getDisplayScript(String localeID, String displayLocaleID) {
return getDisplayScriptInternal(new ULocale(localeID), new ULocale(displayLocaleID));
}
/**
* [icu] Returns a locale's script localized for display in the provided locale.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose script will be displayed
* @param displayLocaleID the id of the locale in which to display the name.
* @return the localized script name.
* @deprecated This API is ICU internal only.
* @hide original deprecated declaration
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
public static String getDisplayScriptInContext(String localeID, String displayLocaleID) {
return getDisplayScriptInContextInternal(new ULocale(localeID), new ULocale(displayLocaleID));
}
/**
* [icu] Returns a locale's script localized for display in the provided locale.
* @param localeID the id of the locale whose script will be displayed.
* @param displayLocale the locale in which to display the name.
* @return the localized script name.
*/
public static String getDisplayScript(String localeID, ULocale displayLocale) {
return getDisplayScriptInternal(new ULocale(localeID), displayLocale);
}
/**
* [icu] Returns a locale's script localized for display in the provided locale.
* @param localeID the id of the locale whose script will be displayed.
* @param displayLocale the locale in which to display the name.
* @return the localized script name.
* @deprecated This API is ICU internal only.
* @hide original deprecated declaration
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
public static String getDisplayScriptInContext(String localeID, ULocale displayLocale) {
return getDisplayScriptInContextInternal(new ULocale(localeID), displayLocale);
}
// displayLocaleID is canonical, localeID need not be since parsing will fix this.
private static String getDisplayScriptInternal(ULocale locale, ULocale displayLocale) {
return LocaleDisplayNames.getInstance(displayLocale)
.scriptDisplayName(locale.getScript());
}
private static String getDisplayScriptInContextInternal(ULocale locale, ULocale displayLocale) {
return LocaleDisplayNames.getInstance(displayLocale)
.scriptDisplayNameInContext(locale.getScript());
}
/**
* Returns this locale's country localized for display in the default DISPLAY
locale.
* Warning: this is for the region part of a valid locale ID; it cannot just be the region code (like "FR").
* To get the display name for a region alone, or for other options, use {@link LocaleDisplayNames} instead.
* @return the localized country name.
* @see Category#DISPLAY
*/
public String getDisplayCountry() {
return getDisplayCountryInternal(this, getDefault(Category.DISPLAY));
}
/**
* Returns this locale's country localized for display in the provided locale.
* Warning: this is for the region part of a valid locale ID; it cannot just be the region code (like "FR").
* To get the display name for a region alone, or for other options, use {@link LocaleDisplayNames} instead.
* @param displayLocale the locale in which to display the name.
* @return the localized country name.
*/
public String getDisplayCountry(ULocale displayLocale){
return getDisplayCountryInternal(this, displayLocale);
}
/**
* [icu] Returns a locale's country localized for display in the provided locale.
* Warning: this is for the region part of a valid locale ID; it cannot just be the region code (like "FR").
* To get the display name for a region alone, or for other options, use {@link LocaleDisplayNames} instead.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose country will be displayed
* @param displayLocaleID the id of the locale in which to display the name.
* @return the localized country name.
*/
public static String getDisplayCountry(String localeID, String displayLocaleID) {
return getDisplayCountryInternal(new ULocale(localeID), new ULocale(displayLocaleID));
}
/**
* [icu] Returns a locale's country localized for display in the provided locale.
* Warning: this is for the region part of a valid locale ID; it cannot just be the region code (like "FR").
* To get the display name for a region alone, or for other options, use {@link LocaleDisplayNames} instead.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose country will be displayed.
* @param displayLocale the locale in which to display the name.
* @return the localized country name.
*/
public static String getDisplayCountry(String localeID, ULocale displayLocale) {
return getDisplayCountryInternal(new ULocale(localeID), displayLocale);
}
// displayLocaleID is canonical, localeID need not be since parsing will fix this.
private static String getDisplayCountryInternal(ULocale locale, ULocale displayLocale) {
return LocaleDisplayNames.getInstance(displayLocale)
.regionDisplayName(locale.getCountry());
}
/**
* Returns this locale's variant localized for display in the default DISPLAY
locale.
* @return the localized variant name.
* @see Category#DISPLAY
*/
public String getDisplayVariant() {
return getDisplayVariantInternal(this, getDefault(Category.DISPLAY));
}
/**
* Returns this locale's variant localized for display in the provided locale.
* @param displayLocale the locale in which to display the name.
* @return the localized variant name.
*/
public String getDisplayVariant(ULocale displayLocale) {
return getDisplayVariantInternal(this, displayLocale);
}
/**
* [icu] Returns a locale's variant localized for display in the provided locale.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose variant will be displayed
* @param displayLocaleID the id of the locale in which to display the name.
* @return the localized variant name.
*/
public static String getDisplayVariant(String localeID, String displayLocaleID){
return getDisplayVariantInternal(new ULocale(localeID), new ULocale(displayLocaleID));
}
/**
* [icu] Returns a locale's variant localized for display in the provided locale.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose variant will be displayed.
* @param displayLocale the locale in which to display the name.
* @return the localized variant name.
*/
public static String getDisplayVariant(String localeID, ULocale displayLocale) {
return getDisplayVariantInternal(new ULocale(localeID), displayLocale);
}
private static String getDisplayVariantInternal(ULocale locale, ULocale displayLocale) {
return LocaleDisplayNames.getInstance(displayLocale)
.variantDisplayName(locale.getVariant());
}
/**
* [icu] Returns a keyword localized for display in the default DISPLAY
locale.
* @param keyword the keyword to be displayed.
* @return the localized keyword name.
* @see #getKeywords()
* @see Category#DISPLAY
*/
public static String getDisplayKeyword(String keyword) {
return getDisplayKeywordInternal(keyword, getDefault(Category.DISPLAY));
}
/**
* [icu] Returns a keyword localized for display in the specified locale.
* @param keyword the keyword to be displayed.
* @param displayLocaleID the id of the locale in which to display the keyword.
* @return the localized keyword name.
* @see #getKeywords(String)
*/
public static String getDisplayKeyword(String keyword, String displayLocaleID) {
return getDisplayKeywordInternal(keyword, new ULocale(displayLocaleID));
}
/**
* [icu] Returns a keyword localized for display in the specified locale.
* @param keyword the keyword to be displayed.
* @param displayLocale the locale in which to display the keyword.
* @return the localized keyword name.
* @see #getKeywords(String)
*/
public static String getDisplayKeyword(String keyword, ULocale displayLocale) {
return getDisplayKeywordInternal(keyword, displayLocale);
}
private static String getDisplayKeywordInternal(String keyword, ULocale displayLocale) {
return LocaleDisplayNames.getInstance(displayLocale).keyDisplayName(keyword);
}
/**
* [icu] Returns a keyword value localized for display in the default DISPLAY
locale.
* @param keyword the keyword whose value is to be displayed.
* @return the localized value name.
* @see Category#DISPLAY
*/
public String getDisplayKeywordValue(String keyword) {
return getDisplayKeywordValueInternal(this, keyword, getDefault(Category.DISPLAY));
}
/**
* [icu] Returns a keyword value localized for display in the specified locale.
* @param keyword the keyword whose value is to be displayed.
* @param displayLocale the locale in which to display the value.
* @return the localized value name.
*/
public String getDisplayKeywordValue(String keyword, ULocale displayLocale) {
return getDisplayKeywordValueInternal(this, keyword, displayLocale);
}
/**
* [icu] Returns a keyword value localized for display in the specified locale.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose keyword value is to be displayed.
* @param keyword the keyword whose value is to be displayed.
* @param displayLocaleID the id of the locale in which to display the value.
* @return the localized value name.
*/
public static String getDisplayKeywordValue(String localeID, String keyword,
String displayLocaleID) {
return getDisplayKeywordValueInternal(new ULocale(localeID), keyword,
new ULocale(displayLocaleID));
}
/**
* [icu] Returns a keyword value localized for display in the specified locale.
* This is a cover for the ICU4C API.
* @param localeID the id of the locale whose keyword value is to be displayed.
* @param keyword the keyword whose value is to be displayed.
* @param displayLocale the id of the locale in which to display the value.
* @return the localized value name.
*/
public static String getDisplayKeywordValue(String localeID, String keyword,
ULocale displayLocale) {
return getDisplayKeywordValueInternal(new ULocale(localeID), keyword, displayLocale);
}
// displayLocaleID is canonical, localeID need not be since parsing will fix this.
private static String getDisplayKeywordValueInternal(ULocale locale, String keyword,
ULocale displayLocale) {
keyword = AsciiUtil.toLowerString(keyword.trim());
String value = locale.getKeywordValue(keyword);
return LocaleDisplayNames.getInstance(displayLocale).keyValueDisplayName(keyword, value);
}
/**
* Returns this locale name localized for display in the default DISPLAY
locale.
* @return the localized locale name.
* @see Category#DISPLAY
*/
public String getDisplayName() {
return getDisplayNameInternal(this, getDefault(Category.DISPLAY));
}
/**
* Returns this locale name localized for display in the provided locale.
* @param displayLocale the locale in which to display the locale name.
* @return the localized locale name.
*/
public String getDisplayName(ULocale displayLocale) {
return getDisplayNameInternal(this, displayLocale);
}
/**
* [icu] Returns the locale ID localized for display in the provided locale.
* This is a cover for the ICU4C API.
* @param localeID the locale whose name is to be displayed.
* @param displayLocaleID the id of the locale in which to display the locale name.
* @return the localized locale name.
*/
public static String getDisplayName(String localeID, String displayLocaleID) {
return getDisplayNameInternal(new ULocale(localeID), new ULocale(displayLocaleID));
}
/**
* [icu] Returns the locale ID localized for display in the provided locale.
* This is a cover for the ICU4C API.
* @param localeID the locale whose name is to be displayed.
* @param displayLocale the locale in which to display the locale name.
* @return the localized locale name.
*/
public static String getDisplayName(String localeID, ULocale displayLocale) {
return getDisplayNameInternal(new ULocale(localeID), displayLocale);
}
private static String getDisplayNameInternal(ULocale locale, ULocale displayLocale) {
return LocaleDisplayNames.getInstance(displayLocale).localeDisplayName(locale);
}
/**
* [icu] Returns this locale name localized for display in the default DISPLAY
locale.
* If a dialect name is present in the locale data, then it is returned.
* @return the localized locale name.
* @see Category#DISPLAY
*/
public String getDisplayNameWithDialect() {
return getDisplayNameWithDialectInternal(this, getDefault(Category.DISPLAY));
}
/**
* [icu] Returns this locale name localized for display in the provided locale.
* If a dialect name is present in the locale data, then it is returned.
* @param displayLocale the locale in which to display the locale name.
* @return the localized locale name.
*/
public String getDisplayNameWithDialect(ULocale displayLocale) {
return getDisplayNameWithDialectInternal(this, displayLocale);
}
/**
* [icu] Returns the locale ID localized for display in the provided locale.
* If a dialect name is present in the locale data, then it is returned.
* This is a cover for the ICU4C API.
* @param localeID the locale whose name is to be displayed.
* @param displayLocaleID the id of the locale in which to display the locale name.
* @return the localized locale name.
*/
public static String getDisplayNameWithDialect(String localeID, String displayLocaleID) {
return getDisplayNameWithDialectInternal(new ULocale(localeID),
new ULocale(displayLocaleID));
}
/**
* [icu] Returns the locale ID localized for display in the provided locale.
* If a dialect name is present in the locale data, then it is returned.
* This is a cover for the ICU4C API.
* @param localeID the locale whose name is to be displayed.
* @param displayLocale the locale in which to display the locale name.
* @return the localized locale name.
*/
public static String getDisplayNameWithDialect(String localeID, ULocale displayLocale) {
return getDisplayNameWithDialectInternal(new ULocale(localeID), displayLocale);
}
private static String getDisplayNameWithDialectInternal(ULocale locale, ULocale displayLocale) {
return LocaleDisplayNames.getInstance(displayLocale, DialectHandling.DIALECT_NAMES)
.localeDisplayName(locale);
}
/**
* [icu] Returns this locale's layout orientation for characters. The possible
* values are "left-to-right", "right-to-left", "top-to-bottom" or
* "bottom-to-top".
* @return The locale's layout orientation for characters.
*/
public String getCharacterOrientation() {
return ICUResourceTableAccess.getTableString(ICUData.ICU_BASE_NAME, this,
"layout", "characters", "characters");
}
/**
* [icu] Returns this locale's layout orientation for lines. The possible
* values are "left-to-right", "right-to-left", "top-to-bottom" or
* "bottom-to-top".
* @return The locale's layout orientation for lines.
*/
public String getLineOrientation() {
return ICUResourceTableAccess.getTableString(ICUData.ICU_BASE_NAME, this,
"layout", "lines", "lines");
}
/**
* [icu] Selector for getLocale() indicating the locale of the
* resource containing the data. This is always at or above the
* valid locale. If the valid locale does not contain the
* specific data being requested, then the actual locale will be
* above the valid locale. If the object was not constructed from
* locale data, then the valid locale is null.
*
* @hide draft / provisional / internal are hidden on Android
*/
public static Type ACTUAL_LOCALE = new Type();
/**
* [icu] Selector for getLocale() indicating the most specific
* locale for which any data exists. This is always at or above
* the requested locale, and at or below the actual locale. If
* the requested locale does not correspond to any resource data,
* then the valid locale will be above the requested locale. If
* the object was not constructed from locale data, then the
* actual locale is null.
*
*
*
* http://www.unicode.org/reports/tr35/#Likely_Subtags
*
* If the provided ULocale instance is already in the minimal form, or there
* is no data available for minimization, it will be returned. Since the
* minimization algorithm relies on proper maximization, see the comments
* for addLikelySubtags for reasons why there might not be any data.
*
* Examples:
*
* "en_Latn_US" minimizes to "en"
*
* "de_Latn_US" minimizes to "de"
*
* "sr_Cyrl_RS" minimizes to "sr"
*
* "zh_Hant_TW" minimizes to "zh_TW" (The region is preferred to the
* script, and minimizing to "zh" would imply "zh_Hans_CN".)
*
* @param loc The ULocale to minimize
* @return The minimized ULocale instance.
*/
public static ULocale minimizeSubtags(ULocale loc) {
return minimizeSubtags(loc, Minimize.FAVOR_REGION);
}
/**
* Options for minimizeSubtags.
* @deprecated This API is ICU internal only.
* @hide Only a subset of ICU is exposed in Android
* @hide original deprecated declaration
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
public enum Minimize {
/**
* Favor including the script, when either the region or the script could be suppressed, but not both.
* @deprecated This API is ICU internal only.
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
FAVOR_SCRIPT,
/**
* Favor including the region, when either the region or the script could be suppressed, but not both.
* @deprecated This API is ICU internal only.
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
FAVOR_REGION
}
/**
* [icu] Minimizes the subtags for a provided locale ID, per the algorithm described
* in the following CLDR technical report:
*
* http://www.unicode.org/reports/tr35/#Likely_Subtags
*
* If the provided ULocale instance is already in the minimal form, or there
* is no data available for minimization, it will be returned. Since the
* minimization algorithm relies on proper maximization, see the comments
* for addLikelySubtags for reasons why there might not be any data.
*
* Examples:
*
* "en_Latn_US" minimizes to "en"
*
* "de_Latn_US" minimizes to "de"
*
* "sr_Cyrl_RS" minimizes to "sr"
*
* "zh_Hant_TW" minimizes to "zh_TW" if fieldToFavor == {@link Minimize#FAVOR_REGION}
* "zh_Hant_TW" minimizes to "zh_Hant" if fieldToFavor == {@link Minimize#FAVOR_SCRIPT}
*
* The fieldToFavor only has an effect if either the region or the script could be suppressed, but not both.
* @param loc The ULocale to minimize
* @param fieldToFavor Indicate which should be preferred, when either the region or the script could be suppressed, but not both.
* @return The minimized ULocale instance.
* @deprecated This API is ICU internal only.
* @hide original deprecated declaration
* @hide draft / provisional / internal are hidden on Android
*/
@Deprecated
public static ULocale minimizeSubtags(ULocale loc, Minimize fieldToFavor) {
String[] tags = new String[3];
String trailing = null;
int trailingIndex = parseTagString(
loc.localeID,
tags);
if (trailingIndex < loc.localeID.length()) {
trailing = loc.localeID.substring(trailingIndex);
}
LSR lsr = LikelySubtags.INSTANCE.minimizeSubtags(
loc.getLanguage(), loc.getScript(), loc.getCountry(), fieldToFavor);
String newLocaleID = createTagString(lsr.language, lsr.script, lsr.region,
trailing);
return newLocaleID == null ? loc : new ULocale(newLocaleID);
}
/**
* A trivial utility function that checks for a null
* reference or checks the length of the supplied String.
*
* @param string The string to check
*
* @return true if the String is empty, or if the reference is null.
*/
private static boolean isEmptyString(String string) {
return string == null || string.length() == 0;
}
/**
* Append a tag to a StringBuilder, adding the separator if necessary.The tag must
* not be a zero-length string.
*
* @param tag The tag to add.
* @param buffer The output buffer.
**/
private static void appendTag(String tag, StringBuilder buffer) {
if (buffer.length() != 0) {
buffer.append(UNDERSCORE);
}
buffer.append(tag);
}
/**
* Create a tag string from the supplied parameters. The lang, script and region
* parameters may be null references.
*
* If any of the language, script or region parameters are empty, and the alternateTags
* parameter is not null, it will be parsed for potential language, script and region tags
* to be used when constructing the new tag. If the alternateTags parameter is null, or
* it contains no language tag, the default tag for the unknown language is used.
*
* @param lang The language tag to use.
* @param script The script tag to use.
* @param region The region tag to use.
* @param trailing Any trailing data to append to the new tag.
* @param alternateTags A string containing any alternate tags.
* @return The new tag string.
**/
private static String createTagString(String lang, String script, String region,
String trailing) {
LocaleIDParser parser = null;
StringBuilder tag = new StringBuilder();
if (!isEmptyString(lang)) {
appendTag(
lang,
tag);
} else {
/*
* Append the value for an unknown language, if
* we found no language.
*/
appendTag(
UNDEFINED_LANGUAGE,
tag);
}
if (!isEmptyString(script)) {
appendTag(
script,
tag);
}
if (!isEmptyString(region)) {
appendTag(
region,
tag);
}
if (trailing != null && trailing.length() > 1) {
/*
* The current ICU format expects two underscores
* will separate the variant from the preceding
* parts of the tag, if there is no region.
*/
int separators = 0;
if (trailing.charAt(0) == UNDERSCORE) {
if (trailing.charAt(1) == UNDERSCORE) {
separators = 2;
}
}
else {
separators = 1;
}
if (!isEmptyString(region)) {
/*
* If we appended a region, we may need to strip
* the extra separator from the variant portion.
*/
if (separators == 2) {
tag.append(trailing.substring(1));
}
else {
tag.append(trailing);
}
}
else {
/*
* If we did not append a region, we may need to add
* an extra separator to the variant portion.
*/
if (separators == 1) {
tag.append(UNDERSCORE);
}
tag.append(trailing);
}
}
return tag.toString();
}
/**
* Parse the language, script, and region subtags from a tag string, and return the results.
*
* This function does not return the canonical strings for the unknown script and region.
*
* @param localeID The locale ID to parse.
* @param tags An array of three String references to return the subtag strings.
* @return The number of chars of the localeID parameter consumed.
**/
private static int parseTagString(String localeID, String tags[]) {
LocaleIDParser parser = new LocaleIDParser(localeID);
String lang = parser.getLanguage();
String script = parser.getScript();
String region = parser.getCountry();
if (isEmptyString(lang)) {
tags[0] = UNDEFINED_LANGUAGE;
}
else {
tags[0] = lang;
}
if (script.equals(UNDEFINED_SCRIPT)) {
tags[1] = "";
}
else {
tags[1] = script;
}
if (region.equals(UNDEFINED_REGION)) {
tags[2] = "";
}
else {
tags[2] = region;
}
/*
* Search for the variant. If there is one, then return the index of
* the preceding separator.
* If there's no variant, search for the keyword delimiter,
* and return its index. Otherwise, return the length of the
* string.
*
* $TOTO(dbertoni) we need to take into account that we might
* find a part of the language as the variant, since it can
* can have a variant portion that is long enough to contain
* the same characters as the variant.
*/
String variant = parser.getVariant();
if (!isEmptyString(variant)){
int index = localeID.indexOf(variant);
return index > 0 ? index - 1 : index;
}
else
{
int index = localeID.indexOf('@');
return index == -1 ? localeID.length() : index;
}
}
// --------------------------------
// BCP47/OpenJDK APIs
// --------------------------------
/**
* The key for the private use locale extension ('x').
*
* @see #getExtension(char)
* @see Builder#setExtension(char, String)
*/
public static final char PRIVATE_USE_EXTENSION = 'x';
/**
* The key for Unicode locale extension ('u').
*
* @see #getExtension(char)
* @see Builder#setExtension(char, String)
*/
public static final char UNICODE_LOCALE_EXTENSION = 'u';
/**
* Returns the extension (or private use) value associated with
* the specified key, or null if there is no extension
* associated with the key. To be well-formed, the key must be one
* of [0-9A-Za-z]
. Keys are case-insensitive, so
* for example 'z' and 'Z' represent the same extension.
*
* @param key the extension key
* @return The extension, or null if this locale defines no
* extension for the specified key.
* @throws IllegalArgumentException if key is not well-formed
* @see #PRIVATE_USE_EXTENSION
* @see #UNICODE_LOCALE_EXTENSION
*/
public String getExtension(char key) {
if (!LocaleExtensions.isValidKey(key)) {
throw new IllegalArgumentException("Invalid extension key: " + key);
}
return extensions().getExtensionValue(key);
}
/**
* Returns the set of extension keys associated with this locale, or the
* empty set if it has no extensions. The returned set is unmodifiable.
* The keys will all be lower-case.
*
* @return the set of extension keys, or the empty set if this locale has
* no extensions
*/
public Setkey
is null
*/
public String getUnicodeLocaleType(String key) {
if (!LocaleExtensions.isValidUnicodeLocaleKey(key)) {
throw new IllegalArgumentException("Invalid Unicode locale key: " + key);
}
return extensions().getUnicodeLocaleType(key);
}
/**
* Returns the set of Unicode locale keys defined by this locale, or the empty set if
* this locale has none. The returned set is immutable. Keys are all lower case.
*
* @return The set of Unicode locale keys, or the empty set if this locale has
* no Unicode locale keywords.
*/
public SetULocale
has a language, script, country, or
* variant that does not satisfy the IETF BCP 47 language tag
* syntax requirements, this method handles these fields as
* described below:
*
*
*
*
*
* [0-9a-zA-Z]{1,8}
* (for example "WIN" or "Oracle_JDK_Standard_Edition"), the first
* ill-formed sub-segment and all following will be appended to
* the private use subtag. The first appended subtag will be
* "lvariant", followed by the sub-segments in order, separated by
* hyphen. For example, "x-lvariant-WIN",
* "Oracle-x-lvariant-JDK-Standard-Edition".
*
* [0-9a-zA-Z]{1,8}
, the variant will be truncated
* and the problematic sub-segment and all following sub-segments
* will be omitted. If the remainder is non-empty, it will be
* emitted as a private use subtag as above (even if the remainder
* turns out to be well-formed). For example,
* "Solaris_isjustthecoolestthing" is emitted as
* "x-lvariant-Solaris", not as "solaris".
* new Locale("xx", "YY").toLanguageTag();
*
* will return "xx-YY", but the language subtag "xx" and the
* region subtag "YY" are invalid because they are not registered
* in the IANA Language Subtag Registry.
*
* @return a BCP47 language tag representing the locale
* @see #forLanguageTag(String)
*/
public String toLanguageTag() {
BaseLocale base = base();
LocaleExtensions exts = extensions();
if (base.getVariant().equalsIgnoreCase("POSIX")) {
// special handling for variant POSIX
base = BaseLocale.getInstance(base.getLanguage(), base.getScript(), base.getRegion(), "");
if (exts.getUnicodeLocaleType("va") == null) {
// add va-posix
InternalLocaleBuilder ilocbld = new InternalLocaleBuilder();
try {
ilocbld.setLocale(BaseLocale.ROOT, exts);
ilocbld.setUnicodeLocaleKeyword("va", "posix");
exts = ilocbld.getLocaleExtensions();
} catch (LocaleSyntaxException e) {
// this should not happen
throw new RuntimeException(e);
}
}
}
LanguageTag tag = LanguageTag.parseLocale(base, exts);
StringBuilder buf = new StringBuilder();
String subtag = tag.getLanguage();
if (subtag.length() > 0) {
buf.append(LanguageTag.canonicalizeLanguage(subtag));
}
subtag = tag.getScript();
if (subtag.length() > 0) {
buf.append(LanguageTag.SEP);
buf.append(LanguageTag.canonicalizeScript(subtag));
}
subtag = tag.getRegion();
if (subtag.length() > 0) {
buf.append(LanguageTag.SEP);
buf.append(LanguageTag.canonicalizeRegion(subtag));
}
List
*
*
*
*
* ULocale loc;
* loc = ULocale.forLanguageTag("en-US-x-lvariant-icu4j);
* loc.getVariant(); // returns "ICU4J"
* loc.getExtension('x'); // returns null
*
* loc = Locale.forLanguageTag("de-icu4j-x-URP-lvariant-Abc-Def");
* loc.getVariant(); // returns "ICU4J_ABC_DEF"
* loc.getExtension('x'); // returns "urp"
*
*
*
* ULocale.forLanguageTag("ar-aao").getLanguage(); // returns "aao"
* ULocale.forLanguageTag("en-abc-def-us").toString(); // returns "abc_US"
*
*
* toLanguageTag
* and forLanguageTag
will round-trip.
*
* @param languageTag the language tag
* @return The locale that best represents the language tag.
* @throws NullPointerException if languageTag
is null
* @see #toLanguageTag()
* @see ULocale.Builder#setLanguageTag(String)
*/
public static ULocale forLanguageTag(String languageTag) {
LanguageTag tag = LanguageTag.parse(languageTag, null);
InternalLocaleBuilder bldr = new InternalLocaleBuilder();
bldr.setLanguageTag(tag);
return getInstance(bldr.getBaseLocale(), bldr.getLocaleExtensions());
}
/**
* [icu] Converts the specified keyword (legacy key, or BCP 47 Unicode locale
* extension key) to the equivalent BCP 47 Unicode locale extension key.
* For example, BCP 47 Unicode locale extension key "co" is returned for
* the input keyword "collation".
* toUnicodeLocaleKey("ZZ")
returns "zz".
*
* @param keyword the input locale keyword (either legacy key
* such as "collation" or BCP 47 Unicode locale extension
* key such as "co").
* @return the well-formed BCP 47 Unicode locale extension key,
* or null if the specified locale keyword cannot be mapped
* to a well-formed BCP 47 Unicode locale extension key.
* @see #toLegacyKey(String)
*/
public static String toUnicodeLocaleKey(String keyword) {
String bcpKey = KeyTypeData.toBcpKey(keyword);
if (bcpKey == null && UnicodeLocaleExtension.isKey(keyword)) {
// unknown keyword, but syntax is fine..
bcpKey = AsciiUtil.toLowerString(keyword);
}
return bcpKey;
}
/**
* [icu] Converts the specified keyword value (legacy type, or BCP 47
* Unicode locale extension type) to the well-formed BCP 47 Unicode locale
* extension type for the specified keyword (category). For example, BCP 47
* Unicode locale extension type "phonebk" is returned for the input
* keyword value "phonebook", with the keyword "collation" (or "co").
* toUnicodeLocaleType("Foo", "Bar")
returns "bar",
* toUnicodeLocaleType("variableTop", "00A4")
returns "00a4".
*
* @param keyword the locale keyword (either legacy key such as
* "collation" or BCP 47 Unicode locale extension
* key such as "co").
* @param value the locale keyword value (either legacy type
* such as "phonebook" or BCP 47 Unicode locale extension
* type such as "phonebk").
* @return the well-formed BCP47 Unicode locale extension type,
* or null if the locale keyword value cannot be mapped to
* a well-formed BCP 47 Unicode locale extension type.
* @see #toLegacyType(String, String)
*/
public static String toUnicodeLocaleType(String keyword, String value) {
String bcpType = KeyTypeData.toBcpType(keyword, value, null, null);
if (bcpType == null && UnicodeLocaleExtension.isType(value)) {
// unknown keyword, but syntax is fine..
bcpType = AsciiUtil.toLowerString(value);
}
return bcpType;
}
/**
* [icu] Converts the specified keyword (BCP 47 Unicode locale extension key, or
* legacy key) to the legacy key. For example, legacy key "collation" is
* returned for the input BCP 47 Unicode locale extension key "co".
*
* @param keyword the input locale keyword (either BCP 47 Unicode locale
* extension key or legacy key).
* @return the well-formed legacy key, or null if the specified
* keyword cannot be mapped to a well-formed legacy key.
* @see #toUnicodeLocaleKey(String)
*/
public static String toLegacyKey(String keyword) {
String legacyKey = KeyTypeData.toLegacyKey(keyword);
if (legacyKey == null) {
// Checks if the specified locale key is well-formed with the legacy locale syntax.
//
// Note:
// Neither ICU nor LDML/CLDR provides the definition of keyword syntax.
// However, a key should not contain '=' obviously. For now, all existing
// keys are using ASCII alphabetic letters only. We won't add any new key
// that is not compatible with the BCP 47 syntax. Therefore, we assume
// a valid key consist from [0-9a-zA-Z], no symbols.
if (keyword.matches("[0-9a-zA-Z]+")) {
legacyKey = AsciiUtil.toLowerString(keyword);
}
}
return legacyKey;
}
/**
* [icu] Converts the specified keyword value (BCP 47 Unicode locale extension type,
* or legacy type or type alias) to the canonical legacy type. For example,
* the legacy type "phonebook" is returned for the input BCP 47 Unicode
* locale extension type "phonebk" with the keyword "collation" (or "co").
* toLegacyType("Foo", "Bar")
returns "bar",
* toLegacyType("vt", "00A4")
returns "00a4".
*
* @param keyword the locale keyword (either legacy keyword such as
* "collation" or BCP 47 Unicode locale extension
* key such as "co").
* @param value the locale keyword value (either BCP 47 Unicode locale
* extension type such as "phonebk" or legacy keyword value
* such as "phonebook").
* @return the well-formed legacy type, or null if the specified
* keyword value cannot be mapped to a well-formed legacy
* type.
* @see #toUnicodeLocaleType(String, String)
*/
public static String toLegacyType(String keyword, String value) {
String legacyType = KeyTypeData.toLegacyType(keyword, value, null, null);
if (legacyType == null) {
// Checks if the specified locale type is well-formed with the legacy locale syntax.
//
// Note:
// Neither ICU nor LDML/CLDR provides the definition of keyword syntax.
// However, a type should not contain '=' obviously. For now, all existing
// types are using ASCII alphabetic letters with a few symbol letters. We won't
// add any new type that is not compatible with the BCP 47 syntax except timezone
// IDs. For now, we assume a valid type start with [0-9a-zA-Z], but may contain
// '-' '_' '/' in the middle.
if (value.matches("[0-9a-zA-Z]+([_/\\-][0-9a-zA-Z]+)*")) {
legacyType = AsciiUtil.toLowerString(value);
}
}
return legacyType;
}
/**
* Builder
is used to build instances of ULocale
* from values configured by the setters. Unlike the ULocale
* constructors, the Builder
checks if a value configured by a
* setter satisfies the syntax requirements defined by the ULocale
* class. A ULocale
object created by a Builder
is
* well-formed and can be transformed to a well-formed IETF BCP 47 language tag
* without losing information.
*
* ULocale
class does not provide any
* syntactic restrictions on variant, while BCP 47 requires each variant
* subtag to be 5 to 8 alphanumerics or a single numeric followed by 3
* alphanumerics. The method setVariant
throws
* IllformedLocaleException
for a variant that does not satisfy
* this restriction. If it is necessary to support such a variant, use a
* ULocale constructor. However, keep in mind that a ULocale
* object created this way might lose the variant information when
* transformed to a BCP 47 language tag.
*
* Locale
object
* with the Builder
.
*
*
*
*
* ULocale aLocale = new Builder().setLanguage("sr").setScript("Latn").setRegion("RS").build();
*
* clear()
resets all
* fields to their default values.
*
* @see ULocale#toLanguageTag()
*/
public static final class Builder {
private final InternalLocaleBuilder _locbld;
/**
* Constructs an empty Builder. The default value of all
* fields, extensions, and private use information is the
* empty string.
*/
public Builder() {
_locbld = new InternalLocaleBuilder();
}
/**
* Resets the Builder
to match the provided
* locale
. Existing state is discarded.
*
* IllformedLocaleException
to be thrown.
*
* @param locale the locale
* @return This builder.
* @throws IllformedLocaleException if locale
has
* any ill-formed fields.
* @throws NullPointerException if locale
is null.
*/
public Builder setLocale(ULocale locale) {
try {
_locbld.setLocale(locale.base(), locale.extensions());
} catch (LocaleSyntaxException e) {
throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
}
return this;
}
/**
* Resets the Builder to match the provided IETF BCP 47
* language tag. Discards the existing state. Null and the
* empty string cause the builder to be reset, like {@link
* #clear}. Legacy tags (see {@link
* ULocale#forLanguageTag}) are converted to their canonical
* form before being processed. Otherwise, the language tag
* must be well-formed (see {@link ULocale}) or an exception is
* thrown (unlike ULocale.forLanguageTag
, which
* just discards ill-formed and following portions of the
* tag).
*
* @param languageTag the language tag
* @return This builder.
* @throws IllformedLocaleException if languageTag
is ill-formed
* @see ULocale#forLanguageTag(String)
*/
public Builder setLanguageTag(String languageTag) {
ParseStatus sts = new ParseStatus();
LanguageTag tag = LanguageTag.parse(languageTag, sts);
if (sts.isError()) {
throw new IllformedLocaleException(sts.getErrorMessage(), sts.getErrorIndex());
}
_locbld.setLanguageTag(tag);
return this;
}
/**
* Sets the language. If language
is the empty string or
* null, the language in this Builder
is removed. Otherwise,
* the language must be well-formed
* or an exception is thrown.
*
* language
is ill-formed
*/
public Builder setLanguage(String language) {
try {
_locbld.setLanguage(language);
} catch (LocaleSyntaxException e) {
throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
}
return this;
}
/**
* Sets the script. If script
is null or the empty string,
* the script in this Builder
is removed.
* Otherwise, the script must be well-formed or an exception is thrown.
*
* script
is ill-formed
*/
public Builder setScript(String script) {
try {
_locbld.setScript(script);
} catch (LocaleSyntaxException e) {
throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
}
return this;
}
/**
* Sets the region. If region is null or the empty string, the region
* in this Builder
is removed. Otherwise,
* the region must be well-formed or an exception is thrown.
*
* Locale
created by the
* Builder
is always normalized to upper case.
*
* @param region the region
* @return This builder.
* @throws IllformedLocaleException if region
is ill-formed
*/
public Builder setRegion(String region) {
try {
_locbld.setRegion(region);
} catch (LocaleSyntaxException e) {
throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
}
return this;
}
/**
* Sets the variant. If variant is null or the empty string, the
* variant in this Builder
is removed. Otherwise, it
* must consist of one or more well-formed subtags, or an exception is thrown.
*
* variant
* satisfies the IETF BCP 47 variant subtag's syntax requirements,
* and normalizes the value to lowercase letters. However,
* the ULocale
class does not impose any syntactic
* restriction on variant. To set such a variant,
* use a ULocale constructor.
*
* @param variant the variant
* @return This builder.
* @throws IllformedLocaleException if variant
is ill-formed
*/
public Builder setVariant(String variant) {
try {
_locbld.setVariant(variant);
} catch (LocaleSyntaxException e) {
throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
}
return this;
}
/**
* Sets the extension for the given key. If the value is null or the
* empty string, the extension is removed. Otherwise, the extension
* must be well-formed or an exception is thrown.
*
* key
is illegal
* or value
is ill-formed
* @see #setUnicodeLocaleKeyword(String, String)
*/
public Builder setExtension(char key, String value) {
try {
_locbld.setExtension(key, value);
} catch (LocaleSyntaxException e) {
throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
}
return this;
}
/**
* Sets the Unicode locale keyword type for the given key. If the type
* is null, the Unicode keyword is removed. Otherwise, the key must be
* non-null and both key and type must be well-formed or an exception
* is thrown.
*
* key
or type
* is ill-formed
* @throws NullPointerException if key
is null
* @see #setExtension(char, String)
*/
public Builder setUnicodeLocaleKeyword(String key, String type) {
try {
_locbld.setUnicodeLocaleKeyword(key, type);
} catch (LocaleSyntaxException e) {
throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
}
return this;
}
/**
* Adds a unicode locale attribute, if not already present, otherwise
* has no effect. The attribute must not be null and must be well-formed
* or an exception is thrown.
*
* @param attribute the attribute
* @return This builder.
* @throws NullPointerException if attribute
is null
* @throws IllformedLocaleException if attribute
is ill-formed
* @see #setExtension(char, String)
*/
public Builder addUnicodeLocaleAttribute(String attribute) {
try {
_locbld.addUnicodeLocaleAttribute(attribute);
} catch (LocaleSyntaxException e) {
throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
}
return this;
}
/**
* Removes a unicode locale attribute, if present, otherwise has no
* effect. The attribute must not be null and must be well-formed
* or an exception is thrown.
*
* attribute
is null
* @throws IllformedLocaleException if attribute
is ill-formed
* @see #setExtension(char, String)
*/
public Builder removeUnicodeLocaleAttribute(String attribute) {
try {
_locbld.removeUnicodeLocaleAttribute(attribute);
} catch (LocaleSyntaxException e) {
throw new IllformedLocaleException(e.getMessage(), e.getErrorIndex());
}
return this;
}
/**
* Resets the builder to its initial, empty state.
*
* @return this builder
*/
public Builder clear() {
_locbld.clear();
return this;
}
/**
* Resets the extensions to their initial, empty state.
* Language, script, region and variant are unchanged.
*
* @return this builder
* @see #setExtension(char, String)
*/
public Builder clearExtensions() {
_locbld.clearExtensions();
return this;
}
/**
* Returns an instance of ULocale
created from the fields set
* on this builder.
*
* @return a new Locale
*/
public ULocale build() {
return getInstance(_locbld.getBaseLocale(), _locbld.getLocaleExtensions());
}
}
private static ULocale getInstance(BaseLocale base, LocaleExtensions exts) {
String id = lscvToID(base.getLanguage(), base.getScript(), base.getRegion(),
base.getVariant());
Set