From 4bc0941d148100da1021f21b5348cfeddd27815f Mon Sep 17 00:00:00 2001 From: Doug Felt Date: Sat, 3 Jun 2006 00:51:08 +0000 Subject: [PATCH] ICU-4743 yoshito's fixes to GP - more changes, improved test X-SVN-Rev: 19681 --- .../format/GlobalizationPreferencesTest.java | 1639 +++++++++++++++-- .../icu/util/GlobalizationPreferences.java | 851 +++++---- 2 files changed, 1981 insertions(+), 509 deletions(-) diff --git a/icu4j/src/com/ibm/icu/dev/test/format/GlobalizationPreferencesTest.java b/icu4j/src/com/ibm/icu/dev/test/format/GlobalizationPreferencesTest.java index 9dddbf6788d..7f060fba53d 100644 --- a/icu4j/src/com/ibm/icu/dev/test/format/GlobalizationPreferencesTest.java +++ b/icu4j/src/com/ibm/icu/dev/test/format/GlobalizationPreferencesTest.java @@ -8,157 +8,1522 @@ package com.ibm.icu.dev.test.format; -import java.io.IOException; -import java.io.PrintStream; -import java.io.PrintWriter; -import java.util.Arrays; -import java.util.Date; +import java.util.ArrayList; +import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import com.ibm.icu.dev.test.TestFmwk; +import com.ibm.icu.text.BreakIterator; +import com.ibm.icu.text.Collator; import com.ibm.icu.text.DateFormat; -import com.ibm.icu.text.DateFormatSymbols; +import com.ibm.icu.text.NumberFormat; import com.ibm.icu.text.SimpleDateFormat; +import com.ibm.icu.util.BuddhistCalendar; +import com.ibm.icu.util.Calendar; import com.ibm.icu.util.Currency; import com.ibm.icu.util.GlobalizationPreferences; +import com.ibm.icu.util.IslamicCalendar; +import com.ibm.icu.util.JapaneseCalendar; +import com.ibm.icu.util.TimeZone; import com.ibm.icu.util.ULocale; -public class GlobalizationPreferencesTest { - /** - * Just for testing right now. Will remove later. - private static final String[] TYPENAMES = { - "locale", "language", "script", "territory", "variant", - "keyword", "keyword=value", - "currency", "currency-symbol", "timezone" - }; - private static final String[] ContextNames = {"format", "standalone"}; - private static final String[] WidthNames = {"abbreviated", "wide", "narrow"}; - - public static void main(String[] args) throws IOException { - PrintStream out = System.out; - //PrintWriter out = BagFormatter.openUTF8Writer("c:/", "tempFile.txt"); - try { - Date now = new Date(); - - GlobalizationPreferences lPreferences = new GlobalizationPreferences(); +public class GlobalizationPreferencesTest extends TestFmwk { - out.println("Samples from Globalization Preferences prototype"); - out.println("\tWarning: some of this is just mockup -- real data will be accessed later."); - out.println(); + public static void main(String[] args) throws Exception { + new GlobalizationPreferencesTest().run(args); + } - //#ifndef FOUNDATION - out.println("Check defaulting"); - String[] localeList = {"fr_BE;q=0.5,de", "fr_BE,de", "fr", "en_NZ", "en", "en-TH", "zh-Hant", "zh-MO", "zh", "it", "as", "haw", "ar-EG", "ar", "qqq"}; - for (int i = 0; i < localeList.length; ++i) { - lPreferences.setLocales(localeList[i]); - out.println("\tdefaults for: \t" + localeList[i] + "\t" - + lPreferences.getLocales() - + ", \t" + lPreferences.getTerritory() - + ", \t" + lPreferences.getCurrency() - + ", \t" + lPreferences.getCalendar().getClass() - + ", \t" + lPreferences.getTimeZone().getID() - ); - } - - out.println(); - //#endif + public void TestDefault() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + ULocale defLocale = new ULocale("en_US"); + ULocale defFallbackLocale = new ULocale("en"); - out.println("Date Formatting"); - out.println("\tdate: \t" + lPreferences.getDateFormat(DateFormat.FULL, GlobalizationPreferences.NONE).format(now)); - - out.println("setting locale to Germany"); - lPreferences.setLocale(ULocale.GERMANY); - out.println("\tdate: \t" + lPreferences.getDateFormat(DateFormat.FULL, GlobalizationPreferences.NONE).format(now)); - - out.println("setting date locale to France"); - lPreferences.setDateLocale(ULocale.FRANCE); - out.println("\tdate: \t" + lPreferences.getDateFormat(DateFormat.FULL, GlobalizationPreferences.NONE).format(now)); - - out.println("setting explicit pattern"); - lPreferences.setDateFormat(DateFormat.FULL, GlobalizationPreferences.NONE, "GGG yyyy+MMM+DD vvvv"); - out.println("\tdate: \t" + lPreferences.getDateFormat(DateFormat.FULL, GlobalizationPreferences.NONE).format(now)); - - out.println("setting date format to yyyy-MMM-dd (Italy)"); - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MMM-dd",ULocale.ITALY); - lPreferences.setDateFormat(DateFormat.FULL, GlobalizationPreferences.NONE, sdf); - out.println("\tdate: \t" + lPreferences.getDateFormat(DateFormat.FULL, GlobalizationPreferences.NONE).format(now)); - - out.println(); - out.println("Various named date fields"); - SimpleDateFormat df = (SimpleDateFormat)lPreferences.getDateFormat(DateFormat.FULL, GlobalizationPreferences.NONE); - DateFormatSymbols dfs = df.getDateFormatSymbols(); - - for (int context = dfs.FORMAT; context <= dfs.STANDALONE; ++context) { - out.println("context: " + ContextNames[context-dfs.FORMAT]); - for (int width = dfs.ABBREVIATED; width <= dfs.NARROW; ++width) { - out.println("\twidth: " + WidthNames[width-dfs.ABBREVIATED]); - out.println("\t\tgetAmPmStrings:\t" + Arrays.asList(dfs.getAmPmStrings())); - out.println("\t\tgetEras\t" + Arrays.asList((width > 0 ? dfs.getEraNames() : dfs.getEras()))); - out.println("\t\tgetMonths:\t" + Arrays.asList(dfs.getMonths(context, width))); - out.println("\t\tgetWeekdays:\t" + Arrays.asList(dfs.getWeekdays(context, width))); - } - } - - // now show currencies - out.println(); - out.println("Currency Formatting"); - out.println("\tcurrency: \t" + lPreferences.getNumberFormat(GlobalizationPreferences.CURRENCY).format(1234.567)); - - out.println("setting number locale to Canada"); - lPreferences.setNumberLocale(ULocale.CANADA); - out.println("\tcurrency: \t" + lPreferences.getNumberFormat(GlobalizationPreferences.CURRENCY).format(1234.567)); - - out.println("setting currency to INR"); - lPreferences.setCurrency(Currency.getInstance("INR")); - out.println("\tcurrency: \t" + lPreferences.getNumberFormat(GlobalizationPreferences.CURRENCY).format(1234.567)); - - out.println("setting number locale to Hindi-India"); - lPreferences.setNumberLocale(new ULocale("hi-IN")); - out.println("\tcurrency: \t" + lPreferences.getNumberFormat(GlobalizationPreferences.CURRENCY).format(1234.567)); - - out.println(); - out.println("Comparison"); - out.println("setting number locale to Germany"); - lPreferences.setLocale(ULocale.GERMANY); - out.println("\tcompare: \u00e4 & z \t" + lPreferences.getCollator().compare("\u00e4", "z")); + if (!defLocale.equals(ULocale.getDefault())) { + // Locale.US is always used as the default locale in the test environment + // If not, some test cases will fail... + errln("FAIL: The default locale of the test environment must be en_US"); + } + + logln("Default locale: " + defLocale.toString()); - out.println("setting number locale to Swedish"); - lPreferences.setLocale(new ULocale("sv")); - out.println("\tcompare: \u00e4 & z \t" + lPreferences.getCollator().compare("\u00e4", "z")); + // First locale is en_US + ULocale gpLocale0 = gp.getLocale(0); + logln("Primary locale: " + gpLocale0.toString()); + if (!gpLocale0.equals(defLocale)) { + errln("FAIL: The primary locale is not en_US"); + } - // now try a fallback within locales - out.println(); - out.println("Display Names"); - lPreferences.setLocales(new ULocale[]{new ULocale("as"),new ULocale("pl"),new ULocale("fr")}); - out.println("Trying fallback for multiple locales: " + lPreferences.getLocales()); - String[][] testItems = { - {GlobalizationPreferences.LOCALEID+"", "as_FR", "en_RU","haw_CA","se_Cyrl_AT"}, - {GlobalizationPreferences.LANGUAGEID+"", "as", "en","haw","se","kok"}, - {GlobalizationPreferences.SCRIPTID+"", "Arab", "Cyrl", "Hant"}, - {GlobalizationPreferences.TERRITORYID+"", "US", "FR", "AU", "RU","IN"}, - {GlobalizationPreferences.VARIANTID+"","REVISED"}, - {GlobalizationPreferences.KEYWORDID+"","calendar", "collation", "currency"}, - {GlobalizationPreferences.KEYWORD_VALUEID+"", "calendar=buddhist", "calendar=gregorian", - "collation=phonebook", "collation=traditional"}, - {GlobalizationPreferences.CURRENCYID+"", "USD", "GBP", "EUR", "JPY","INR"}, - {GlobalizationPreferences.CURRENCY_SYMBOLID+"", "USD", "GBP", "EUR", "JPY","INR"}, - {GlobalizationPreferences.TIMEZONEID+"", "America/Mexico_City", "Asia/Shanghai", "Europe/London", "Europe/Berlin"}, - }; - for (int i = 0; i < testItems.length; ++i) { - int type = Integer.parseInt(testItems[i][0]); - String typeName = TYPENAMES[type]; - for (int j = 1; j < testItems[i].length; ++j) { - String item = testItems[i][j]; - out.println(typeName + " for " + item + ": \t" - + lPreferences.getDisplayName(item, type)); - } - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - out.close(); - System.out.println("done"); + // Second locale is en + ULocale gpLocale1 = gp.getLocale(1); + logln("Secondary locale: " + gpLocale1.toString()); + if (!gpLocale1.equals(defFallbackLocale)) { + errln("FAIL: The secondary locale is not en"); + } + + // Third locale is null + ULocale gpLocale2 = gp.getLocale(2); + if (gpLocale2 != null) { + errln("FAIL: Number of locales must be 2"); + } + + // Calendar locale + Calendar cal = gp.getCalendar(); + ULocale calLocale = cal.getLocale(ULocale.VALID_LOCALE); + logln("Calendar locale: " + calLocale.toString()); + if (!calLocale.equals(defLocale)) { + errln("FAIL: The calendar locale must match with the default JVM locale"); + } + + // Collator locale + Collator coll = gp.getCollator(); + ULocale collLocale = coll.getLocale(ULocale.VALID_LOCALE); + logln("Collator locale: " + collLocale.toString()); + if (!collLocale.equals(defLocale)) { + errln("FAIL: The collator locale must match with the default JVM locale"); + } + + // BreakIterator locale + BreakIterator brk = gp.getBreakIterator(GlobalizationPreferences.BI_CHARACTER); + ULocale brkLocale = brk.getLocale(ULocale.VALID_LOCALE); + logln("BreakIterator locale: " + brkLocale.toString()); + if (!brkLocale.equals(defLocale)) { + errln("FAIL: The break iterator locale must match with the default JVM locale"); + } + + /* Skip - Bug#5209 + // DateFormat locale + DateFormat df = gp.getDateFormat(GlobalizationPreferences.DF_FULL, GlobalizationPreferences.DF_NONE); + ULocale dfLocale = df.getLocale(ULocale.VALID_LOCALE); + logln("DateFormat locale: " + dfLocale.toString()); + if (!dfLocale.equals(defLocale)) { + errln("FAIL: The date format locale must match with the default JVM locale"); + } + */ + + // NumberFormat locale + NumberFormat nf = gp.getNumberFormat(GlobalizationPreferences.NF_NUMBER); + ULocale nfLocale = nf.getLocale(ULocale.VALID_LOCALE); + logln("NumberFormat locale: " + nfLocale.toString()); + if (!nfLocale.equals(defLocale)) { + errln("FAIL: The number format locale must match with the default JVM locale"); + } + } + + public void TestFreezable() { + logln("Create a new GlobalizationPreference object"); + GlobalizationPreferences gp = new GlobalizationPreferences(); + if (gp.isFrozen()) { + errln("FAIL: This object is not yet frozen"); + } + + logln("Call reset()"); + boolean bSet = true; + try { + gp.reset(); + } catch (UnsupportedOperationException uoe) { + bSet = false; + } + if (!bSet) { + errln("FAIL: reset() must not throw an exception before frozen"); + } + + // Freeze the object + logln("Freeze the object"); + gp.freeze(); + if (!gp.isFrozen()) { + errln("FAIL: This object is already fronzen"); + } + + // reset() + logln("Call reset() after frozen"); + bSet = true; + try { + gp.reset(); + } catch (UnsupportedOperationException uoe) { + bSet = false; + } + if (bSet) { + errln("FAIL: reset() must be blocked after frozen"); + } + + // setLocales(ULocale[]) + logln("Call setLocales(ULocale[]) after frozen"); + bSet = true; + try { + gp.setLocales(new ULocale[] {new ULocale("fr_FR")}); + } catch (UnsupportedOperationException uoe) { + bSet = false; + } + if (bSet) { + errln("FAIL: setLocales(ULocale[]) must be blocked after frozen"); + } + + // setLocales(ULocale[]) + logln("Call setLocales(List) after frozen"); + bSet = true; + ArrayList list = new ArrayList(1); + list.add(new ULocale("fr_FR")); + try { + gp.setLocales(list); + } catch (UnsupportedOperationException uoe) { + bSet = false; + } + if (bSet) { + errln("FAIL: setLocales(List) must be blocked after frozen"); + } + + // setLocales(String) + logln("Call setLocales(String) after frozen"); + bSet = true; + try { + gp.setLocales("pt-BR,es;q=0.7"); + } catch (UnsupportedOperationException uoe) { + bSet = false; + } + if (bSet) { + errln("FAIL: setLocales(String) must be blocked after frozen"); + } + + // setLocale(ULocale) + logln("Call setLocale(ULocale) after frozen"); + bSet = true; + try { + gp.setLocale(new ULocale("fi_FI")); + } catch (UnsupportedOperationException uoe) { + bSet = false; + } + if (bSet) { + errln("FAIL: setLocale(ULocale) must be blocked after frozen"); + } + + // setTerritory(String) + logln("Call setTerritory(String) after frozen"); + bSet = true; + try { + gp.setTerritory("AU"); + } catch (UnsupportedOperationException uoe) { + bSet = false; + } + if (bSet) { + errln("FAIL: setTerritory(String) must be blocked after frozen"); + } + + // Modifiable clone + logln("Create a modifiable clone"); + GlobalizationPreferences gp1 = (GlobalizationPreferences)gp.cloneAsThawed(); + + if (gp1.isFrozen()) { + errln("FAIL: The object returned by cloneAsThawed() must not be frozen yet"); + } + + // setLocale(ULocale) + logln("Call setLocale(ULocale) of the modifiable clone"); + bSet = true; + try { + gp1.setLocale(new ULocale("fr_FR")); + } catch (UnsupportedOperationException uoe) { + bSet = false; + } + if (!bSet) { + errln("FAIL: setLocales(ULocale) must not throw an exception before frozen"); + } + } + + static String[][] INPUT_LOCALEIDS = { + {"en_US"}, + {"fr_CA", "fr"}, + {"fr", "fr_CA"}, + {"es", "fr", "en_US"}, + {"zh_CN", "zh_Hans", "zh_Hans_CN"} + }; + + static String[] ACCEPT_LANGUAGES = { + "en-US", + "fr-CA,fr;q=0.5", + "fr_CA;q=0.5,fr", + "es,fr;q=0.76,en_US;q=0.75", + "zh-CN,zh-Hans;q=0.5,zh-Hans-CN;q=0.1" + }; + + static String[][] RESULTS_LOCALEIDS = { + {"en_US", "en"}, + {"fr_CA", "fr"}, + {"fr_CA", "fr"}, + {"es", "fr", "en_US", "en"}, + {"zh_Hans_CN", "zh_CN", "zh_Hans", "zh"} + }; + + public void TestSetLocales() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + + // setLocales(List) + for (int i = 0; i < INPUT_LOCALEIDS.length; i++) { + String[] localeStrings = INPUT_LOCALEIDS[i]; + ArrayList locales = new ArrayList(); + StringBuffer sb = new StringBuffer(); + for (int j = 0; j < localeStrings.length; j++) { + locales.add(new ULocale(localeStrings[j])); + if (j != 0) { + sb.append(", "); + } + sb.append(localeStrings[j]); + } + logln("Input locales: " + sb.toString()); + + gp.reset(); + gp.setLocales(locales); + + List resultLocales = gp.getLocales(); + if (resultLocales.size() != RESULTS_LOCALEIDS[i].length) { + errln("FAIL: Number of locales mismatch - GP:" + resultLocales.size() + + " Expected:" + RESULTS_LOCALEIDS[i].length); + } else { + + for (int j = 0; j < RESULTS_LOCALEIDS[i].length; j++) { + ULocale loc = gp.getLocale(j); + logln("Locale[" + j + "]: " + loc.toString()); + if (!gp.getLocale(j).toString().equals(RESULTS_LOCALEIDS[i][j])) { + errln("FAIL: Locale index(" + j + ") does not match - GP:" + loc.toString() + + " Expected:" + RESULTS_LOCALEIDS[i][j]); + } + } + } + } + + // setLocales(ULocale[]) + for (int i = 0; i < INPUT_LOCALEIDS.length; i++) { + String[] localeStrings = INPUT_LOCALEIDS[i]; + ULocale[] localeArray = new ULocale[INPUT_LOCALEIDS[i].length]; + StringBuffer sb = new StringBuffer(); + for (int j = 0; j < localeStrings.length; j++) { + localeArray[j] = new ULocale(localeStrings[j]); + if (j != 0) { + sb.append(", "); + } + sb.append(localeStrings[j]); + } + logln("Input locales: " + sb.toString()); + + gp.reset(); + gp.setLocales(localeArray); + + List resultLocales = gp.getLocales(); + if (resultLocales.size() != RESULTS_LOCALEIDS[i].length) { + errln("FAIL: Number of locales mismatch - GP:" + resultLocales.size() + + " Expected:" + RESULTS_LOCALEIDS[i].length); + } else { + + for (int j = 0; j < RESULTS_LOCALEIDS[i].length; j++) { + ULocale loc = gp.getLocale(j); + logln("Locale[" + j + "]: " + loc.toString()); + if (!gp.getLocale(j).toString().equals(RESULTS_LOCALEIDS[i][j])) { + errln("FAIL: Locale index(" + j + ") does not match - GP:" + loc.toString() + + " Expected:" + RESULTS_LOCALEIDS[i][j]); + } + } + } + } + + // setLocales(String) + for (int i = 0; i < ACCEPT_LANGUAGES.length; i++) { + String acceptLanguage = ACCEPT_LANGUAGES[i]; + logln("Accept language: " + acceptLanguage); + + gp.reset(); + gp.setLocales(acceptLanguage); + + List resultLocales = gp.getLocales(); + if (resultLocales.size() != RESULTS_LOCALEIDS[i].length) { + errln("FAIL: Number of locales mismatch - GP:" + resultLocales.size() + + " Expected:" + RESULTS_LOCALEIDS[i].length); + } else { + + for (int j = 0; j < RESULTS_LOCALEIDS[i].length; j++) { + ULocale loc = gp.getLocale(j); + logln("Locale[" + j + "]: " + loc.toString()); + if (!gp.getLocale(j).toString().equals(RESULTS_LOCALEIDS[i][j])) { + errln("FAIL: Locale index(" + j + ") does not match - GP:" + loc.toString() + + " Expected:" + RESULTS_LOCALEIDS[i][j]); + } + } + } + } + + + // accept-language without q-value + logln("Set accept-language - de,de-AT"); + gp.setLocales("de,de-AT"); + if (!gp.getLocale(0).toString().equals("de_AT")) { + errln("FAIL: getLocale(0) returns " + gp.getLocale(0).toString() + " Expected: de_AT"); + } + + // Invalid accept-language + logln("Set locale - ko_KR"); + gp.setLocale(new ULocale("ko_KR")); + boolean bException = false; + try { + logln("Set invlaid accept-language - ko=100"); + gp.setLocales("ko=100"); + } catch (IllegalArgumentException iae) { + logln("IllegalArgumentException was thrown"); + bException = true; + } + if (!bException) { + errln("FAIL: IllegalArgumentException was not thrown for illegal accept-language - ko=100"); + } + if (!gp.getLocale(0).toString().equals("ko_KR")) { + errln("FAIL: Previous valid locale list had gone"); + } + } + + public void TestResourceBundle() { + String baseName = "com.ibm.icu.dev.data.resources.TestDataElements"; + ResourceBundle rb; + + logln("Get a resource bundle " + baseName + + " using GlobalizationPreferences initialized by locales - en_GB, en_US"); + GlobalizationPreferences gp = new GlobalizationPreferences(); + ULocale[] locales = new ULocale[2]; + locales[0] = new ULocale("en_GB"); + locales[1] = new ULocale("en_US"); + gp.setLocales(locales); + + try { + rb = gp.getResourceBundle(baseName); + String str = rb.getString("from_en_US"); + if (!str.equals("This data comes from en_US")) { + errln("FAIL: from_en_US is not from en_US bundle"); + } + } catch (MissingResourceException mre) { + errln("FAIL: Missing resouces"); + } + + gp.reset(); + + logln("Get a resource bundle " + baseName + + " using GlobalizationPreferences initialized by locales - ja, en_US_California"); + + locales = new ULocale[2]; + locales[0] = new ULocale("ja"); + locales[1] = new ULocale("en_US_California"); + gp.setLocales(locales); + + try { + rb = gp.getResourceBundle(baseName, ClassLoader.getSystemClassLoader()); + String str = rb.getString("from_en_US"); + if (!str.equals("This data comes from en_US")) { + errln("FAIL: from_en_US is not from en_US bundle"); + } + } catch (MissingResourceException mre) { + errln("FAIL: Missing resouces"); + } + + logln("Get a resource bundle which does not exist"); + boolean bException = false; + try { + rb = gp.getResourceBundle("foo.bar.XXX"); + } catch (MissingResourceException mre) { + logln("Missing resource exception for getting resource bundle - foo.bar.XXX"); + bException = true; + } + if (!bException) { + errln("FAIL: MissingResourceException must be thrown for RB - foo.bar.XXX"); + } + } + + public void TestTerritory() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + + // Territory for unsupported language locale + logln("Set locale - ang"); + gp.setLocale(new ULocale("ang")); + String territory = gp.getTerritory(); + if (!territory.equals("US")) { + errln("FAIL: Territory is " + territory + " - Expected: US"); + } + + // Territory for language only locale "fr" + logln("Set locale - fr"); + gp.setLocale(new ULocale("fr")); + territory = gp.getTerritory(); + if (!territory.equals("FR")) { + errln("FAIL: Territory is " + territory + " - Expected: FR"); + } + + + // Set explicity territory + logln("Set explicit territory - CA"); + gp.setTerritory("CA"); + territory = gp.getTerritory(); + if (!territory.equals("CA")) { + errln("FAIL: Territory is " + territory + " - Expected: CA"); + } + + // Freeze + logln("Freeze this object"); + gp.freeze(); + + boolean bFrozen = false; + try { + gp.setTerritory("FR"); + } catch (UnsupportedOperationException uoe) { + logln("setTerritory is blocked"); + bFrozen = true; + } + if (!bFrozen) { + errln("FAIL: setTerritory must be blocked after frozen"); + } + territory = gp.getTerritory(); + if (!territory.equals("CA")) { + errln("FAIL: Territory is not CA"); + } + + // Safe clone + GlobalizationPreferences gp1 = (GlobalizationPreferences)gp.cloneAsThawed(); + territory = gp1.getTerritory(); + if (!territory.equals("CA")) { + errln("FAIL: Territory is " + territory + " - Expected: CA"); + } + + gp1.reset(); + ULocale[] locales = new ULocale[2]; + locales[0] = new ULocale("ja"); + locales[1] = new ULocale("zh_Hant_TW"); + + logln("Set locales - ja, zh_Hant_TW"); + gp1.setLocales(locales); + + territory = gp1.getTerritory(); + if (!territory.equals("TW")) { + errln("FAIL: Territory is " + territory + " - Expected: TW"); + } + } + + public void TestCurrency() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + + // Set language only locale - ja + logln("Set locale - ja"); + gp.setLocale(new ULocale("ja")); + Currency cur = gp.getCurrency(); + String code = cur.getCurrencyCode(); + if (!code.equals("JPY")) { + errln("FAIL: Currency is " + code + " - Expected: JPY"); + } + + gp.reset(); + // Set locales with territory + logln("Set locale - ja_US"); + gp.setLocale(new ULocale("ja_US")); + cur = gp.getCurrency(); + code = cur.getCurrencyCode(); + if (!code.equals("USD")) { + errln("FAIL: Currency is " + code + " - Expected: USD"); + } + + // Set locales with territory in the second locale + logln("Set locales - it, en_US"); + ULocale[] locales = new ULocale[2]; + locales[0] = new ULocale("it"); + locales[1] = new ULocale("en_US"); + gp.setLocales(locales); + cur = gp.getCurrency(); + code = cur.getCurrencyCode(); + if (!code.equals("USD")) { + errln("FAIL: Currency is " + code + " - Expected: USD"); + } + + // Set explicit territory + logln("Set territory - DE"); + gp.setTerritory("DE"); + cur = gp.getCurrency(); + code = cur.getCurrencyCode(); + if (!code.equals("EUR")) { + errln("FAIL: Currency is " + code + " - Expected: EUR"); + } + + // Set explicit currency + Currency ecur = Currency.getInstance("BRL"); + gp.setCurrency(ecur); + logln("Set explicit currency - BRL"); + cur = gp.getCurrency(); + code = cur.getCurrencyCode(); + if (!code.equals("BRL")) { + errln("FAIL: Currency is " + code + " - Expected: BRL"); + } + + // Set explicit territory again + logln("Set territory - JP"); + cur = gp.getCurrency(); + code = cur.getCurrencyCode(); + if (!code.equals("BRL")) { + errln("FAIL: Currency is " + code + " - Expected: BRL"); + } + + // Freeze + logln("Freeze this object"); + Currency ecur2 = Currency.getInstance("CHF"); + boolean bFrozen = false; + gp.freeze(); + try { + gp.setCurrency(ecur2); + } catch (UnsupportedOperationException uoe) { + logln("setCurrency is blocked"); + bFrozen = true; + } + if (!bFrozen) { + errln("FAIL: setCurrency must be blocked"); + } + + // Safe clone + logln("cloneAsThawed"); + GlobalizationPreferences gp1 = (GlobalizationPreferences)gp.cloneAsThawed(); + cur = gp.getCurrency(); + code = cur.getCurrencyCode(); + if (!code.equals("BRL")) { + errln("FAIL: Currency is " + code + " - Expected: BRL"); + } + + // Set ecplicit currency + gp1.setCurrency(ecur2); + cur = gp1.getCurrency(); + code = cur.getCurrencyCode(); + if (!code.equals("CHF")) { + errln("FAIL: Currency is " + code + " - Expected: CHF"); + } + } + + public void TestCalendar() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + + // Set locale - pt_BR + logln("Set locale - pt"); + gp.setLocale(new ULocale("pt")); + Calendar cal = gp.getCalendar(); + String calType = cal.getType(); + if (!calType.equals("gregorian")) { + errln("FAIL: Calendar type is " + calType + " Expected: gregorian"); + } + + // Set a list of locales + logln("Set locales - en, en_JP, en_GB"); + ULocale[] locales = new ULocale[3]; + locales[0] = new ULocale("en"); + locales[1] = new ULocale("en_JP"); + locales[2] = new ULocale("en_GB"); + gp.setLocales(locales); + + cal = gp.getCalendar(); + ULocale calLocale = cal.getLocale(ULocale.VALID_LOCALE); + if (!calLocale.equals(locales[2])) { + errln("FAIL: Calendar locale is " + calLocale.toString() + " - Expected: en_GB"); + } + + // Set ecplicit calendar + logln("Set Japanese calendar to this object"); + JapaneseCalendar jcal = new JapaneseCalendar(); + gp.setCalendar(jcal); + cal = gp.getCalendar(); + calType = cal.getType(); + if (!calType.equals("japanese")) { + errln("FAIL: Calendar type is " + calType + " Expected: japanese"); + } + + jcal.setFirstDayOfWeek(3); + if (cal.getFirstDayOfWeek() == jcal.getFirstDayOfWeek()) { + errln("FAIL: Calendar returned by getCalendar must be a safe copy"); + } + cal.setFirstDayOfWeek(3); + Calendar cal1 = gp.getCalendar(); + if (cal1.getFirstDayOfWeek() == cal.getFirstDayOfWeek()) { + errln("FAIL: Calendar returned by getCalendar must be a safe copy"); + } + + // Freeze + logln("Freeze this object"); + IslamicCalendar ical = new IslamicCalendar(); + boolean bFrozen = false; + gp.freeze(); + try { + gp.setCalendar(ical); + } catch (UnsupportedOperationException uoe) { + logln("setCalendar is blocked"); + bFrozen = true; + } + if (!bFrozen) { + errln("FAIL: setCalendar must be blocked"); + } + + // Safe clone + logln("cloneAsThawed"); + GlobalizationPreferences gp1 = (GlobalizationPreferences)gp.cloneAsThawed(); + cal = gp.getCalendar(); + calType = cal.getType(); + if (!calType.equals("japanese")) { + errln("FAIL: Calendar type afte clone is " + calType + " Expected: japanese"); + } + + logln("Set islamic calendar"); + gp1.setCalendar(ical); + cal = gp1.getCalendar(); + calType = cal.getType(); + if (!calType.equals("islamic")) { + errln("FAIL: Calendar type afte clone is " + calType + " Expected: islamic"); + } + } + + public void TestTimeZone() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + + // Set locale - zh_CN + logln("Set locale - zh_CN"); + gp.setLocale(new ULocale("zh_CN")); + TimeZone tz = gp.getTimeZone(); + String tzid = tz.getID(); + if (!tzid.equals("Asia/Shanghai")) { + errln("FAIL: Time zone ID is " + tzid + " Expected: Asia/Shanghai"); + } + + // Set locale - en + logln("Set locale - en"); + gp.setLocale(new ULocale("en")); + tz = gp.getTimeZone(); + tzid = tz.getID(); + if (!tzid.equals("America/New_York")) { + errln("FAIL: Time zone ID is " + tzid + " Expected: America/New_York"); + } + + // Set territory - GB + logln("Set territory - GB"); + gp.setTerritory("GB"); + tz = gp.getTimeZone(); + tzid = tz.getID(); + if (!tzid.equals("Europe/London")) { + errln("FAIL: Time zone ID is " + tzid + " Expected: Europe/London"); + } + + // Check if getTimeZone returns a safe clone + tz.setID("Bad_ID"); + tz = gp.getTimeZone(); + tzid = tz.getID(); + if (!tzid.equals("Europe/London")) { + errln("FAIL: Time zone ID is " + tzid + " Expected: Europe/London"); + } + + // Set explicit time zone + TimeZone jst = TimeZone.getTimeZone("Asia/Tokyo"); + String customJstId = "Japan_Standard_Time"; + jst.setID(customJstId); + gp.setTimeZone(jst); + tz = gp.getTimeZone(); + tzid = tz.getID(); + if (!tzid.equals(customJstId)) { + errln("FAIL: Time zone ID is " + tzid + " Expected: " + customJstId); + } + + // Freeze + logln("Freeze this object"); + TimeZone cst = TimeZone.getTimeZone("Europe/Paris"); + boolean bFrozen = false; + gp.freeze(); + try { + gp.setTimeZone(cst); + } catch (UnsupportedOperationException uoe) { + logln("setTimeZone is blocked"); + bFrozen = true; + } + if (!bFrozen) { + errln("FAIL: setTimeZone must be blocked"); + } + + // Modifiable clone + logln("cloneAsThawed"); + GlobalizationPreferences gp1 = (GlobalizationPreferences)gp.cloneAsThawed(); + tz = gp1.getTimeZone(); + tzid = tz.getID(); + if (!tzid.equals(customJstId)) { + errln("FAIL: Time zone ID is " + tzid + " Expected: " + customJstId); + } + + // Set explicit time zone + gp1.setTimeZone(cst); + tz = gp1.getTimeZone(); + tzid = tz.getID(); + if (!tzid.equals(cst.getID())) { + errln("FAIL: Time zone ID is " + tzid + " Expected: " + cst.getID()); + } + } + + public void TestCollator() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + + // Set locale - tr + logln("Set locale - tr"); + gp.setLocale(new ULocale("tr")); + Collator coll = gp.getCollator(); + String locStr = coll.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("tr")) { + errln("FAIL: Collator locale is " + locStr + " Expected: tr"); + } + + // Unsupported collator locale - zun + logln("Set locale - zun"); + gp.setLocale(new ULocale("zun")); + coll = gp.getCollator(); + locStr = coll.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("root")) { + errln("FAIL: Collator locale is " + locStr + " Expected: root"); + } + + // Set locales - en_JP, fr, en_US, fr_FR + logln("Set locale - en_JP, fr, en_US, fr_FR"); + ULocale[] locales = new ULocale[4]; + locales[0] = new ULocale("en_JP"); + locales[1] = new ULocale("fr"); + locales[2] = new ULocale("en_US"); + locales[3] = new ULocale("fr_FR"); + gp.setLocales(locales); + coll = gp.getCollator(); + locStr = coll.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("fr_FR")) { + errln("FAIL: Collator locale is " + locStr + " Expected: fr_FR"); + } + + // Set explicit Collator + Collator coll1 = Collator.getInstance(new ULocale("it")); + coll1.setDecomposition(Collator.CANONICAL_DECOMPOSITION); + logln("Set collator for it in canonical deconposition mode"); + gp.setCollator(coll1); + coll1.setStrength(Collator.IDENTICAL); + coll = gp.getCollator(); + locStr = coll.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("it")) { + errln("FAIL: Collator locale is " + locStr + " Expected: it"); + } + if (coll1.equals(coll)) { + errln("FAIL: setCollator must use a safe copy of a Collator"); + } + + // Freeze + logln("Freeze this object"); + boolean isFrozen = false; + gp.freeze(); + try { + gp.setCollator(coll1); + } catch (UnsupportedOperationException uoe) { + logln("setCollator is blocked"); + isFrozen = true; + } + if (!isFrozen) { + errln("FAIL: setCollator must be blocked after freeze"); + } + + // Modifiable clone + logln("cloneAsThawed"); + GlobalizationPreferences gp1 = (GlobalizationPreferences)gp.cloneAsThawed(); + coll = gp1.getCollator(); + locStr = coll.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("it")) { + errln("FAIL: Collator locale is " + locStr + " Expected: it"); + } + if (coll.getDecomposition() != Collator.CANONICAL_DECOMPOSITION) { + errln("FAIL: Decomposition mode is not CANONICAL_DECOMPOSITION"); + } + + // Set custom collator again + gp1.setCollator(coll1); + coll = gp1.getCollator(); + if (coll.getStrength() != Collator.IDENTICAL) { + errln("FAIL: Strength is not IDENTICAL"); + } + } + + public void TestBreakIterator() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + + // Unsupported break iterator locale - aar + logln("Set locale - aar"); + gp.setLocale(new ULocale("aar")); + BreakIterator brk = gp.getBreakIterator(GlobalizationPreferences.BI_LINE); + String locStr = brk.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("root")) { + errln("FAIL: Line break iterator locale is " + locStr + " Expected: root"); + } + + // Set locale - es + logln("Set locale - es"); + gp.setLocale(new ULocale("es")); + brk = gp.getBreakIterator(GlobalizationPreferences.BI_CHARACTER); + locStr = brk.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("es")) { + errln("FAIL: Character break iterator locale is " + locStr + " Expected: es"); + } + + // Set explicit break sentence iterator + logln("Set break iterator for sentence using locale hu_HU"); + BreakIterator brk1 = BreakIterator.getSentenceInstance(new ULocale("hu_HU")); + gp.setBreakIterator(GlobalizationPreferences.BI_SENTENCE, brk1); + + brk = gp.getBreakIterator(GlobalizationPreferences.BI_SENTENCE); + /* Skip - Bug#5210 + locStr = brk.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("hu_HU")) { + errln("FAIL: Sentence break locale is " + locStr + " Expected: hu_HU"); + } + */ + brk.setText("This is a test case. Is this a new instance?"); + brk.next(); + if (brk1.current() == brk.current()) { + errln("FAIL: getBreakIterator must return a new instance"); + } + + // Illegal argument + logln("Get break iterator type 100"); + boolean illegalArg = false; + try { + brk = gp.getBreakIterator(100); + } catch (IllegalArgumentException iae) { + logln("Break iterator type 100 is illegal"); + illegalArg = true; + } + if (!illegalArg) { + errln("FAIL: getBreakIterator must throw IllegalArgumentException for type 100"); + } + logln("Set break iterator type -1"); + illegalArg = false; + try { + gp.setBreakIterator(-1, brk1); + } catch (IllegalArgumentException iae) { + logln("Break iterator type -1 is illegal"); + illegalArg = true; + } + if (!illegalArg) { + errln("FAIL: getBreakIterator must throw IllegalArgumentException for type -1"); + } + + // Freeze + logln("Freeze this object"); + BreakIterator brk2 = BreakIterator.getTitleInstance(new ULocale("es_MX")); + boolean isFrozen = false; + gp.freeze(); + try { + gp.setBreakIterator(GlobalizationPreferences.BI_TITLE, brk2); + } catch (UnsupportedOperationException uoe) { + logln("setBreakIterator is blocked"); + isFrozen = true; + } + if (!isFrozen) { + errln("FAIL: setBreakIterator must be blocked after frozen"); + } + + // Modifiable clone + logln("cloneAsThawed"); + GlobalizationPreferences gp1 = (GlobalizationPreferences)gp.cloneAsThawed(); + brk = gp1.getBreakIterator(GlobalizationPreferences.BI_WORD); + locStr = brk.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("es")) { + errln("FAIL: Word break iterator locale is " + locStr + " Expected: es"); + } + + ULocale frFR = new ULocale("fr_FR"); + BreakIterator brkC = BreakIterator.getCharacterInstance(frFR); + BreakIterator brkW = BreakIterator.getWordInstance(frFR); + BreakIterator brkL = BreakIterator.getLineInstance(frFR); + BreakIterator brkS = BreakIterator.getSentenceInstance(frFR); + BreakIterator brkT = BreakIterator.getTitleInstance(frFR); + + gp1.setBreakIterator(GlobalizationPreferences.BI_CHARACTER, brkC); + gp1.setBreakIterator(GlobalizationPreferences.BI_WORD, brkW); + gp1.setBreakIterator(GlobalizationPreferences.BI_LINE, brkL); + gp1.setBreakIterator(GlobalizationPreferences.BI_SENTENCE, brkS); + gp1.setBreakIterator(GlobalizationPreferences.BI_TITLE, brkT); + + /* Skip - Bug#5210 + locStr = brkC.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("ja_JP")) { + errln("FAIL: Character break iterator locale is " + locStr + " Expected: fr_FR"); + } + locStr = brkW.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("ja_JP")) { + errln("FAIL: Word break iterator locale is " + locStr + " Expected: fr_FR"); + } + locStr = brkL.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("ja_JP")) { + errln("FAIL: Line break iterator locale is " + locStr + " Expected: fr_FR"); + } + locStr = brkS.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("ja_JP")) { + errln("FAIL: Sentence break iterator locale is " + locStr + " Expected: fr_FR"); + } + locStr = brkT.getLocale(ULocale.VALID_LOCALE).toString(); + if (!locStr.equals("ja_JP")) { + errln("FAIL: Title break iterator locale is " + locStr + " Expected: fr_FR"); + } + */ + } + + public void TestDisplayName() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + + ULocale loc_fr_FR_Paris = new ULocale("fr_FR_Paris"); + ULocale loc_peo = new ULocale("peo"); + + // Locale list - fr_FR_Paris + ArrayList locales1 = new ArrayList(1); + locales1.add(loc_fr_FR_Paris); + + // Locale list - ain, fr_FR_Paris + ArrayList locales2 = new ArrayList(2); + locales2.add(loc_peo); + locales2.add(loc_fr_FR_Paris); + + logln("Locales: | | "); + + // ID_LOCALE + String id = "zh_Hant_HK"; + String name1 = gp.getDisplayName(id, GlobalizationPreferences.ID_LOCALE); + gp.setLocales(locales1); + String name2 = gp.getDisplayName(id, GlobalizationPreferences.ID_LOCALE); + gp.setLocales(locales2); + String name3 = gp.getDisplayName(id, GlobalizationPreferences.ID_LOCALE); + + logln("Locale[zh_Hant_HK]: " + name1 + " | " + name2 + " | " + name3); + if (name1.equals(name2) || !name2.equals(name3)) { + errln("FAIL: Locale ID"); + } + + // ID_LANGUAGE + gp.reset(); + id = "fr"; + name1 = gp.getDisplayName(id, GlobalizationPreferences.ID_LANGUAGE); + gp.setLocales(locales1); + name2 = gp.getDisplayName(id, GlobalizationPreferences.ID_LANGUAGE); + gp.setLocales(locales2); + name3 = gp.getDisplayName(id, GlobalizationPreferences.ID_LANGUAGE); + + logln("Language[fr]: " + name1 + " | " + name2 + " | " + name3); + if (name1.equals(name2) || !name2.equals(name3)) { + errln("FAIL: Language ID"); + } + + // ID_SCRIPT + gp.reset(); + id = "cyrl"; + name1 = gp.getDisplayName(id, GlobalizationPreferences.ID_SCRIPT); + gp.setLocales(locales1); + name2 = gp.getDisplayName(id, GlobalizationPreferences.ID_SCRIPT); + gp.setLocales(locales2); + name3 = gp.getDisplayName(id, GlobalizationPreferences.ID_SCRIPT); + + logln("Script[cyrl]: " + name1 + " | " + name2 + " | " + name3); + if (name1.equals(name2) || !name2.equals(name3)) { + errln("FAIL: Script ID"); + } + + // ID_TERRITORY + gp.reset(); + id = "JP"; + name1 = gp.getDisplayName(id, GlobalizationPreferences.ID_TERRITORY); + gp.setLocales(locales1); + name2 = gp.getDisplayName(id, GlobalizationPreferences.ID_TERRITORY); + gp.setLocales(locales2); + name3 = gp.getDisplayName(id, GlobalizationPreferences.ID_TERRITORY); + + logln("Territory[JP]: " + name1 + " | " + name2 + " | " + name3); + if (name1.equals(name2) || !name2.equals(name3)) { + errln("FAIL: Territory ID"); + } + + // ID_VARIANT + gp.reset(); + id = "NEDIS"; + name1 = gp.getDisplayName(id, GlobalizationPreferences.ID_VARIANT); + gp.setLocales(locales1); + name2 = gp.getDisplayName(id, GlobalizationPreferences.ID_VARIANT); + gp.setLocales(locales2); + name3 = gp.getDisplayName(id, GlobalizationPreferences.ID_VARIANT); + + logln("Variant[NEDIS]: " + name1 + " | " + name2 + " | " + name3); + if (name1.equals(name2) || !name2.equals(name3)) { + errln("FAIL: Variant ID"); + } + + // ID_KEYWORD + gp.reset(); + id = "collation"; + name1 = gp.getDisplayName(id, GlobalizationPreferences.ID_KEYWORD); + gp.setLocales(locales1); + name2 = gp.getDisplayName(id, GlobalizationPreferences.ID_KEYWORD); + gp.setLocales(locales2); + name3 = gp.getDisplayName(id, GlobalizationPreferences.ID_KEYWORD); + + logln("Keyword[collation]: " + name1 + " | " + name2 + " | " + name3); + if (name1.equals(name2) || !name2.equals(name3)) { + errln("FAIL: Keyword ID"); + } + + // ID_KEYWORD_VALUE + gp.reset(); + id = "collation=traditional"; + name1 = gp.getDisplayName(id, GlobalizationPreferences.ID_KEYWORD_VALUE); + gp.setLocales(locales1); + name2 = gp.getDisplayName(id, GlobalizationPreferences.ID_KEYWORD_VALUE); + gp.setLocales(locales2); + name3 = gp.getDisplayName(id, GlobalizationPreferences.ID_KEYWORD_VALUE); + + logln("Keyword value[traditional]: " + name1 + " | " + name2 + " | " + name3); + if (name1.equals(name2) || !name2.equals(name3)) { + errln("FAIL: Keyword value ID"); + } + + // ID_CURRENCY_SYMBOL + gp.reset(); + id = "USD"; + name1 = gp.getDisplayName(id, GlobalizationPreferences.ID_CURRENCY_SYMBOL); + gp.setLocales(locales1); + name2 = gp.getDisplayName(id, GlobalizationPreferences.ID_CURRENCY_SYMBOL); + gp.setLocales(locales2); + name3 = gp.getDisplayName(id, GlobalizationPreferences.ID_CURRENCY_SYMBOL); + + logln("Currency symbol[USD]: " + name1 + " | " + name2 + " | " + name3); + String dollar = "$"; + if (!name1.equals(dollar) || !name2.equals(dollar) || !name3.equals(dollar)) { + errln("FAIL: Currency symbol ID"); + } + + // ID_CURRENCY + gp.reset(); + id = "USD"; + name1 = gp.getDisplayName(id, GlobalizationPreferences.ID_CURRENCY); + gp.setLocales(locales1); + name2 = gp.getDisplayName(id, GlobalizationPreferences.ID_CURRENCY); + gp.setLocales(locales2); + name3 = gp.getDisplayName(id, GlobalizationPreferences.ID_CURRENCY); + + logln("Currency[USD]: " + name1 + " | " + name2 + " | " + name3); + if (name1.equals(name2) || !name2.equals(name3)) { + errln("FAIL: Currency ID"); + } + + // ID_TIMEZONE + gp.reset(); + id = "Europe/Paris"; + name1 = gp.getDisplayName(id, GlobalizationPreferences.ID_TIMEZONE); + gp.setLocales(locales1); + name2 = gp.getDisplayName(id, GlobalizationPreferences.ID_TIMEZONE); + gp.setLocales(locales2); + name3 = gp.getDisplayName(id, GlobalizationPreferences.ID_TIMEZONE); + + logln("Timezone[Europe/Paris]: " + name1 + " | " + name2 + " | " + name3); + if (name1.equals(name2) || !name2.equals(name3)) { + errln("FAIL: Timezone ID"); + } + + // Illegal ID + gp.reset(); + boolean illegalArg = false; + try { + name1 = gp.getDisplayName(id, -1); + } catch (IllegalArgumentException iae) { + logln("Illegal type -1"); + illegalArg = true; + } + if (!illegalArg) { + errln("FAIL: getDisplayName must throw IllegalArgumentException for type -1"); + } + + illegalArg = false; + try { + name1 = gp.getDisplayName(id, 100); + } catch (IllegalArgumentException iae) { + logln("Illegal type 100"); + illegalArg = true; + } + if (!illegalArg) { + errln("FAIL: getDisplayName must throw IllegalArgumentException for type 100"); + } + } + + public void TestDateFormat() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + + String pattern; + DateFormat df; + + // Set unsupported locale - ach + logln("Set locale - ach"); + gp.setLocale(new ULocale("ach")); + + // Date - short + df = gp.getDateFormat(GlobalizationPreferences.DF_SHORT, GlobalizationPreferences.DF_NONE); + pattern = ((SimpleDateFormat)df).toPattern(); + // root pattern must be used + if (!pattern.equals("yy/MM/dd")) { + errln("FAIL: SHORT date pattern is " + pattern + " Expected: yy/MM/dd"); + } + + // Set locale - fr, fr_CA, fr_FR + ArrayList lcls = new ArrayList(3); + lcls.add(new ULocale("fr")); + lcls.add(new ULocale("fr_CA")); + lcls.add(new ULocale("fr_FR")); + logln("Set locales - fr, fr_CA, fr_FR"); + gp.setLocales(lcls); + // Date - short + df = gp.getDateFormat(GlobalizationPreferences.DF_SHORT, GlobalizationPreferences.DF_NONE); + pattern = ((SimpleDateFormat)df).toPattern(); + // fr_CA pattern must be used + if (!pattern.equals("yy-MM-dd")) { + errln("FAIL: FULL date pattern is " + pattern + " Expected: yy-MM-dd"); + } + + + // Set locale - en_GB + logln("Set locale - en_GB"); + gp.setLocale(new ULocale("en_GB")); + + // Date - full + df = gp.getDateFormat(GlobalizationPreferences.DF_FULL, GlobalizationPreferences.DF_NONE); + pattern = ((SimpleDateFormat)df).toPattern(); + if (!pattern.equals("EEEE, d MMMM yyyy")) { + errln("FAIL: FULL date pattern is " + pattern + " Expected: EEEE, d MMMM yyyy"); + } + + // Date - long + df = gp.getDateFormat(GlobalizationPreferences.DF_LONG, GlobalizationPreferences.DF_NONE); + pattern = ((SimpleDateFormat)df).toPattern(); + if (!pattern.equals("d MMMM yyyy")) { + errln("FAIL: LONG date pattern is " + pattern + " Expected: d MMMM yyyy"); + } + + // Date - medium + df = gp.getDateFormat(GlobalizationPreferences.DF_MEDIUM, GlobalizationPreferences.DF_NONE); + pattern = ((SimpleDateFormat)df).toPattern(); + if (!pattern.equals("d MMM yyyy")) { + errln("FAIL: MEDIUM date pattern is " + pattern + " Expected: d MMM yyyy"); + } + + // Date - short + df = gp.getDateFormat(GlobalizationPreferences.DF_SHORT, GlobalizationPreferences.DF_NONE); + pattern = ((SimpleDateFormat)df).toPattern(); + if (!pattern.equals("dd/MM/yyyy")) { + errln("FAIL: SHORT date pattern is " + pattern + " Expected: dd/MM/yyyy"); + } + + // Time - full + df = gp.getDateFormat(GlobalizationPreferences.DF_NONE, GlobalizationPreferences.DF_FULL); + pattern = ((SimpleDateFormat)df).toPattern(); + if (!pattern.equals("HH:mm:ss z")) { + errln("FAIL: FULL time pattern is " + pattern + " Expected: HH:mm:ss z"); + } + + // Time - long + df = gp.getDateFormat(GlobalizationPreferences.DF_NONE, GlobalizationPreferences.DF_LONG); + pattern = ((SimpleDateFormat)df).toPattern(); + if (!pattern.equals("HH:mm:ss z")) { + errln("FAIL: LONG time pattern is " + pattern + " Expected: HH:mm:ss z"); + } + + // Time - medium + df = gp.getDateFormat(GlobalizationPreferences.DF_NONE, GlobalizationPreferences.DF_MEDIUM); + pattern = ((SimpleDateFormat)df).toPattern(); + if (!pattern.equals("HH:mm:ss")) { + errln("FAIL: MEDIUM time pattern is " + pattern + " Expected: HH:mm:ss"); + } + + // Time - short + df = gp.getDateFormat(GlobalizationPreferences.DF_NONE, GlobalizationPreferences.DF_SHORT); + pattern = ((SimpleDateFormat)df).toPattern(); + if (!pattern.equals("HH:mm")) { + errln("FAIL: SHORT time pattern is " + pattern + " Expected: HH:mm"); + } + + // Date/Time - full + df = gp.getDateFormat(GlobalizationPreferences.DF_FULL, GlobalizationPreferences.DF_FULL); + pattern = ((SimpleDateFormat)df).toPattern(); + if (!pattern.equals("EEEE, d MMMM yyyy HH:mm:ss z")) { + errln("FAIL: FULL date/time pattern is " + pattern + " Expected: EEEE, d MMMM yyyy HH:mm:ss z"); + } + + // Invalid style + boolean illegalArg = false; + try { + df = gp.getDateFormat(-1, GlobalizationPreferences.DF_NONE); + } catch (IllegalArgumentException iae) { + logln("Illegal date style -1"); + illegalArg = true; + } + if (!illegalArg) { + errln("FAIL: getDateFormat() must throw IllegalArgumentException for dateStyle -1"); + } + + illegalArg = false; + try { + df = gp.getDateFormat(GlobalizationPreferences.DF_NONE, GlobalizationPreferences.DF_NONE); + } catch (IllegalArgumentException iae) { + logln("Illegal style - dateStyle:DF_NONE / timeStyle:DF_NONE"); + illegalArg = true; + } + if (!illegalArg) { + errln("FAIL: getDateFormat() must throw IllegalArgumentException for dateStyle:DF_NONE/timeStyle:DF_NONE"); + } + + // Set explicit time zone + logln("Set timezone - America/Sao_Paulo"); + TimeZone tz = TimeZone.getTimeZone("America/Sao_Paulo"); + gp.setTimeZone(tz); + df = gp.getDateFormat(GlobalizationPreferences.DF_LONG, GlobalizationPreferences.DF_MEDIUM); + String tzid = df.getTimeZone().getID(); + if (!tzid.equals("America/Sao_Paulo")) { + errln("FAIL: The DateFormat instance must use timezone America/Sao_Paulo"); + } + + // Set explicit calendar + logln("Set calendar - japanese"); + Calendar jcal = new JapaneseCalendar(); + jcal.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo")); + gp.setCalendar(jcal); + df = gp.getDateFormat(GlobalizationPreferences.DF_SHORT, GlobalizationPreferences.DF_SHORT); + Calendar dfCal = df.getCalendar(); + if (!(dfCal instanceof JapaneseCalendar)) { + errln("FAIL: The DateFormat instance must use Japanese calendar"); + } + // TimeZone must be still America/Sao_Paulo + tzid = df.getTimeZone().getID(); + if (!tzid.equals("America/Sao_Paulo")) { + errln("FAIL: The DateFormat instance must use timezone America/Sao_Paulo"); + } + + // Set explicit DateFormat + logln("Set explicit date format - full date"); + DateFormat customFD = DateFormat.getDateInstance(new IslamicCalendar(), DateFormat.FULL, new ULocale("ar_SA")); + customFD.setTimeZone(TimeZone.getTimeZone("Asia/Riyadh")); + gp.setDateFormat(GlobalizationPreferences.DF_FULL, GlobalizationPreferences.DF_NONE, customFD); + df = gp.getDateFormat(GlobalizationPreferences.DF_FULL, GlobalizationPreferences.DF_NONE); + dfCal = df.getCalendar(); + if (!(dfCal instanceof IslamicCalendar)) { + errln("FAIL: The DateFormat instance must use Islamic calendar"); + } + // TimeZone in the custom DateFormat is overridden by GP's timezone setting + tzid = df.getTimeZone().getID(); + if (!tzid.equals("America/Sao_Paulo")) { + errln("FAIL: The DateFormat instance must use timezone America/Sao_Paulo"); + } + + // Freeze + logln("Freeze this object"); + gp.freeze(); + DateFormat customLD = DateFormat.getDateInstance(new BuddhistCalendar(), DateFormat.LONG, new ULocale("th")); + customLD.setTimeZone(TimeZone.getTimeZone("Asia/Bangkok")); + boolean isFrozen = false; + try { + gp.setDateFormat(GlobalizationPreferences.DF_LONG, GlobalizationPreferences.DF_NONE, customLD); + } catch (UnsupportedOperationException uoe) { + logln("setDateFormat is blocked"); + isFrozen = true; + } + if (!isFrozen) { + errln("FAIL: setDateFormat must be blocked after frozen"); + } + + // Modifiable clone + logln("cloneAsThawed"); + GlobalizationPreferences gp1 = (GlobalizationPreferences)gp.cloneAsThawed(); + gp1.setDateFormat(GlobalizationPreferences.DF_LONG, GlobalizationPreferences.DF_NONE, customLD); + + df = gp1.getDateFormat(GlobalizationPreferences.DF_SHORT, GlobalizationPreferences.DF_SHORT); + dfCal = df.getCalendar(); + if (!(dfCal instanceof JapaneseCalendar)) { + errln("FAIL: The DateFormat instance must use Japanese calendar"); + } + // TimeZone must be still America/Sao_Paulo + tzid = df.getTimeZone().getID(); + if (!tzid.equals("America/Sao_Paulo")) { + errln("FAIL: The DateFormat instance must use timezone America/Sao_Paulo"); + } + + df = gp1.getDateFormat(GlobalizationPreferences.DF_LONG, GlobalizationPreferences.DF_NONE); + dfCal = df.getCalendar(); + if (!(dfCal instanceof BuddhistCalendar)) { + errln("FAIL: The DateFormat instance must use Buddhist calendar"); + } + // TimeZone must be still America/Sao_Paulo + tzid = df.getTimeZone().getID(); + if (!tzid.equals("America/Sao_Paulo")) { + errln("FAIL: The DateFormat instance must use timezone America/Sao_Paulo"); + } + + } + + public void TestNumberFormat() { + GlobalizationPreferences gp = new GlobalizationPreferences(); + + NumberFormat nf; + String numStr; + double num = 123456.789; + + // Set unsupported locale with supported territory ang_KR + logln("Set locale - ang_KR"); + gp.setLocale(new ULocale("ang_KR")); + nf = gp.getNumberFormat(GlobalizationPreferences.NF_CURRENCY); + numStr = nf.format(num); + if (!numStr.equals("KRW 123,457")) { + errln("FAIL: Number string is " + numStr + " Expected: KRW 123,457"); + } + + // Set locale - de_DE + logln("Set locale - de_DE"); + gp.setLocale(new ULocale("de_DE")); + + // NF_NUMBER + logln("NUMBER type"); + nf = gp.getNumberFormat(GlobalizationPreferences.NF_NUMBER); + numStr = nf.format(num); + if (!numStr.equals("123.456,789")) { + errln("FAIL: Number string is " + numStr + " Expected: 123.456,789"); + } + + // NF_CURRENCY + logln("CURRENCY type"); + nf = gp.getNumberFormat(GlobalizationPreferences.NF_CURRENCY); + numStr = nf.format(num); + if (!numStr.equals("123.456,79 \u20AC")) { + errln("FAIL: Number string is " + numStr + " Expected: 123.456,79 \u20AC"); + } + + // NF_PERCENT + logln("PERCENT type"); + nf = gp.getNumberFormat(GlobalizationPreferences.NF_PERCENT); + numStr = nf.format(num); + if (!numStr.equals("12.345.679%")) { + errln("FAIL: Number string is " + numStr + " Expected: 12.345.679%"); + } + + // NF_SCIENTIFIC + logln("SCIENTIFIC type"); + nf = gp.getNumberFormat(GlobalizationPreferences.NF_SCIENTIFIC); + numStr = nf.format(num); + if (!numStr.equals("1,23456789E5")) { + errln("FAIL: Number string is " + numStr + " Expected: 1,23456789E5"); + } + + // NF_INTEGER + logln("INTEGER type"); + nf = gp.getNumberFormat(GlobalizationPreferences.NF_INTEGER); + numStr = nf.format(num); + if (!numStr.equals("123.457")) { + errln("FAIL: Number string is " + numStr + " Expected: 123.457"); + } + + // Invalid number type + logln("INVALID type"); + boolean illegalArg = false; + try { + nf = gp.getNumberFormat(100); + } catch (IllegalArgumentException iae) { + logln("Illegal number format type 100"); + illegalArg = true; + } + if (!illegalArg) { + errln("FAIL: getNumberFormat must throw IllegalArgumentException for type 100"); + } + illegalArg = false; + try { + nf = gp.getNumberFormat(-1); + } catch (IllegalArgumentException iae) { + logln("Illegal number format type -1"); + illegalArg = true; + } + if (!illegalArg) { + errln("FAIL: getNumberFormat must throw IllegalArgumentException for type -1"); + } + + // Set explicit territory + logln("Set territory - US"); + gp.setTerritory("US"); + nf = gp.getNumberFormat(GlobalizationPreferences.NF_CURRENCY); + numStr = nf.format(num); + if (!numStr.equals("123.456,79 $")) { + errln("FAIL: Number string is " + numStr + " Expected: 123.456,79 $"); + } + + // Set explicit currency + logln("Set currency - GBP"); + gp.setCurrency(Currency.getInstance("GBP")); + nf = gp.getNumberFormat(GlobalizationPreferences.NF_CURRENCY); + numStr = nf.format(num); + if (!numStr.equals("123.456,79 \u00A3")) { + errln("FAIL: Number string is " + numStr + " Expected: 123.456,79 \u00A3"); + } + + // Set exliplicit NumberFormat + logln("Set explicit NumberFormat objects"); + NumberFormat customNum = NumberFormat.getNumberInstance(new ULocale("he_IL")); + gp.setNumberFormat(GlobalizationPreferences.NF_NUMBER, customNum); + NumberFormat customCur = NumberFormat.getCurrencyInstance(new ULocale("zh_CN")); + gp.setNumberFormat(GlobalizationPreferences.NF_CURRENCY, customCur); + NumberFormat customPct = NumberFormat.getPercentInstance(new ULocale("el_GR")); + gp.setNumberFormat(GlobalizationPreferences.NF_PERCENT, customPct); + NumberFormat customSci = NumberFormat.getScientificInstance(new ULocale("ru_RU")); + gp.setNumberFormat(GlobalizationPreferences.NF_SCIENTIFIC, customSci); + NumberFormat customInt = NumberFormat.getIntegerInstance(new ULocale("pt_PT")); + gp.setNumberFormat(GlobalizationPreferences.NF_INTEGER, customInt); + + + nf = gp.getNumberFormat(GlobalizationPreferences.NF_NUMBER); + if (!nf.getLocale(ULocale.VALID_LOCALE).toString().equals("he_IL")) { + errln("FAIL: The NumberFormat instance must use locale he_IL"); + } + nf = gp.getNumberFormat(GlobalizationPreferences.NF_CURRENCY); + if (!nf.getLocale(ULocale.VALID_LOCALE).toString().equals("zh_CN")) { + errln("FAIL: The NumberFormat instance must use locale zh_CN"); + } + nf = gp.getNumberFormat(GlobalizationPreferences.NF_PERCENT); + if (!nf.getLocale(ULocale.VALID_LOCALE).toString().equals("el_GR")) { + errln("FAIL: The NumberFormat instance must use locale el_GR"); + } + nf = gp.getNumberFormat(GlobalizationPreferences.NF_SCIENTIFIC); + if (!nf.getLocale(ULocale.VALID_LOCALE).toString().equals("ru_RU")) { + errln("FAIL: The NumberFormat instance must use locale ru_RU"); + } + nf = gp.getNumberFormat(GlobalizationPreferences.NF_INTEGER); + if (!nf.getLocale(ULocale.VALID_LOCALE).toString().equals("pt_PT")) { + errln("FAIL: The NumberFormat instance must use locale pt_PT"); + } + + NumberFormat customNum1 = NumberFormat.getNumberInstance(new ULocale("hi_IN")); + + // Freeze + logln("Freeze this object"); + boolean isFrozen = false; + gp.freeze(); + try { + gp.setNumberFormat(GlobalizationPreferences.NF_NUMBER, customNum1); + } catch (UnsupportedOperationException uoe) { + logln("setNumberFormat is blocked"); + isFrozen = true; + } + if (!isFrozen) { + errln("FAIL: setNumberFormat must be blocked after frozen"); + } + + // Create a modifiable clone + GlobalizationPreferences gp1 = (GlobalizationPreferences)gp.cloneAsThawed(); + + // Number type format's locale is still he_IL + nf = gp1.getNumberFormat(GlobalizationPreferences.NF_NUMBER); + if (!nf.getLocale(ULocale.VALID_LOCALE).toString().equals("he_IL")) { + errln("FAIL: The NumberFormat instance must use locale he_IL"); + } + + logln("Set custom number format using locale hi_IN"); + gp1.setNumberFormat(GlobalizationPreferences.NF_NUMBER, customNum1); + nf = gp1.getNumberFormat(GlobalizationPreferences.NF_NUMBER); + if (!nf.getLocale(ULocale.VALID_LOCALE).toString().equals("hi_IN")) { + errln("FAIL: The NumberFormat instance must use locale hi_IN"); } } - */ } diff --git a/icu4j/src/com/ibm/icu/util/GlobalizationPreferences.java b/icu4j/src/com/ibm/icu/util/GlobalizationPreferences.java index 439a593a6a9..2a77f7201a0 100644 --- a/icu4j/src/com/ibm/icu/util/GlobalizationPreferences.java +++ b/icu4j/src/com/ibm/icu/util/GlobalizationPreferences.java @@ -8,6 +8,7 @@ package com.ibm.icu.util; import java.util.ArrayList; import java.util.Arrays; +import java.util.BitSet; import java.util.Date; import java.util.HashMap; import java.util.Iterator; @@ -17,19 +18,15 @@ import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.TreeMap; - //#ifndef FOUNDATION import java.util.regex.Matcher; import java.util.regex.Pattern; //#endif - import com.ibm.icu.impl.Utility; import com.ibm.icu.impl.ZoneMeta; import com.ibm.icu.text.BreakIterator; import com.ibm.icu.text.Collator; import com.ibm.icu.text.DateFormat; -import com.ibm.icu.text.DecimalFormat; -import com.ibm.icu.text.DecimalFormatSymbols; import com.ibm.icu.text.NumberFormat; import com.ibm.icu.text.SimpleDateFormat; @@ -62,9 +59,9 @@ import com.ibm.icu.text.SimpleDateFormat; * English, then the display name for a language will be returned in Breton if * available, otherwise in French if available, otherwise in English. *

