From 1e3205b8692cee7d14c126ff4156380b793df538 Mon Sep 17 00:00:00 2001 From: Yoshito Umaoka Date: Thu, 9 Dec 2010 21:55:20 +0000 Subject: [PATCH] ICU-8078 Better ULocale/Locale mapping on JRE 7+ using the new Locale APIs. X-SVN-Rev: 29181 --- .../core/src/com/ibm/icu/util/ULocale.java | 338 +++++++++++++++--- .../test/format/IntlTestDateFormatAPI.java | 10 +- .../ibm/icu/dev/test/util/ULocaleTest.java | 149 +++++++- 3 files changed, 436 insertions(+), 61 deletions(-) diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/ULocale.java b/icu4j/main/classes/core/src/com/ibm/icu/util/ULocale.java index 6287c3bd2fb..4ab9b179e3c 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/util/ULocale.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/util/ULocale.java @@ -8,14 +8,18 @@ package com.ibm.icu.util; import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.text.ParseException; 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.Set; import java.util.TreeMap; +import java.util.TreeSet; import com.ibm.icu.impl.ICUCache; import com.ibm.icu.impl.ICUResourceBundle; @@ -241,7 +245,7 @@ public final class ULocale implements Serializable { // default empty locale private static final Locale EMPTY_LOCALE = new Locale("", ""); - // specia keyword key for Unicode locale attributes + // special keyword key for Unicode locale attributes private static final String LOCALE_ATTRIBUTE_KEY = "attribute"; /** @@ -360,21 +364,6 @@ public final class ULocale implements Serializable { } } - /* - * This table is used for mapping between ICU and special Java - * locales. When an ICU locale matches with - * /, the ICU locale is mapped to 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[][] _javaLocaleMap = { - // { , , , , - { "ja_JP_JP", "ja_JP", "calendar", "japanese", "ja"}, - { "no_NO_NY", "nn_NO", null, null, "nn"}, - { "th_TH_TH", "th_TH", "numbers", "thai", "th"}, - }; - /** * Private constructor used by static initializers. */ @@ -405,22 +394,9 @@ public final class ULocale implements Serializable { ULocale result = CACHE.get(loc); if (result == null) { if (defaultULocale != null && loc == defaultULocale.locale) { - result = defaultULocale; - } else { - String locStr = loc.toString(); - if (locStr.length() == 0) { - result = ROOT; - } else { - for (int i = 0; i < _javaLocaleMap.length; i++) { - if (_javaLocaleMap[i][0].equals(locStr)) { - LocaleIDParser p = new LocaleIDParser(_javaLocaleMap[i][1]); - p.setKeywordValue(_javaLocaleMap[i][2], _javaLocaleMap[i][3]); - locStr = p.getName(); - break; - } - } - result = new ULocale(locStr, loc); - } + result = defaultULocale; + } else { + result = JDKLocaleMapper.INSTANCE.toULocale(loc); } CACHE.put(loc, result); } @@ -527,24 +503,7 @@ public final class ULocale implements Serializable { */ public Locale toLocale() { if (locale == null) { - LocaleIDParser p = new LocaleIDParser(localeID); - String base = p.getBaseName(); - for (int i = 0; i < _javaLocaleMap.length; i++) { - if (base.equals(_javaLocaleMap[i][1]) || base.equals(_javaLocaleMap[i][4])) { - if (_javaLocaleMap[i][2] != null) { - String val = p.getKeywordValue(_javaLocaleMap[i][2]); - if (val != null && val.equals(_javaLocaleMap[i][3])) { - p = new LocaleIDParser(_javaLocaleMap[i][0]); - break; - } - } else { - p = new LocaleIDParser(_javaLocaleMap[i][0]); - break; - } - } - } - String[] names = p.getLanguageScriptCountryVariant(); - locale = new Locale(names[0], names[2], names[3]); + locale = JDKLocaleMapper.INSTANCE.toLocale(this); } return locale; } @@ -3545,4 +3504,283 @@ public final class ULocale implements Serializable { } return type; } + + /* + * JDK Locale Mapper + */ + private static final class JDKLocaleMapper { + public static final JDKLocaleMapper INSTANCE = new JDKLocaleMapper(); + + private static boolean isJava7orNewer = 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; + + /* + * This table is used for mapping between ICU and special Java + * 6 locales. When an ICU locale matches with + * /, the ICU locale is mapped to 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 = { + // { , , , , + { "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 { + 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); + isJava7orNewer = true; + } catch (NoSuchMethodException e) { + // Java 6 or older + } + } + + private JDKLocaleMapper() { + } + + public ULocale toULocale(Locale loc) { + return isJava7orNewer ? toULocale7(loc) : toULocale6(loc); + } + + public Locale toLocale(ULocale uloc) { + return isJava7orNewer ? toLocale7(uloc) : toLocale6(uloc); + } + + private ULocale toULocale7(Locale loc) { + String language = loc.getLanguage(); + String script = ""; + String country = loc.getCountry(); + String variant = loc.getVariant(); + + Set attributes = null; + Map keywords = null; + + try { + script = (String) mGetScript.invoke(loc, (Object[]) null); + @SuppressWarnings("unchecked") + Set extKeys = (Set) mGetExtensionKeys.invoke(loc, (Object[]) null); + if (!extKeys.isEmpty()) { + for (Character extKey : extKeys) { + if (extKey.charValue() == 'u') { + // Found Unicode locale extension + + // attributes + @SuppressWarnings("unchecked") + Set uAttributes = (Set) mGetUnicodeLocaleAttributes.invoke(loc, (Object[]) null); + if (!uAttributes.isEmpty()) { + attributes = new TreeSet(); + for (String attr : uAttributes) { + attributes.add(attr); + } + } + + // keywords + @SuppressWarnings("unchecked") + Set uKeys = (Set) 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(); + } + keywords.put(kwKey, kwVal); + } + } + } + } else { + String extVal = (String) mGetExtension.invoke(loc, 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, + // and it should be transformed to nn_NO. + + // Note: JDK7+ unerstand both no_NO_NY and nn_NO. When convert + // ICU locale to JDK, we do not need to map nn_NO back to no_NO_NY. + + if (language.equals("no") && country.equals("NO") && variant.equals("NY")) { + language = "nn"; + variant = ""; + } + + // Constructing ID + StringBuilder buf = new StringBuilder(language); + + if (script.length() > 0) { + buf.append('_'); + buf.append(script); + } + + if (country.length() > 0) { + buf.append('_'); + buf.append(country); + } + + if (variant.length() > 0) { + if (country.length() == 0) { + buf.append('_'); + } + buf.append('_'); + buf.append(variant); + } + + if (attributes != null) { + // transform Unicode attributes into a keyword + StringBuilder attrBuf = new StringBuilder(); + for (String attr : attributes) { + if (attrBuf.length() != 0) { + attrBuf.append('-'); + } + attrBuf.append(attr); + } + if (keywords == null) { + keywords = new TreeMap(); + } + keywords.put(LOCALE_ATTRIBUTE_KEY, attrBuf.toString()); + } + + if (keywords != null) { + buf.append('@'); + boolean addSep = false; + for (Entry kwEntry : keywords.entrySet()) { + String kwKey = kwEntry.getKey(); + String kwVal = kwEntry.getValue(); + + 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)); + } + + if (addSep) { + buf.append(';'); + } else { + addSep = true; + } + buf.append(kwKey); + buf.append('='); + buf.append(kwVal); + } + } + + return new ULocale(buf.toString()); + } + + private 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(locStr, loc); + } + return uloc; + } + + private Locale toLocale7(ULocale uloc) { + Locale loc = null; + String ulocStr = uloc.getName(); + if (uloc.getScript().length() > 0 || ulocStr.contains("@")) { + // With script or keywords available, the best way + // to get a mapped Locale is to go through a language tag. + // A Locale with script or keywords can only have variants + // that is 1 to 8 alphanum. If this ULocale has a variant + // subtag not satisfying the criteria, the variant subtag + // will be lost. + String tag = uloc.toLanguageTag(); + + // Workaround for variant casing problem: + // + // The variant field in ICU is case insensitive and normalized + // to upper case letters by getVariant(), while + // the variant field in JDK Locale is case sensitive. + // ULocale#toLanguageTag use lower case characters for + // BCP 47 variant and private use x-lvariant. + // + // Locale#forLanguageTag in JDK preserves character casing + // 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); + } + } + if (loc == null) { + // Without script or keywords, use a Locale constructor, + // so we can preserve any ill-formed variants. + loc = new Locale(uloc.getLanguage(), uloc.getCountry(), uloc.getVariant()); + } + return loc; + } + + private 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]); + } + } } diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/IntlTestDateFormatAPI.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/IntlTestDateFormatAPI.java index c25a17f6496..23ef7430ca7 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/IntlTestDateFormatAPI.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/IntlTestDateFormatAPI.java @@ -26,6 +26,7 @@ import com.ibm.icu.text.DateFormat; import com.ibm.icu.text.NumberFormat; import com.ibm.icu.util.Calendar; import com.ibm.icu.util.TimeZone; +import com.ibm.icu.util.VersionInfo; public class IntlTestDateFormatAPI extends com.ibm.icu.dev.test.TestFmwk { @@ -152,6 +153,7 @@ public class IntlTestDateFormatAPI extends com.ibm.icu.dev.test.TestFmwk // Ticket#6280 // These locales should be included in the result + boolean java7orLater = (VersionInfo.javaVersion().compareTo(VersionInfo.getInstance(1, 7)) >= 0); final Locale[] samples = { new Locale("zh", "CN"), new Locale("zh", "TW"), @@ -172,7 +174,13 @@ public class IntlTestDateFormatAPI extends com.ibm.icu.dev.test.TestFmwk } for (int i = 0; i < available.length; i++) { if (!available[i]) { - errln("ERROR: missing Locale: " + samples[i]); + if (java7orLater) { + // Java 7 supports script field, so zh_Hans_CN is included + // in the available locale list. + logln("INFO: missing Locale: " + samples[i]); + } else { + errln("ERROR: missing Locale: " + samples[i]); + } } } diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/ULocaleTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/ULocaleTest.java index 88d18d52772..044ef46d67c 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/ULocaleTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/util/ULocaleTest.java @@ -38,6 +38,8 @@ import com.ibm.icu.util.VersionInfo; public class ULocaleTest extends TestFmwk { + private static final boolean JAVA7_OR_LATER = (VersionInfo.javaVersion().compareTo(VersionInfo.getInstance(1, 7)) >= 0); + public static void main(String[] args) throws Exception { new ULocaleTest().run(args); } @@ -191,7 +193,7 @@ public class ULocaleTest extends TestFmwk { */ public void TestJavaLocaleCompatibility() { Locale backupDefault = Locale.getDefault(); - + // Java Locale for ja_JP with Japanese calendar Locale jaJPJP = new Locale("ja", "JP", "JP"); Locale jaJP = new Locale("ja", "JP"); @@ -213,8 +215,14 @@ public class ULocaleTest extends TestFmwk { // Default locale Locale.setDefault(jaJPJP); ULocale defUloc = ULocale.getDefault(); - if (!defUloc.toString().equals("ja_JP@calendar=japanese")) { - errln("FAIL: Invalid default ULocale: " + defUloc + " /expected: ja_JP@calendar=japanese"); + if (JAVA7_OR_LATER) { + if (!defUloc.toString().equals("ja_JP_JP@calendar=japanese")) { + errln("FAIL: Invalid default ULocale: " + defUloc + " /expected: ja_JP_JP@calendar=japanese"); + } + } else { + if (!defUloc.toString().equals("ja_JP@calendar=japanese")) { + errln("FAIL: Invalid default ULocale: " + defUloc + " /expected: ja_JP@calendar=japanese"); + } } // Check calendar type cal = Calendar.getInstance(); @@ -227,7 +235,7 @@ public class ULocaleTest extends TestFmwk { // Set default via ULocale ULocale ujaJP_calJP = new ULocale("ja_JP@calendar=japanese"); ULocale.setDefault(ujaJP_calJP); - if (!Locale.getDefault().equals(jaJPJP)) { + if (!JAVA7_OR_LATER && !Locale.getDefault().equals(jaJPJP)) { errln("FAIL: ULocale#setDefault failed to set Java Locale ja_JP_JP /actual: " + Locale.getDefault()); } // Ticket#6672 - missing keywords @@ -246,7 +254,7 @@ public class ULocaleTest extends TestFmwk { // We also want to map ICU locale ja@calendar=japanese to Java ja_JP_JP ULocale.setDefault(new ULocale("ja@calendar=japanese")); - if (!Locale.getDefault().equals(jaJPJP)) { + if (!JAVA7_OR_LATER && !Locale.getDefault().equals(jaJPJP)) { errln("FAIL: ULocale#setDefault failed to set Java Locale ja_JP_JP /actual: " + Locale.getDefault()); } Locale.setDefault(backupDefault); @@ -255,28 +263,28 @@ public class ULocaleTest extends TestFmwk { Locale noNONY = new Locale("no", "NO", "NY"); Locale.setDefault(noNONY); defUloc = ULocale.getDefault(); - if (defUloc.toString().equals("nn_NY")) { - errln("FAIL: Invalid default ULocale: " + defUloc + " /expected: nn_NY"); + if (!defUloc.toString().equals("nn_NO")) { + errln("FAIL: Invalid default ULocale: " + defUloc + " /expected: nn_NO"); } Locale.setDefault(backupDefault); // Java th_TH_TH -> ICU th_TH@numbers=thai ULocale.setDefault(new ULocale("th@numbers=thai")); - if (!Locale.getDefault().equals(thTHTH)) { + if (!JAVA7_OR_LATER && !Locale.getDefault().equals(thTHTH)) { errln("FAIL: ULocale#setDefault failed to set Java Locale th_TH_TH /actual: " + Locale.getDefault()); } Locale.setDefault(backupDefault); // Set default via ULocale ULocale.setDefault(new ULocale("nn_NO")); - if (!Locale.getDefault().equals(noNONY)) { + if (!JAVA7_OR_LATER && !Locale.getDefault().equals(noNONY)) { errln("FAIL: ULocale#setDefault failed to set Java Locale no_NO_NY /actual: " + Locale.getDefault()); } Locale.setDefault(backupDefault); // We also want to map ICU locale nn to Java no_NO_NY ULocale.setDefault(new ULocale("nn")); - if (!Locale.getDefault().equals(noNONY)) { + if (!JAVA7_OR_LATER && !Locale.getDefault().equals(noNONY)) { errln("FAIL: ULocale#setDefault failed to set Java Locale no_NO_NY /actual: " + Locale.getDefault()); } Locale.setDefault(backupDefault); @@ -4021,4 +4029,125 @@ public class ULocaleTest extends TestFmwk { errln("getUnicodeLocaleType must throw an exception on illegal input key"); } } + + public void TestForLocale() { + Object[][] DATA = { + {new Locale(""), ""}, + {new Locale("en", "US"), "en_US"}, + {new Locale("en", "US", "POSIX"), "en_US_POSIX"}, + {new Locale("", "US"), "_US"}, + {new Locale("en", "", "POSIX"), "en__POSIX"}, + {new Locale("no", "NO", "NY"), "nn_NO"}, + }; + + for (int i = 0; i < DATA.length; i++) { + ULocale uloc = ULocale.forLocale((Locale) DATA[i][0]); + assertEquals("forLocale with " + DATA[i][0], DATA[i][1], uloc.getName()); + } + + if (JAVA7_OR_LATER) { + Object[][] DATA7 = { + {new Locale("ja", "JP", "JP"), "ja_JP_JP@calendar=japanese"}, + {new Locale("th", "TH", "TH"), "th_TH_TH@numbers=thai"}, + }; + for (int i = 0; i < DATA7.length; i++) { + ULocale uloc = ULocale.forLocale((Locale) DATA7[i][0]); + assertEquals("forLocale with " + DATA7[i][0], DATA7[i][1], uloc.getName()); + } + + try { + Method localeForLanguageTag = Locale.class.getMethod("forLanguageTag", String.class); + + String[][] DATA7EXT = { + {"en-Latn-US", "en_Latn_US"}, + {"zh-Hant-TW", "zh_Hant_TW"}, + {"und-US-u-cu-usd", "_US@currency=usd"}, + {"th-TH-u-ca-buddhist-nu-thai", "th_TH@calendar=buddhist;numbers=thai"}, + {"en-US-u-va-POSIX", "en_US_POSIX"}, + {"de-DE-u-co-phonebk", "de_DE@collation=phonebook"}, + {"en-a-exta-b-extb-x-privu", "en@a=exta;b=extb;x=privu"}, + {"fr-u-attr1-attr2-cu-eur", "fr@attribute=attr1-attr2;currency=eur"}, + }; + + for (int i = 0; i < DATA7EXT.length; i++) { + Locale loc = (Locale) localeForLanguageTag.invoke(null, DATA7EXT[i][0]); + ULocale uloc = ULocale.forLocale(loc); + assertEquals("forLocale with " + loc, DATA7EXT[i][1], uloc.getName()); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + } else { + Object[][] DATA6 = { + {new Locale("ja", "JP", "JP"), "ja_JP@calendar=japanese"}, + {new Locale("th", "TH", "TH"), "th_TH@numbers=thai"}, + }; + for (int i = 0; i < DATA6.length; i++) { + ULocale uloc = ULocale.forLocale((Locale) DATA6[i][0]); + assertEquals("forLocale with " + DATA6[i][0], DATA6[i][1], uloc.getName()); + } + } + } + + public void TestToLocale() { + Object[][] DATA = { + {"", new Locale("")}, + {"en_US", new Locale("en", "US")}, + {"_US", new Locale("", "US")}, + {"en__POSIX", new Locale("en", "", "POSIX")}, + }; + + for (int i = 0; i < DATA.length; i++) { + Locale loc = new ULocale((String) DATA[i][0]).toLocale(); + assertEquals("toLocale with " + DATA[i][0], DATA[i][1], loc); + } + + if (JAVA7_OR_LATER) { + Object[][] DATA7 = { + {"nn_NO", new Locale("nn", "NO")}, + {"no_NO_NY", new Locale("no", "NO", "NY")}, + }; + for (int i = 0; i < DATA7.length; i++) { + Locale loc = new ULocale((String) DATA7[i][0]).toLocale(); + assertEquals("toLocale with " + DATA7[i][0], DATA7[i][1], loc); + } + + try { + Method localeForLanguageTag = Locale.class.getMethod("forLanguageTag", String.class); + + String[][] DATA7EXT = { + {"en_Latn_US", "en-Latn-US"}, + {"zh_Hant_TW", "zh-Hant-TW"}, + {"ja_JP@calendar=japanese", "ja-JP-u-ca-japanese"}, + {"ja_JP_JP@calendar=japanese", "ja-JP-u-ca-japanese-x-lvariant-JP"}, + {"th_TH@numbers=thai", "th-TH-u-nu-thai"}, + {"th_TH_TH@numbers=thai", "th-TH-u-nu-thai-x-lvariant-TH"}, + {"de@collation=phonebook", "de-u-co-phonebk"}, + {"en@a=exta;b=extb;x=privu", "en-a-exta-b-extb-x-privu"}, + {"fr@attribute=attr1-attr2;currency=eur", "fr-u-attr1-attr2-cu-eur"}, + }; + + for (int i = 0; i < DATA7EXT.length; i++) { + Locale loc = new ULocale((String) DATA7EXT[i][0]).toLocale(); + Locale expected = (Locale) localeForLanguageTag.invoke(null, DATA7EXT[i][1]); + assertEquals("toLocale with " + DATA7EXT[i][0], expected, loc); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + + } else { + Object[][] DATA6 = { + {"nn_NO", new Locale("no", "NO", "NY")}, + {"no_NO_NY", new Locale("no", "NO", "NY")}, + {"ja_JP@calendar=japanese", new Locale("ja", "JP", "JP")}, + {"th_TH@numbers=thai", new Locale("th", "TH", "TH")}, + }; + for (int i = 0; i < DATA6.length; i++) { + Locale loc = new ULocale((String) DATA6[i][0]).toLocale(); + assertEquals("toLocale with " + DATA6[i][0], DATA6[i][1], loc); + } + } + } }