package com.ibm.icu.util;
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;
// 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 uses Java reflection to create a Locale
- // with a script tag. When a new ULocale is constructed with the single arg
+ // 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.
//
static {
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
+ // 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.hasLocaleCategories()) {
- 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;
- }
+ for (Category cat: Category.values()) {
+ int idx = cat.ordinal();
+ defaultCategoryLocales[idx] = JDKLocaleHelper.getDefault(cat);
+ defaultCategoryULocales[idx] = forLocale(defaultCategoryLocales[idx]);
}
}
* <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 {@link java.util.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
- * {@link java.util.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
if (!defaultLocale.equals(currentDefault)) {
defaultLocale = currentDefault;
defaultULocale = forLocale(currentDefault);
-
- if (!JDKLocaleHelper.hasLocaleCategories()) {
- // Detected Java default Locale change.
- // We need to update category defaults to match the
- // Java 7's behavior on Java 6 or older environment.
- for (Category cat : Category.values()) {
- int idx = cat.ordinal();
- defaultCategoryLocales[idx] = currentDefault;
- defaultCategoryULocales[idx] = forLocale(currentDefault);
- }
- }
}
return defaultULocale;
}
// 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 Java 6 or older environment,
- // 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 Java 6 or older env,
- // there is no good way to detect the event, ICU4J simply
- // check if the default Java Locale has changed since last
- // time.
-
- Locale currentDefault = Locale.getDefault();
- if (!defaultLocale.equals(currentDefault)) {
- defaultLocale = 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 Java 6 or older versions
+ Locale currentCategoryDefault = JDKLocaleHelper.getDefault(category);
+ if (!defaultCategoryLocales[idx].equals(currentCategoryDefault)) {
+ defaultCategoryLocales[idx] = currentCategoryDefault;
+ defaultCategoryULocales[idx] = forLocale(currentCategoryDefault);
}
+
return defaultCategoryULocales[idx];
}
}
// parse out the acceptLanguage into an array
TreeMap<ULocaleAcceptLanguageQ, ULocale> map =
- new TreeMap<ULocaleAcceptLanguageQ, ULocale>();
+ new TreeMap<>();
StringBuilder languageRangeBuf = new StringBuilder();
StringBuilder qvalBuf = new StringBuilder();
int state = 0;
// other extensions are at the same level.
// e.g. @a=ext-for-aa;calendar=japanese;m=ext-for-mm;x=priv-use
- TreeMap<String, String> kwds = new TreeMap<String, String>();
+ TreeMap<String, String> kwds = new TreeMap<>();
for (Character key : extKeys) {
Extension ext = exts.getExtension(key);
if (ext instanceof UnicodeLocaleExtension) {
* JDK Locale Helper
*/
private static final class JDKLocaleHelper {
- private static boolean hasScriptsAndUnicodeExtensions = false;
- private static boolean hasLocaleCategories = false;
-
- /*
- * New methods in Java 7 Locale class
- */
- private static Method mGetScript;
- private static Method mGetExtensionKeys;
- private static Method mGetExtension;
- private static Method mGetUnicodeLocaleKeys;
- private static Method mGetUnicodeLocaleAttributes;
- private static Method mGetUnicodeLocaleType;
- private static Method mForLanguageTag;
-
- private static Method mGetDefault;
- private static Method mSetDefault;
- private static Object eDISPLAY;
- private static Object eFORMAT;
-
- /*
- * This table is used for mapping between ICU and special Java
- * 6 locales. When an ICU locale matches <minumum base> with
- * <keyword>/<value>, the ICU locale is mapped to <Java> locale.
- * For example, both ja_JP@calendar=japanese and ja@calendar=japanese
- * are mapped to Java locale "ja_JP_JP". ICU locale "nn" is mapped
- * to Java locale "no_NO_NY".
- */
- private static final String[][] JAVA6_MAPDATA = {
- // { <Java>, <ICU base>, <keyword>, <value>, <minimum base>
- { "ja_JP_JP", "ja_JP", "calendar", "japanese", "ja"},
- { "no_NO_NY", "nn_NO", null, null, "nn"},
- { "th_TH_TH", "th_TH", "numbers", "thai", "th"},
- };
-
- static {
- do {
- try {
- mGetScript = Locale.class.getMethod("getScript", (Class[]) null);
- mGetExtensionKeys = Locale.class.getMethod("getExtensionKeys", (Class[]) null);
- mGetExtension = Locale.class.getMethod("getExtension", char.class);
- mGetUnicodeLocaleKeys = Locale.class.getMethod("getUnicodeLocaleKeys", (Class[]) null);
- mGetUnicodeLocaleAttributes = Locale.class.getMethod("getUnicodeLocaleAttributes", (Class[]) null);
- mGetUnicodeLocaleType = Locale.class.getMethod("getUnicodeLocaleType", String.class);
- mForLanguageTag = Locale.class.getMethod("forLanguageTag", String.class);
-
- hasScriptsAndUnicodeExtensions = true;
- } catch (NoSuchMethodException e) {
- } catch (IllegalArgumentException e) {
- } catch (SecurityException e) {
- // TODO : report?
- }
-
- try {
- Class<?> cCategory = null;
- Class<?>[] classes = Locale.class.getDeclaredClasses();
- for (Class<?> c : classes) {
- if (c.getName().equals("java.util.Locale$Category")) {
- cCategory = c;
- break;
- }
- }
- if (cCategory == null) {
- break;
- }
- mGetDefault = Locale.class.getDeclaredMethod("getDefault", cCategory);
- mSetDefault = Locale.class.getDeclaredMethod("setDefault", cCategory, Locale.class);
-
- Method mName = cCategory.getMethod("name", (Class[]) null);
- Object[] enumConstants = cCategory.getEnumConstants();
- for (Object e : enumConstants) {
- String catVal = (String)mName.invoke(e, (Object[])null);
- if (catVal.equals("DISPLAY")) {
- eDISPLAY = e;
- } else if (catVal.equals("FORMAT")) {
- eFORMAT = e;
- }
- }
- if (eDISPLAY == null || eFORMAT == null) {
- break;
- }
-
- hasLocaleCategories = true;
- } catch (NoSuchMethodException e) {
- } catch (IllegalArgumentException e) {
- } catch (IllegalAccessException e) {
- } catch (InvocationTargetException e) {
- } catch (SecurityException e) {
- // TODO : report?
- }
- } while (false);
- }
private JDKLocaleHelper() {
}
- public static boolean hasLocaleCategories() {
- return hasLocaleCategories;
- }
-
public static ULocale toULocale(Locale loc) {
- return hasScriptsAndUnicodeExtensions ? toULocale7(loc) : toULocale6(loc);
- }
-
- public static Locale toLocale(ULocale uloc) {
- return hasScriptsAndUnicodeExtensions ? toLocale7(uloc) : toLocale6(uloc);
- }
-
- private static ULocale toULocale7(Locale loc) {
String language = loc.getLanguage();
String script = "";
String country = loc.getCountry();
Set<String> attributes = null;
Map<String, String> keywords = null;
- try {
- script = (String) mGetScript.invoke(loc, (Object[]) null);
- @SuppressWarnings("unchecked")
- Set<Character> extKeys = (Set<Character>) mGetExtensionKeys.invoke(loc, (Object[]) null);
- if (!extKeys.isEmpty()) {
- for (Character extKey : extKeys) {
- if (extKey.charValue() == 'u') {
- // Found Unicode locale extension
-
- // attributes
- @SuppressWarnings("unchecked")
- Set<String> uAttributes = (Set<String>) mGetUnicodeLocaleAttributes.invoke(loc, (Object[]) null);
- if (!uAttributes.isEmpty()) {
- attributes = new TreeSet<String>();
- for (String attr : uAttributes) {
- attributes.add(attr);
- }
+ script = loc.getScript();
+ Set<Character> extKeys = loc.getExtensionKeys();
+ if (!extKeys.isEmpty()) {
+ for (Character extKey : extKeys) {
+ if (extKey.charValue() == 'u') {
+ // Found Unicode locale extension
+
+ // attributes
+ @SuppressWarnings("unchecked")
+ Set<String> uAttributes = loc.getUnicodeLocaleAttributes();
+ if (!uAttributes.isEmpty()) {
+ attributes = new TreeSet<>();
+ for (String attr : uAttributes) {
+ attributes.add(attr);
}
+ }
- // keywords
- @SuppressWarnings("unchecked")
- Set<String> uKeys = (Set<String>) mGetUnicodeLocaleKeys.invoke(loc, (Object[]) null);
- for (String kwKey : uKeys) {
- String kwVal = (String) mGetUnicodeLocaleType.invoke(loc, kwKey);
- if (kwVal != null) {
- if (kwKey.equals("va")) {
- // va-* is interpreted as a variant
- variant = (variant.length() == 0) ? kwVal : kwVal + "_" + variant;
- } else {
- if (keywords == null) {
- keywords = new TreeMap<String, String>();
- }
- keywords.put(kwKey, kwVal);
+ // keywords
+ Set<String> uKeys = loc.getUnicodeLocaleKeys();
+ for (String kwKey : uKeys) {
+ String kwVal = loc.getUnicodeLocaleType(kwKey);
+ if (kwVal != null) {
+ if (kwKey.equals("va")) {
+ // va-* is interpreted as a variant
+ variant = (variant.length() == 0) ? kwVal : kwVal + "_" + variant;
+ } else {
+ if (keywords == null) {
+ keywords = new TreeMap<>();
}
+ keywords.put(kwKey, kwVal);
}
}
- } else {
- String extVal = (String) mGetExtension.invoke(loc, extKey);
- if (extVal != null) {
- if (keywords == null) {
- keywords = new TreeMap<String, String>();
- }
- keywords.put(String.valueOf(extKey), extVal);
+ }
+ } else {
+ String extVal = loc.getExtension(extKey);
+ if (extVal != null) {
+ if (keywords == null) {
+ keywords = new TreeMap<>();
}
+ keywords.put(String.valueOf(extKey), extVal);
}
}
}
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException(e);
}
// JDK locale no_NO_NY is not interpreted as Nynorsk by ICU,
attrBuf.append(attr);
}
if (keywords == null) {
- keywords = new TreeMap<String, String>();
+ keywords = new TreeMap<>();
}
keywords.put(LOCALE_ATTRIBUTE_KEY, attrBuf.toString());
}
return new ULocale(getName(buf.toString()), loc);
}
- private static ULocale toULocale6(Locale loc) {
- ULocale uloc = null;
- String locStr = loc.toString();
- if (locStr.length() == 0) {
- uloc = ULocale.ROOT;
- } else {
- for (int i = 0; i < JAVA6_MAPDATA.length; i++) {
- if (JAVA6_MAPDATA[i][0].equals(locStr)) {
- LocaleIDParser p = new LocaleIDParser(JAVA6_MAPDATA[i][1]);
- p.setKeywordValue(JAVA6_MAPDATA[i][2], JAVA6_MAPDATA[i][3]);
- locStr = p.getName();
- break;
- }
- }
- uloc = new ULocale(getName(locStr), loc);
- }
- return uloc;
- }
-
- private static Locale toLocale7(ULocale uloc) {
+ public static Locale toLocale(ULocale uloc) {
Locale loc = null;
String ulocStr = uloc.getName();
if (uloc.getScript().length() > 0 || ulocStr.contains("@")) {
// for variant. Because ICU always normalizes variant to
// upper case, we convert language tag to upper case here.
tag = AsciiUtil.toUpperString(tag);
-
- try {
- loc = (Locale)mForLanguageTag.invoke(null, tag);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException(e);
- }
+ loc = Locale.forLanguageTag(tag);
}
if (loc == null) {
// Without script or keywords, use a Locale constructor,
return loc;
}
- private static Locale toLocale6(ULocale uloc) {
- String locstr = uloc.getBaseName();
- for (int i = 0; i < JAVA6_MAPDATA.length; i++) {
- if (locstr.equals(JAVA6_MAPDATA[i][1]) || locstr.equals(JAVA6_MAPDATA[i][4])) {
- if (JAVA6_MAPDATA[i][2] != null) {
- String val = uloc.getKeywordValue(JAVA6_MAPDATA[i][2]);
- if (val != null && val.equals(JAVA6_MAPDATA[i][3])) {
- locstr = JAVA6_MAPDATA[i][0];
- break;
- }
- } else {
- locstr = JAVA6_MAPDATA[i][0];
- break;
- }
- }
- }
- LocaleIDParser p = new LocaleIDParser(locstr);
- String[] names = p.getLanguageScriptCountryVariant();
- return new Locale(names[0], names[2], names[3]);
- }
-
public static Locale getDefault(Category category) {
- Locale loc = Locale.getDefault();
- if (hasLocaleCategories) {
- Object cat = null;
+ java.util.Locale.Category cat = null;
+ if (category != null) {
switch (category) {
case DISPLAY:
- cat = eDISPLAY;
+ cat = java.util.Locale.Category.DISPLAY;
break;
case FORMAT:
- cat = eFORMAT;
+ cat = java.util.Locale.Category.FORMAT;
break;
}
- if (cat != null) {
- try {
- loc = (Locale)mGetDefault.invoke(null, cat);
- } catch (InvocationTargetException e) {
- // fall through - use the base default
- } catch (IllegalArgumentException e) {
- // fall through - use the base default
- } catch (IllegalAccessException e) {
- // fall through - use the base default
- }
- }
}
- return loc;
+ if (cat != null) {
+ return Locale.getDefault(cat);
+ }
+ return Locale.getDefault();
}
public static void setDefault(Category category, Locale newLocale) {
- if (hasLocaleCategories) {
- Object cat = null;
+ java.util.Locale.Category cat = null;
+ if (category != null) {
switch (category) {
case DISPLAY:
- cat = eDISPLAY;
+ cat = java.util.Locale.Category.DISPLAY;
break;
case FORMAT:
- cat = eFORMAT;
+ cat = java.util.Locale.Category.FORMAT;
break;
}
- if (cat != null) {
- try {
- mSetDefault.invoke(null, cat, newLocale);
- } catch (InvocationTargetException e) {
- // fall through - no effects
- } catch (IllegalArgumentException e) {
- // fall through - no effects
- } catch (IllegalAccessException e) {
- // fall through - no effects
- }
- }
}
- }
-
- // 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 (hasScriptsAndUnicodeExtensions) {
- 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>() {
- @Override
- public String run() {
- return System.getProperty(fkey);
- }
- });
- } catch (AccessControlException e) {
- // ignore
- }
+ if (cat != null) {
+ Locale.setDefault(cat, newLocale);
} else {
- val = System.getProperty(fkey);
+ Locale.setDefault(newLocale);
}
- return val;
}
}
}