- * The codes used to reference territory, currency, etc. are as defined elsewhere in ICU, - * and are taken from CLDR (which reflects RFC 3066bis usage, ISO 4217, and the - * TZ Timezone database identifiers). + * The codes used to reference territory, currency, etc. are as defined elsewhere + * in ICU, and are taken from CLDR (which reflects RFC 3066bis usage, ISO 4217, + * and the TZ Timezone database identifiers). *

* This is at a prototype stage, and has not incorporated all the design * changes that we would like yet; further feedback is welcome.

@@ -137,9 +134,9 @@ public class GlobalizationPreferences implements Freezable { ID_CURRENCY = 7, ID_CURRENCY_SYMBOL = 8, ID_TIMEZONE = 9; - + private static final int ID_LIMIT = ID_TIMEZONE + 1; - + /** * Break iterator types * @internal @@ -153,45 +150,42 @@ public class GlobalizationPreferences implements Freezable { BI_TITLE = BreakIterator.KIND_TITLE; // 4 private static final int BI_LIMIT = BI_TITLE + 1; - + /** * Sets the language/locale priority list. If other information is * not (yet) available, this is used to to produce a default value * for the appropriate territory, currency, timezone, etc. The * user should be given the opportunity to correct those defaults * in case they are incorrect. + * * @param locales list of locales in priority order, eg {"be", "fr"} * for Breton first, then French if that fails. * @return this, for chaining * @internal * @deprecated This API is ICU internal only. */ - public GlobalizationPreferences setLocales(List locales) { + public GlobalizationPreferences setLocales(List inputLocales) { if (isFrozen()) { throw new UnsupportedOperationException("Attempt to modify immutable object"); } - if (locales.size() == 1) { - this.locales = locales.get(0); - } else if (locales.size() > 1) { - this.locales = new ArrayList(locales); // clone for safety - } + locales = processLocales(inputLocales); return this; } /** * Get a copy of the language/locale priority list + * * @return a copy of the language/locale priority list. * @internal * @deprecated This API is ICU internal only. */ public List getLocales() { - List result = new ArrayList(); // clone for safety + List result; if (locales == null) { result = guessLocales(); - } else if (locales instanceof ULocale) { - result.add(locales); } else { - result.addAll((List)locales); + result = new ArrayList(); + result.addAll(locales); } return result; } @@ -199,26 +193,25 @@ public class GlobalizationPreferences implements Freezable { /** * Convenience function for getting the locales in priority order * @param index The index (0..n) of the desired item. - * @return desired item. + * @return desired item. null if index is out of range * @internal * @deprecated This API is ICU internal only. */ public ULocale getLocale(int index) { - if (locales == null) { - return (ULocale)guessLocales().get(index); - } else if (locales instanceof ULocale) { - if (index != 0) { - throw new IllegalArgumentException("Out of bounds: " + index); - } - return (ULocale)locales; - } else { - return (ULocale)((List)locales).get(index); + List lcls = locales; + if (lcls == null) { + lcls = guessLocales(); } + if (index >= 0 && index < lcls.size()) { + return (ULocale)lcls.get(index); + } + return null; } /** * Convenience routine for setting the language/locale priority * list from an array. + * * @see #setLocales(List locales) * @param uLocales list of locales in an array * @return this, for chaining @@ -235,6 +228,7 @@ public class GlobalizationPreferences implements Freezable { /** * Convenience routine for setting the language/locale priority * list from a single locale/language. + * * @see #setLocales(List locales) * @param uLocale single locale * @return this, for chaining @@ -306,134 +300,6 @@ public class GlobalizationPreferences implements Freezable { } //#endif - /** - * Convenience routine for populating locale fallback order. - * @return a copy of fallback locale priority list - * @internal - * @deprecated This API is ICU internal only. - */ - public List getFallbackLocales() { - ArrayList fallbacks = new ArrayList(); - List localeList = getLocales(); - - /* - * Step 1: Relocate later occurence of more specific locale - * before earlier occurence of less specific locale. - * - * Example: - * Before - en_US, fr_FR, zh, en_US_Boston, zh_TW, zh_Hant, fr_CA - * After - en_US_Boston, en_US, fr_FR, zh_TW, zh_Hant, zh, fr_CA - */ - for (int i = 0; i < localeList.size(); i++) { - ULocale uloc = (ULocale)localeList.get(i); - - String language = uloc.getLanguage(); - String script = uloc.getScript(); - String country = uloc.getCountry(); - String variant = uloc.getVariant(); - - boolean bInserted = false; - for (int j = 0; j < fallbacks.size(); j++) { - // Check if this locale is more specific - // than existing locale entries already inserted - // in the destination list - ULocale u = (ULocale)fallbacks.get(j); - if (!u.getLanguage().equals(language)) { - continue; - } - String s = u.getScript(); - String c = u.getCountry(); - String v = u.getVariant(); - if (!s.equals(script)) { - if (s.length() == 0 && c.length() == 0 && v.length() == 0) { - fallbacks.add(j, uloc); - bInserted = true; - break; - } else if (s.length() == 0 && c.equals(country)) { - // We want to see zh_Hant_HK before zh_HK - fallbacks.add(j, uloc); - bInserted = true; - break; - } else if (script.length() == 0 && country.length() > 0 && c.length() == 0) { - // We want to see zh_HK before zh_Hant - fallbacks.add(j, uloc); - bInserted = true; - break; - } - continue; - } - if (!c.equals(country)) { - if (c.length() == 0 && v.length() == 0) { - fallbacks.add(j, uloc); - bInserted = true; - break; - } - } - if (!v.equals(variant) && v.length() == 0) { - fallbacks.add(j, uloc); - bInserted = true; - break; - } - } - if (!bInserted) { - // Add this locale at the end of the list - fallbacks.add(uloc); - } - } - - // TODO: Locale aliases should be resolved here - // For example, zh_Hant_TW = zh_TW - - /* - * Step 2: Append fallback locales for each entry - * - * Example: - * Before - en_US_Boston, en_US, fr_FR, zh_TW, zh_Hant, zh, fr_CA - * After - en_US_Boston, en_US, en, en_US, en, fr_FR, fr, - * zh_TW, zn, zh_Hant, zh, zh, fr_CA, fr - */ - int index = 0; - while (index < fallbacks.size()) { - ULocale uloc = (ULocale)fallbacks.get(index); - while (true) { - uloc = uloc.getFallback(); - if (uloc.getLanguage().length() == 0) { - break; - } - index++; - fallbacks.add(index, uloc); - } - index++; - } - - /* - * Step 3: Remove earlier occurence of duplicated locales - * - * Example: - * Before - en_US_Boston, en_US, en, en_US, en, fr_FR, fr, - * zh_TW, zn, zh_Hant, zh, zh, fr_CA, fr - * After - en_US_Boston, en_US, en, fr_FR, zh_TW, zh_Hant, - * zh, fr_CA, fr - */ - index = 0; - while (index < fallbacks.size() - 1) { - ULocale uloc = (ULocale)fallbacks.get(index); - boolean bRemoved = false; - for (int i = index + 1; i < fallbacks.size(); i++) { - if (uloc.equals((ULocale)fallbacks.get(i))) { - // Remove ealier one - fallbacks.remove(index); - bRemoved = true; - break; - } - } - if (!bRemoved) { - index++; - } - } - return fallbacks; - } - /** * Convenience function to get a ResourceBundle instance using * the specified base name based on the language/locale priority list @@ -449,7 +315,7 @@ public class GlobalizationPreferences implements Freezable { public ResourceBundle getResourceBundle(String baseName) { return getResourceBundle(baseName, null); } - + /** * Convenience function to get a ResourceBundle instance using * the specified base name and class loader based on the language/locale @@ -467,7 +333,7 @@ public class GlobalizationPreferences implements Freezable { UResourceBundle urb = null; UResourceBundle candidate = null; String actualLocaleName = null; - List fallbacks = getFallbackLocales(); + List fallbacks = getLocales(); for (int i = 0; i < fallbacks.size(); i++) { String localeName = ((ULocale)fallbacks.get(i)).toString(); if (actualLocaleName != null && localeName.equals(actualLocaleName)) { @@ -512,6 +378,7 @@ public class GlobalizationPreferences implements Freezable { * currency and timezone values will be set from this. The user * should be given the opportunity to correct those defaults in * case they are incorrect. + * * @param territory code * @return this, for chaining * @internal @@ -521,13 +388,14 @@ public class GlobalizationPreferences implements Freezable { if (isFrozen()) { throw new UnsupportedOperationException("Attempt to modify immutable object"); } - this.territory = territory; + this.territory = territory; // immutable, so don't need to clone return this; } /** * Gets the territory setting. If it wasn't explicitly set, it is * computed from the general locale setting. + * * @return territory code, explicit or implicit. * @internal * @deprecated This API is ICU internal only. @@ -541,6 +409,7 @@ public class GlobalizationPreferences implements Freezable { /** * Sets the currency code. If this has not been set, uses default for territory. + * * @param currency Valid ISO 4217 currency code. * @return this, for chaining * @internal @@ -550,12 +419,13 @@ public class GlobalizationPreferences implements Freezable { if (isFrozen()) { throw new UnsupportedOperationException("Attempt to modify immutable object"); } - this.currency = currency; + this.currency = currency; // immutable, so don't need to clone return this; } /** - * Get a copy of the currency computed according to the settings. + * Get a copy of the currency computed according to the settings. + * * @return currency code, explicit or implicit. * @internal * @deprecated This API is ICU internal only. @@ -569,6 +439,7 @@ public class GlobalizationPreferences implements Freezable { /** * Sets the calendar. If this has not been set, uses default for territory. + * * @param calendar arbitrary calendar * @return this, for chaining * @internal @@ -584,6 +455,7 @@ public class GlobalizationPreferences implements Freezable { /** * Get a copy of the calendar according to the settings. + * * @return calendar explicit or implicit. * @internal * @deprecated This API is ICU internal only. @@ -599,6 +471,7 @@ public class GlobalizationPreferences implements Freezable { /** * Sets the timezone ID. If this has not been set, uses default for territory. + * * @param timezone a valid TZID (see UTS#35). * @return this, for chaining * @internal @@ -615,6 +488,7 @@ public class GlobalizationPreferences implements Freezable { /** * Get the timezone. It was either explicitly set, or is * heuristically computed from other settings. + * * @return timezone, either implicitly or explicitly set * @internal * @deprecated This API is ICU internal only. @@ -628,6 +502,7 @@ public class GlobalizationPreferences implements Freezable { /** * Get a copy of the collator according to the settings. + * * @return collator explicit or implicit. * @internal * @deprecated This API is ICU internal only. @@ -639,7 +514,7 @@ public class GlobalizationPreferences implements Freezable { try { return (Collator) collator.clone(); // clone for safety } catch (CloneNotSupportedException e) { - throw new IllegalStateException("Error in cloning collator"); + throw new IllegalStateException("Error in cloning collator"); } } @@ -655,7 +530,7 @@ public class GlobalizationPreferences implements Freezable { throw new UnsupportedOperationException("Attempt to modify immutable object"); } try { - this.collator = (Collator) collator.clone(); + this.collator = (Collator) collator.clone(); // clone for safety } catch (CloneNotSupportedException e) { throw new IllegalStateException("Error in cloning collator"); } @@ -667,10 +542,13 @@ public class GlobalizationPreferences implements Freezable { * settings. * * @param type - * break type - CHARACTER or TITLE, WORD, LINE, SENTENC + * break type - BI_CHARACTER or BI_WORD, BI_LINE, BI_SENTENCE, BI_TITLE * @return break iterator explicit or implicit */ public BreakIterator getBreakIterator(int type) { + if (type < BI_CHARACTER || type >= BI_LIMIT) { + throw new IllegalArgumentException("Illegal break iterator type"); + } if (breakIterators == null || breakIterators[type] == null) { return guessBreakIterator(type); } @@ -681,11 +559,14 @@ public class GlobalizationPreferences implements Freezable { * Explicitly set the break iterator for this object. * * @param type - * break type - CHARACTER or TITLE, WORD, LINE, SENTENC + * break type - BI_CHARACTER or BI_WORD, BI_LINE, BI_SENTENCE, BI_TITLE * @param iterator a break iterator * @return */ public GlobalizationPreferences setBreakIterator(int type, BreakIterator iterator) { + if (type < BI_CHARACTER || type >= BI_LIMIT) { + throw new IllegalArgumentException("Illegal break iterator type"); + } if (isFrozen()) { throw new UnsupportedOperationException("Attempt to modify immutable object"); } @@ -695,60 +576,12 @@ public class GlobalizationPreferences implements Freezable { return this; } - - /** - * Set the date locale. - * @param dateLocale If not null, overrides the locale priority list for all the date formats. - * @return this, for chaining - */ - public GlobalizationPreferences setDateLocale(ULocale dateLocale) { - if (isFrozen()) { - throw new UnsupportedOperationException("Attempt to modify immutable object"); - } - this.dateLocale = dateLocale; - return this; - } - - /** - * Gets the date locale, to be used in computing date formats. Overrides the general locale setting. - * @return date locale. Null if none was set explicitly. - * @internal - * @deprecated This API is ICU internal only. - */ - public ULocale getDateLocale() { - return dateLocale != null ? dateLocale : getLocale(0); - } - - /** - * Set the number locale. - * @param numberLocale If not null, overrides the locale priority list for all the date formats. - * @return this, for chaining - * @internal - * @deprecated This API is ICU internal only. - */ - public GlobalizationPreferences setNumberLocale(ULocale numberLocale) { - if (isFrozen()) { - throw new UnsupportedOperationException("Attempt to modify immutable object"); - } - this.numberLocale = numberLocale; - return this; - } - - /** - * Get the current number locale setting used for getNumberFormat. - * @return number locale. Null if none was set explicitly. - * @internal - * @deprecated This API is ICU internal only. - */ - public ULocale getNumberLocale() { - return numberLocale != null ? numberLocale : getLocale(0); - } - /** * Get the display name for an ID: language, script, territory, currency, timezone... * Uses the language priority list to do so. + * * @param id language code, script code, ... - * @param type specifies the type of the ID: LANGUAGE, etc. + * @param type specifies the type of the ID: ID_LANGUAGE, etc. * @return the display name * @internal * @deprecated This API is ICU internal only. @@ -757,6 +590,9 @@ public class GlobalizationPreferences implements Freezable { String result = id; for (Iterator it = getLocales().iterator(); it.hasNext();) { ULocale locale = (ULocale) it.next(); + if (!isAvailableLocale(locale, TYPE_GENERIC)) { + continue; + } switch (type) { case ID_LOCALE: result = ULocale.getDisplayName(id, locale); @@ -782,7 +618,9 @@ public class GlobalizationPreferences implements Freezable { Utility.split(id,'=',parts); result = ULocale.getDisplayKeywordValue("und@"+id, parts[0], locale); // TODO fix to tell when successful - if (result.equals(parts[1])) continue; + if (result.equals(parts[1])) { + continue; + } break; case ID_CURRENCY_SYMBOL: case ID_CURRENCY: @@ -811,9 +649,12 @@ public class GlobalizationPreferences implements Freezable { default: throw new IllegalArgumentException("Unknown type: " + type); } - if (!id.equals(result)) return result; + // TODO need better way of seeing if we fell back to root!! // This will not work at all for lots of stuff + if (!id.equals(result)) { + return result; + } } return result; } @@ -824,13 +665,14 @@ public class GlobalizationPreferences implements Freezable { /** - * Set an explicit date format. Overrides both the date locale, - * and the locale priority list for a particular combination of - * dateStyle and timeStyle. NONE should be used if for the style, - * where only the date or time format individually is being set. - * @param dateStyle NONE, or DateFormat.FULL, LONG, MEDIUM, SHORT - * @param timeStyle NONE, or DateFormat.FULL, LONG, MEDIUM, SHORT - * @param format + * Set an explicit date format. Overrides the locale priority list for + * a particular combination of dateStyle and timeStyle. DF_NONE should + * be used if for the style, where only the date or time format individually + * is being set. + * + * @param dateStyle DF_FULL, DF_LONG, DF_MEDIUM, DF_SHORT or DF_NONE + * @param timeStyle DF_FULL, DF_LONG, DF_MEDIUM, DF_SHORT or DF_NONE + * @param format The date format * @return this, for chaining * @internal * @deprecated This API is ICU internal only. @@ -840,171 +682,94 @@ public class GlobalizationPreferences implements Freezable { throw new UnsupportedOperationException("Attempt to modify immutable object"); } if (dateFormats == null) { - dateFormats = new Object[DF_LIMIT][DF_LIMIT]; + dateFormats = new DateFormat[DF_LIMIT][DF_LIMIT]; } dateFormats[dateStyle][timeStyle] = (DateFormat) format.clone(); // for safety return this; } - /** - * Set an explicit date format. Overrides both the date locale, - * and the locale priority list for a particular combination of - * dateStyle and timeStyle. NONE should be used if for the style, - * where only the date or time format individually is being set. - * @param dateStyle NONE, or DateFormat.FULL, LONG, MEDIUM, SHORT - * @param timeStyle NONE, or DateFormat.FULL, LONG, MEDIUM, SHORT - * @param formatPattern date pattern, eg "yyyy-MMM-dd" - * @return this, for chaining - * @internal - * @deprecated This API is ICU internal only. - */ - public GlobalizationPreferences setDateFormat(int dateStyle, int timeStyle, String formatPattern) { - if (isFrozen()) { - throw new UnsupportedOperationException("Attempt to modify immutable object"); - } - if (dateFormats == null) { - dateFormats = new Object[DF_LIMIT][DF_LIMIT]; - } - // test the format to make sure it won't throw an error later - new SimpleDateFormat(formatPattern, getDateLocale()); - dateFormats[dateStyle][timeStyle] = formatPattern; // for safety - return this; - } - /** * Gets a date format according to the current settings. If there * is an explicit (non-null) date/time format set, a copy of that - * is returned. Otherwise, if there is a non-null date locale, - * that is used. Otherwise, the language priority list is - * used. NONE should be used for the style, where only the date or + * is returned. Otherwise, the language priority list is used. + * DF_NONE should be used for the style, where only the date or * time format individually is being gotten. - * @param dateStyle NONE, or DateFormat.FULL, LONG, MEDIUM, SHORT - * @param timeStyle NONE, or DateFormat.FULL, LONG, MEDIUM, SHORT + * + * @param dateStyle DF_FULL, DF_LONG, DF_MEDIUM, DF_SHORT or DF_NONE + * @param timeStyle DF_FULL, DF_LONG, DF_MEDIUM, DF_SHORT or DF_NONE * @return a DateFormat, according to the above description * @internal * @deprecated This API is ICU internal only. */ public DateFormat getDateFormat(int dateStyle, int timeStyle) { - try { - DateFormat result = null; - if (dateFormats != null) { // and override can either be a string or a pattern - Object temp = dateFormats[dateStyle][timeStyle]; - if (temp instanceof DateFormat) { - result = (DateFormat) temp; - } else { - result = new SimpleDateFormat((String)temp, getDateLocale()); - } - } - if (result != null) { - result = (DateFormat) result.clone(); // clone for safety - result.setCalendar(getCalendar()); - } else { - // In the case of date formats, we don't have to look at more than one - // locale. May be different for other cases - // TODO Make this one function. - if (timeStyle == DF_NONE) { - result = DateFormat.getDateInstance(getCalendar(), dateStyle, getDateLocale()); - } else if (dateStyle == DF_NONE) { - result = DateFormat.getTimeInstance(getCalendar(), timeStyle, getDateLocale()); - } else { - result = DateFormat.getDateTimeInstance(getCalendar(), dateStyle, timeStyle, getDateLocale()); - } - } - return result; - } catch (RuntimeException e) { - IllegalArgumentException ex = new IllegalArgumentException("Cannot create DateFormat"); -//#ifndef FOUNDATION - ex.initCause(e); -//#endif - throw ex; + if (dateStyle == DF_NONE && timeStyle == DF_NONE + || dateStyle < 0 || dateStyle >= DF_LIMIT + || timeStyle < 0 || timeStyle >= DF_LIMIT) { + throw new IllegalArgumentException("Illegal date format style arguments"); } + DateFormat result = null; + if (dateFormats != null) { + result = dateFormats[dateStyle][timeStyle]; + } + if (result != null) { + result = (DateFormat) result.clone(); // clone for safety + // Not sure overriding configuration is what we really want... + result.setTimeZone(getTimeZone()); + } else { + result = guessDateFormat(dateStyle, timeStyle); + } + return result; } - + /** * Gets a number format according to the current settings. If * there is an explicit (non-null) number format set, a copy of - * that is returned. Otherwise, if there is a non-null number - * locale, that is used. Otherwise, the language priority list is - * used. NONE should be used for the style, where only the date or - * time format individually is being gotten. - * @param style CURRENCY, NUMBER, INTEGER, SCIENTIFIC, PERCENT + * that is returned. Otherwise, the language priority list is + * used. + * + * @param style NF_NUMBER, NF_CURRENCY, NF_PERCENT, NF_SCIENTIFIC, NF_INTEGER * @internal * @deprecated This API is ICU internal only. */ public NumberFormat getNumberFormat(int style) { - try { - NumberFormat result = null; - if (numberFormats != null) { - Object temp = numberFormats[style]; - if (temp instanceof NumberFormat) { - result = (NumberFormat) temp; - } else { - result = new DecimalFormat((String)temp, new DecimalFormatSymbols(getDateLocale())); - } - } - if (result != null) { - result = (NumberFormat) result.clone(); // clone for safety (later optimize) - if (style == NF_CURRENCY) { - result.setCurrency(getCurrency()); - } - return result; - } - // In the case of date formats, we don't have to look at more than one - // locale. May be different for other cases - switch (style) { - case NF_NUMBER: return NumberFormat.getInstance(getNumberLocale()); - case NF_SCIENTIFIC: return NumberFormat.getScientificInstance(getNumberLocale()); - case NF_INTEGER: return NumberFormat.getIntegerInstance(getNumberLocale()); - case NF_PERCENT: return NumberFormat.getPercentInstance(getNumberLocale()); - case NF_CURRENCY: result = NumberFormat.getCurrencyInstance(getNumberLocale()); - result.setCurrency(getCurrency()); - return result; - } - } catch (RuntimeException e) {} - throw new IllegalArgumentException(); // fix later + if (style < 0 || style >= NF_LIMIT) { + throw new IllegalArgumentException("Illegal number format type"); + } + NumberFormat result = null; + if (numberFormats != null) { + result = numberFormats[style]; + } + if (result != null) { + result = (NumberFormat) result.clone(); // clone for safety (later optimize) + } else { + result = guessNumberFormat(style); + } + return result; } - + /** - * Sets a number format explicitly. Overrides the number locale - * and the general locale settings. - * @param style CURRENCY, NUMBER, INTEGER, SCIENTIFIC, PERCENT + * Sets a number format explicitly. Overrides the general locale settings. + * + * @param style NF_NUMBER, NF_CURRENCY, NF_PERCENT, NF_SCIENTIFIC, NF_INTEGER + * @param format The number format * @return this, for chaining * @internal * @deprecated This API is ICU internal only. */ - public GlobalizationPreferences setNumberFormat(int style, DateFormat format) { + public GlobalizationPreferences setNumberFormat(int style, NumberFormat format) { if (isFrozen()) { throw new UnsupportedOperationException("Attempt to modify immutable object"); } if (numberFormats == null) { - numberFormats = new Object[NF_LIMIT]; + numberFormats = new NumberFormat[NF_LIMIT]; } numberFormats[style] = (NumberFormat) format.clone(); // for safety return this; } - - /** - * Sets a number format explicitly. Overrides the number locale - * and the general locale settings. - * @return this, for chaining - * @internal - * @deprecated This API is ICU internal only. - */ - public GlobalizationPreferences setNumberFormat(int style, String formatPattern) { - if (isFrozen()) { - throw new UnsupportedOperationException("Attempt to modify immutable object"); - } - if (numberFormats == null) { - numberFormats = new Object[NF_LIMIT]; - } - // check to make sure it compiles - new DecimalFormat((String)formatPattern, new DecimalFormatSymbols(getDateLocale())); - numberFormats[style] = formatPattern; // for safety - return this; - } /** * Restore the object to the initial state. + * * @return this, for chaining * @internal * @deprecated This API is ICU internal only. @@ -1013,6 +778,7 @@ public class GlobalizationPreferences implements Freezable { if (isFrozen()) { throw new UnsupportedOperationException("Attempt to modify immutable object"); } + locales = null; territory = null; calendar = null; collator = null; @@ -1021,14 +787,236 @@ public class GlobalizationPreferences implements Freezable { currency = null; dateFormats = null; numberFormats = null; - dateLocale = null; - numberLocale = null; - locales = null; + implicitLocales = null; return this; } + + /** + * Process a language/locale priority list specified via setLocales. + * The input locale list may be expanded or re-ordered to represent the prioritized + * language/locale order actually used by this object by the algorithm exaplained + * below. + *
+ *
+ * Step 1: Move later occurence of more specific locale before ealier occurence of less + * specific locale. + *
+ * Before: en, fr_FR, en_US, en_GB + *
+ * After: en_US, en_GB, en, fr_FR + *
+ *
+ * Step 2: Append a fallback locale to each locale. + *
+ * Before: en_US, en_GB, en, fr_FR + *
+ * After: en_US, en, en_GB, en, en, fr_FR, fr + *
+ *
+ * Step 3: Remove ealier occurence of duplicated locale entries. + *
+ * Before: en_US, en, en_GB, en, en, fr_FR, fr + *
+ * After: en_US, en_GB, en, fr_FR, fr + *
+ *
+ * The final locale list is used to produce a default value for the appropriate territory, + * currency, timezone, etc. The list also represents the lookup order used in + * getResourceBundle for this object. A subclass may override this method + * to customize the algorithm used for populating the locale list. + * + * @param localeList The list of input locales + * @internal + * @deprecated This API is ICU internal only. + */ + protected List processLocales(List inputLocales) { + List result = new ArrayList(); + /* + * Step 1: Relocate later occurence of more specific locale + * before earlier occurence of less specific locale. + * + * Example: + * Before - en_US, fr_FR, zh, en_US_Boston, zh_TW, zh_Hant, fr_CA + * After - en_US_Boston, en_US, fr_FR, zh_TW, zh_Hant, zh, fr_CA + */ + for (int i = 0; i < inputLocales.size(); i++) { + ULocale uloc = (ULocale)inputLocales.get(i); + + String language = uloc.getLanguage(); + String script = uloc.getScript(); + String country = uloc.getCountry(); + String variant = uloc.getVariant(); + + boolean bInserted = false; + for (int j = 0; j < result.size(); j++) { + // Check if this locale is more specific + // than existing locale entries already inserted + // in the destination list + ULocale u = (ULocale)result.get(j); + if (!u.getLanguage().equals(language)) { + continue; + } + String s = u.getScript(); + String c = u.getCountry(); + String v = u.getVariant(); + if (!s.equals(script)) { + if (s.length() == 0 && c.length() == 0 && v.length() == 0) { + result.add(j, uloc); + bInserted = true; + break; + } else if (s.length() == 0 && c.equals(country)) { + // We want to see zh_Hant_HK before zh_HK + result.add(j, uloc); + bInserted = true; + break; + } else if (script.length() == 0 && country.length() > 0 && c.length() == 0) { + // We want to see zh_HK before zh_Hant + result.add(j, uloc); + bInserted = true; + break; + } + continue; + } + if (!c.equals(country)) { + if (c.length() == 0 && v.length() == 0) { + result.add(j, uloc); + bInserted = true; + break; + } + } + if (!v.equals(variant) && v.length() == 0) { + result.add(j, uloc); + bInserted = true; + break; + } + } + if (!bInserted) { + // Add this locale at the end of the list + result.add(uloc); + } + } + + // TODO: Locale aliases might be resolved here + // For example, zh_Hant_TW = zh_TW + + /* + * Step 2: Append fallback locales for each entry + * + * Example: + * Before - en_US_Boston, en_US, fr_FR, zh_TW, zh_Hant, zh, fr_CA + * After - en_US_Boston, en_US, en, en_US, en, fr_FR, fr, + * zh_TW, zn, zh_Hant, zh, zh, fr_CA, fr + */ + int index = 0; + while (index < result.size()) { + ULocale uloc = (ULocale)result.get(index); + while (true) { + uloc = uloc.getFallback(); + if (uloc.getLanguage().length() == 0) { + break; + } + index++; + result.add(index, uloc); + } + index++; + } + + /* + * Step 3: Remove earlier occurence of duplicated locales + * + * Example: + * Before - en_US_Boston, en_US, en, en_US, en, fr_FR, fr, + * zh_TW, zn, zh_Hant, zh, zh, fr_CA, fr + * After - en_US_Boston, en_US, en, fr_FR, zh_TW, zh_Hant, + * zh, fr_CA, fr + */ + index = 0; + while (index < result.size() - 1) { + ULocale uloc = (ULocale)result.get(index); + boolean bRemoved = false; + for (int i = index + 1; i < result.size(); i++) { + if (uloc.equals((ULocale)result.get(i))) { + // Remove ealier one + result.remove(index); + bRemoved = true; + break; + } + } + if (!bRemoved) { + index++; + } + } + return result; + } + /** * This function can be overridden by subclasses to use different heuristics. + * It MUST return a 'safe' value, + * one whose modification will not affect this object. + * + * @param dateStyle + * @param timeStyle + * @internal + * @deprecated This API is ICU internal only. + */ + protected DateFormat guessDateFormat(int dateStyle, int timeStyle) { + DateFormat result; + ULocale dfLocale = getAvailableLocale(TYPE_DATEFORMAT); + if (dfLocale == null) { + dfLocale = ULocale.ROOT; + } + if (timeStyle == DF_NONE) { + result = DateFormat.getDateInstance(getCalendar(), dateStyle, dfLocale); + } else if (dateStyle == DF_NONE) { + result = DateFormat.getTimeInstance(getCalendar(), timeStyle, dfLocale); + } else { + result = DateFormat.getDateTimeInstance(getCalendar(), dateStyle, timeStyle, dfLocale); + } + return result; + } + + /** + * This function can be overridden by subclasses to use different heuristics. + * It MUST return a 'safe' value, + * one whose modification will not affect this object. + * + * @param style + * @internal + * @deprecated This API is ICU internal only. + */ + protected NumberFormat guessNumberFormat(int style) { + NumberFormat result; + ULocale nfLocale = getAvailableLocale(TYPE_NUMBERFORMAT); + if (nfLocale == null) { + nfLocale = ULocale.ROOT; + } + switch (style) { + case NF_NUMBER: + result = NumberFormat.getInstance(nfLocale); + break; + case NF_SCIENTIFIC: + result = NumberFormat.getScientificInstance(nfLocale); + break; + case NF_INTEGER: + result = NumberFormat.getIntegerInstance(nfLocale); + break; + case NF_PERCENT: + result = NumberFormat.getPercentInstance(nfLocale); + break; + case NF_CURRENCY: + result = NumberFormat.getCurrencyInstance(nfLocale); + result.setCurrency(getCurrency()); + break; + default: + throw new IllegalArgumentException("Unknown number format style"); + } + return result; + } + + /** + * This function can be overridden by subclasses to use different heuristics. + * * @internal * @deprecated This API is ICU internal only. */ @@ -1064,6 +1052,7 @@ public class GlobalizationPreferences implements Freezable { /** * This function can be overridden by subclasses to use different heuristics + * * @internal * @deprecated This API is ICU internal only. */ @@ -1075,43 +1064,65 @@ public class GlobalizationPreferences implements Freezable { * This function can be overridden by subclasses to use different heuristics * It MUST return a 'safe' value, * one whose modification will not affect this object. + * * @internal * @deprecated This API is ICU internal only. */ protected List guessLocales() { - List result = new ArrayList(0); - result.add(ULocale.getDefault()); - return result; + if (implicitLocales == null) { + List result = new ArrayList(1); + result.add(ULocale.getDefault()); + implicitLocales = processLocales(result); + } + return implicitLocales; } /** * This function can be overridden by subclasses to use different heuristics. * It MUST return a 'safe' value, * one whose modification will not affect this object. + * * @internal * @deprecated This API is ICU internal only. */ protected Collator guessCollator() { - return Collator.getInstance(getLocale(0)); + ULocale collLocale = getAvailableLocale(TYPE_COLLATOR); + if (collLocale == null) { + collLocale = ULocale.ROOT; + } + return Collator.getInstance(collLocale); } + /** + * This function can be overridden by subclasses to use different heuristics. + * It MUST return a 'safe' value, + * one whose modification will not affect this object. + * + * @param type + * @internal + * @deprecated This API is ICU internal only. + */ protected BreakIterator guessBreakIterator(int type) { BreakIterator bitr = null; + ULocale brkLocale = getAvailableLocale(TYPE_BREAKITERATOR); + if (brkLocale == null) { + brkLocale = ULocale.ROOT; + } switch (type) { case BI_CHARACTER: - bitr = BreakIterator.getCharacterInstance(getLocale(0)); + bitr = BreakIterator.getCharacterInstance(brkLocale); break; case BI_TITLE: - bitr = BreakIterator.getTitleInstance(getLocale(0)); + bitr = BreakIterator.getTitleInstance(brkLocale); break; case BI_WORD: - bitr = BreakIterator.getWordInstance(getLocale(0)); + bitr = BreakIterator.getWordInstance(brkLocale); break; case BI_LINE: - bitr = BreakIterator.getLineInstance(getLocale(0)); + bitr = BreakIterator.getLineInstance(brkLocale); break; case BI_SENTENCE: - bitr = BreakIterator.getSentenceInstance(getLocale(0)); + bitr = BreakIterator.getSentenceInstance(brkLocale); break; default: throw new IllegalArgumentException("Unknown break iterator type"); @@ -1123,6 +1134,7 @@ public class GlobalizationPreferences implements Freezable { * This function can be overridden by subclasses to use different heuristics. * It MUST return a 'safe' value, * one whose modification will not affect this object. + * * @internal * @deprecated This API is ICU internal only. */ @@ -1156,33 +1168,126 @@ public class GlobalizationPreferences implements Freezable { * This function can be overridden by subclasses to use different heuristics. * It MUST return a 'safe' value, * one whose modification will not affect this object. + * * @internal * @deprecated This API is ICU internal only. */ protected Calendar guessCalendar() { - // TODO add better API - return Calendar.getInstance(new ULocale("und-" + getTerritory())); + ULocale calLocale = getAvailableLocale(TYPE_CALENDAR); + if (calLocale == null) { + calLocale = ULocale.US; + } + return Calendar.getInstance(getTimeZone(), calLocale); } // PRIVATES - private Object locales; + private List locales; private String territory; private Currency currency; private TimeZone timezone; private Calendar calendar; private Collator collator; private BreakIterator[] breakIterators; - - private ULocale dateLocale; - private Object[][] dateFormats; - private ULocale numberLocale; - private Object[] numberFormats; + private DateFormat[][] dateFormats; + private NumberFormat[] numberFormats; + private List implicitLocales; { reset(); } + + + private ULocale getAvailableLocale(int type) { + List locs = getLocales(); + ULocale result = null; + for (int i = 0; i < locs.size(); i++) { + ULocale l = (ULocale)locs.get(i); + if (isAvailableLocale(l, type)) { + result = l; + break; + } + } + return result; + } + + private boolean isAvailableLocale(ULocale loc, int type) { + BitSet bits = (BitSet)available_locales.get(loc); + if (bits != null && bits.get(type)) { + return true; + } + return false; + } + /* + * Available locales for service types + */ + private static final HashMap available_locales = new HashMap(); + private static final int + TYPE_GENERIC = 0, + TYPE_CALENDAR = 1, + TYPE_DATEFORMAT= 2, + TYPE_NUMBERFORMAT = 3, + TYPE_COLLATOR = 4, + TYPE_BREAKITERATOR = 5, + TYPE_LIMIT = TYPE_BREAKITERATOR + 1; + + static { + BitSet bits; + ULocale[] allLocales = ULocale.getAvailableLocales(); + for (int i = 0; i < allLocales.length; i++) { + bits = new BitSet(TYPE_LIMIT); + available_locales.put(allLocales[i], bits); + bits.set(TYPE_GENERIC); + } + + ULocale[] calLocales = Calendar.getAvailableULocales(); + for (int i = 0; i < calLocales.length; i++) { + bits = (BitSet)available_locales.get(calLocales[i]); + if (bits == null) { + bits = new BitSet(TYPE_LIMIT); + available_locales.put(allLocales[i], bits); + } + bits.set(TYPE_CALENDAR); + } + + ULocale[] dateLocales = DateFormat.getAvailableULocales(); + for (int i = 0; i < dateLocales.length; i++) { + bits = (BitSet)available_locales.get(dateLocales[i]); + if (bits == null) { + bits = new BitSet(TYPE_LIMIT); + available_locales.put(allLocales[i], bits); + } + bits.set(TYPE_DATEFORMAT); + } + + ULocale[] numLocales = NumberFormat.getAvailableULocales(); + for (int i = 0; i < numLocales.length; i++) { + bits = (BitSet)available_locales.get(numLocales[i]); + if (bits == null) { + bits = new BitSet(TYPE_LIMIT); + available_locales.put(allLocales[i], bits); + } + bits.set(TYPE_NUMBERFORMAT); + } + + ULocale[] collLocales = Collator.getAvailableULocales(); + for (int i = 0; i < collLocales.length; i++) { + bits = (BitSet)available_locales.get(collLocales[i]); + if (bits == null) { + bits = new BitSet(TYPE_LIMIT); + available_locales.put(allLocales[i], bits); + } + bits.set(TYPE_COLLATOR); + } + + ULocale[] brkLocales = BreakIterator.getAvailableULocales(); + for (int i = 0; i < brkLocales.length; i++) { + bits = (BitSet)available_locales.get(brkLocales[i]); + bits.set(TYPE_BREAKITERATOR); + } + } + /** WARNING: All of this data is temporary, until we start importing from CLDR!!! * */ @@ -1347,7 +1452,7 @@ public class GlobalizationPreferences implements Freezable { language_territory_hack_map.put(language_territory_hack[i][0],language_territory_hack[i][1]); } } - + static final Map territory_tzid_hack_map = new HashMap(); static final String[][] territory_tzid_hack = { {"AQ", "Antarctica/McMurdo"}, @@ -1387,6 +1492,8 @@ public class GlobalizationPreferences implements Freezable { } } + // Freezable implmentation + private boolean frozen; /**