/*
******************************************************************************
-* Copyright (C) 2003-2011, International Business Machines Corporation and *
-* others. All Rights Reserved. *
+* Copyright (C) 2003-2013, International Business Machines Corporation and
+* others. All Rights Reserved.
******************************************************************************
*/
import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.text.ParseException;
import java.util.Iterator;
import java.util.List;
* Keep our own default ULocale.
*/
private static Locale defaultLocale = Locale.getDefault();
- private static ULocale defaultULocale = forLocale(defaultLocale);
+ private static ULocale defaultULocale;
private static Locale[] defaultCategoryLocales = new Locale[Category.values().length];
private static ULocale[] defaultCategoryULocales = new ULocale[Category.values().length];
static {
- for (Category cat: Category.values()) {
- int idx = cat.ordinal();
- defaultCategoryLocales[idx] = JDKLocaleHelper.getDefault(cat);
- defaultCategoryULocales[idx] = forLocale(defaultCategoryLocales[idx]);
+ defaultULocale = forLocale(defaultLocale);
+
+ // For Java 6 or older JRE, ICU initializes the default script from
+ // "user.script" system property. The system property was added
+ // in Java 7. On JRE 7, Locale.getDefault() should reflect the
+ // property value to the Locale's default. So ICU just relies on
+ // Locale.getDefault().
+
+ // Note: The "user.script" property is only used by initialization.
+ //
+ if (JDKLocaleHelper.isJava7orNewer()) {
+ for (Category cat: Category.values()) {
+ int idx = cat.ordinal();
+ defaultCategoryLocales[idx] = JDKLocaleHelper.getDefault(cat);
+ defaultCategoryULocales[idx] = forLocale(defaultCategoryLocales[idx]);
+ }
+ } else {
+ // Make sure the current default Locale is original.
+ // If not, it means that someone updated the default Locale.
+ // In this case, user.XXX properties are already out of date
+ // and we should not use user.script.
+ if (JDKLocaleHelper.isOriginalDefaultLocale(defaultLocale)) {
+ // Use "user.script" if available
+ String userScript = JDKLocaleHelper.getSystemProperty("user.script");
+ if (userScript != null && LanguageTag.isScript(userScript)) {
+ // Note: Builder or forLanguageTag cannot be used here
+ // when one of Locale fields is not well-formed.
+ BaseLocale base = defaultULocale.base();
+ BaseLocale newBase = BaseLocale.getInstance(base.getLanguage(), userScript,
+ base.getRegion(), base.getVariant());
+ defaultULocale = getInstance(newBase, defaultULocale.extensions());
+ }
+ }
+
+ // Java 6 or older does not have separated 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.
+ * <p>
+ * The default ULocale is synchronized to the default Java Locale. This method checks
+ * the current default Java Locale and returns an equivalent ULocale.
+ * <p>
+ * <b>Note:</b> Before Java 7, the JDK Locale was not able to represent a locale's script.
+ * Therefore, the script field in the default ULocale is always empty unless
+ * a ULocale with non-empty script is explicitly set by {@link #setDefault(ULocale)}
+ * on Java 6 or older systems.
+ * <p>
+ * <b>Note for ICU 49 or later:</b> Some JRE implementations allow users to override the default
+ * JDK Locale using system properties - <code>user.language</code>, <code>user.country</code>
+ * and <code>user.variant</code>. In addition to these system properties, some Java 7
+ * implementations support <code>user.script</code> for overriding the default Locale's script.
+ * ICU 49 and later versions use the <code>user.script</code> system property on Java 6
+ * or older systems supporting other <code>user.*</code> system properties to initialize
+ * the default ULocale. The <code>user.script</code> override for default ULocale is not
+ * used on Java 7, or if the current Java default Locale is changed after start up.
+ *
* @return the default ULocale.
* @stable ICU 2.8
*/
public static ULocale getDefault() {
synchronized (ULocale.class) {
+ if (defaultULocale == 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. 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;
+ }
Locale currentDefault = Locale.getDefault();
if (!defaultLocale.equals(currentDefault)) {
defaultLocale = currentDefault;
/**
* Returns true if the other object is another ULocale with the
- * same full name, or is a String localeID that matches the full name.
+ * same full name.
* Note that since names are not canonicalized, two ULocales that
* function identically might not compare equal.
*
if (this == obj) {
return true;
}
- if (obj instanceof String) {
- return localeID.equals((String)obj);
- }
if (obj instanceof ULocale) {
return localeID.equals(((ULocale)obj).localeID);
}
}
/**
- * {@icu} Returns the (normalized) base name for this locale.
+ * {@icu} Returns the (normalized) base name for this locale,
+ * like {@link #getName()}, but without keywords.
+ *
* @return the base name as a String.
* @stable ICU 3.0
*/
}
/**
- * {@icu} Returns the (normalized) base name for the specified locale.
+ * {@icu} Returns the (normalized) base name for the specified locale,
+ * like {@link #getName(String)}, but without keywords.
+ *
* @param localeID the locale ID as a string
* @return the base name as a String.
* @stable ICU 3.0
/**
* Given a keyword and a value, return a new locale with an updated
- * keyword and value. If keyword is null, this removes all keywords from the locale id.
+ * 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.
+ *
+ * <p>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
/**
* Given a locale id, a keyword, and a value, return a new locale id with an updated
- * keyword and value. If keyword is null, this removes all keywords from the locale id.
+ * 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.
+ *
+ * <p>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 getDisplayScriptInternal(this, getDefault(Category.DISPLAY));
}
+ /**
+ * {@icu} Returns this locale's script localized for display in the default <code>DISPLAY</code> locale.
+ * @return the localized script name.
+ * @see Category#DISPLAY
+ * @internal ICU 49
+ * @deprecated This API is ICU internal only.
+ */
+ public String getDisplayScriptInContext() {
+ return getDisplayScriptInContextInternal(this, getDefault(Category.DISPLAY));
+ }
+
/**
* {@icu} Returns this locale's script localized for display in the provided locale.
* @param displayLocale the locale in which to display the name.
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.
+ * @internal ICU 49
+ * @deprecated This API is ICU internal only.
+ */
+ 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.
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.
+ * @internal ICU 49
+ * @deprecated This API is ICU internal only.
+ */
+ 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.
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.
+ * @internal ICU 49
+ * @deprecated This API is ICU internal only.
+ */
+ 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) {
.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 <code>DISPLAY</code> locale.
* @return the localized country name.
* @see #getExtension(char)
* @see Builder#setExtension(char, String)
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public static final char PRIVATE_USE_EXTENSION = 'x';
* @see #getExtension(char)
* @see Builder#setExtension(char, String)
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public static final char UNICODE_LOCALE_EXTENSION = 'u';
* @see #PRIVATE_USE_EXTENSION
* @see #UNICODE_LOCALE_EXTENSION
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public String getExtension(char key) {
if (!LocaleExtensions.isValidKey(key)) {
*
* @return the set of extension keys, or the empty set if this locale has
* no extensions
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Set<Character> getExtensionKeys() {
return extensions().getKeys();
* returned set is unmodifiable.
*
* @return The set of attributes.
- * @draft ICU 4.6
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.6
*/
public Set<String> getUnicodeLocaleAttributes() {
return extensions().getUnicodeLocaleAttributes();
* @throws IllegalArgumentException if the key is not well-formed
* @throws NullPointerException if <code>key</code> is null
*
- * @draft ICU 4.4
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.4
*/
public String getUnicodeLocaleType(String key) {
if (!LocaleExtensions.isValidUnicodeLocaleKey(key)) {
* @return The set of Unicode locale keys, or the empty set if this locale has
* no Unicode locale keywords.
*
- * @draft ICU 4.4
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.4
*/
public Set<String> getUnicodeLocaleKeys() {
return extensions().getUnicodeLocaleKeys();
* @return a BCP47 language tag representing the locale
* @see #forLanguageTag(String)
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public String toLanguageTag() {
BaseLocale base = base();
* @see #toLanguageTag()
* @see ULocale.Builder#setLanguageTag(String)
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public static ULocale forLanguageTag(String languageTag) {
LanguageTag tag = LanguageTag.parse(languageTag, null);
*
* @see ULocale#toLanguageTag()
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public static final class Builder {
* fields, extensions, and private use information is the
* empty string.
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Builder() {
_locbld = new InternalLocaleBuilder();
* any ill-formed fields.
* @throws NullPointerException if <code>locale</code> is null.
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Builder setLocale(ULocale locale) {
try {
* @throws IllformedLocaleException if <code>languageTag</code> is ill-formed
* @see ULocale#forLanguageTag(String)
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Builder setLanguageTag(String languageTag) {
ParseStatus sts = new ParseStatus();
* @return This builder.
* @throws IllformedLocaleException if <code>language</code> is ill-formed
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Builder setLanguage(String language) {
try {
* @return This builder.
* @throws IllformedLocaleException if <code>script</code> is ill-formed
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Builder setScript(String script) {
try {
* @return This builder.
* @throws IllformedLocaleException if <code>region</code> is ill-formed
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Builder setRegion(String region) {
try {
* @return This builder.
* @throws IllformedLocaleException if <code>variant</code> is ill-formed
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Builder setVariant(String variant) {
try {
* or <code>value</code> is ill-formed
* @see #setUnicodeLocaleKeyword(String, String)
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Builder setExtension(char key, String value) {
try {
* @throws NullPointerException if <code>key</code> is null
* @see #setExtension(char, String)
*
- * @draft ICU 4.4
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.4
*/
public Builder setUnicodeLocaleKeyword(String key, String type) {
try {
* @throws IllformedLocaleException if <code>attribute</code> is ill-formed
* @see #setExtension(char, String)
*
- * @draft ICU 4.6
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.6
*/
public Builder addUnicodeLocaleAttribute(String attribute) {
try {
* @throws IllformedLocaleException if <code>attribute</code> is ill-formed
* @see #setExtension(char, String)
*
- * @draft ICU 4.6
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.6
*/
public Builder removeUnicodeLocaleAttribute(String attribute) {
try {
*
* @return this builder
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Builder clear() {
_locbld.clear();
* @return this builder
* @see #setExtension(char, String)
*
- * @draft ICU 4.2
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.2
*/
public Builder clearExtensions() {
_locbld.clearExtensions();
*
* @return a new Locale
*
- * @draft ICU 4.4
- * @provisional This API might change or be removed in a future release.
+ * @stable ICU 4.4
*/
public ULocale build() {
return getInstance(_locbld.getBaseLocale(), _locbld.getLocaleExtensions());
String bcpType = uext.getUnicodeLocaleType(bcpKey);
// convert to legacy key/type
String lkey = bcp47ToLDMLKey(bcpKey);
- String ltype = bcp47ToLDMLType(lkey, ((bcpType.length() == 0) ? "true" : bcpType)); // use "true" as the value of typeless keywords
+ String ltype = bcp47ToLDMLType(lkey, ((bcpType.length() == 0) ? "yes" : bcpType)); // use "yes" as the value of typeless keywords
// special handling for u-va-posix, since this is a variant, not a keyword
if (lkey.equals("va") && ltype.equals("posix") && base.getVariant().length() == 0) {
id = id + "_POSIX";
if (kwKey.length() != 1) {
// Unicode locale key
kwKey = bcp47ToLDMLKey(kwKey);
- // use "true" as the value of typeless keywords
- kwVal = bcp47ToLDMLType(kwKey, ((kwVal.length() == 0) ? "true" : kwVal));
+ // use "yes" as the value of typeless keywords
+ kwVal = bcp47ToLDMLType(kwKey, ((kwVal.length() == 0) ? "yes" : kwVal));
}
if (addSep) {
}
}
}
+
+ // Returns true if the given Locale matches the original
+ // default locale initialized by JVM by checking user.XXX
+ // system properties. When the system properties are not accessible,
+ // this method returns false.
+ public static boolean isOriginalDefaultLocale(Locale loc) {
+ if (isJava7orNewer) {
+ String script = "";
+ try {
+ script = (String) mGetScript.invoke(loc, (Object[]) null);
+ } catch (Exception e) {
+ return false;
+ }
+
+ return loc.getLanguage().equals(getSystemProperty("user.language"))
+ && loc.getCountry().equals(getSystemProperty("user.country"))
+ && loc.getVariant().equals(getSystemProperty("user.variant"))
+ && script.equals(getSystemProperty("user.script"));
+ }
+ return loc.getLanguage().equals(getSystemProperty("user.language"))
+ && loc.getCountry().equals(getSystemProperty("user.country"))
+ && loc.getVariant().equals(getSystemProperty("user.variant"));
+ }
+
+ public static String getSystemProperty(String key) {
+ String val = null;
+ final String fkey = key;
+ if (System.getSecurityManager() != null) {
+ try {
+ val = AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return System.getProperty(fkey);
+ }
+ });
+ } catch (AccessControlException e) {
+ // ignore
+ }
+ } else {
+ val = System.getProperty(fkey);
+ }
+ return val;
+ }
}
}