ICU-6289 Merging another CLDR data update for resolving timezone format problem, Plural format enhancement(#6373) and a fix for Java1.3/Foundation 1.0 environment support in recent DateIntervalFormat change(#6157).

X-SVN-Rev: 24271
diff --git a/src/com/ibm/icu/dev/data/testdata.jar b/src/com/ibm/icu/dev/data/testdata.jar
index ed2ea72..dbab76a 100644
--- a/src/com/ibm/icu/dev/data/testdata.jar
+++ b/src/com/ibm/icu/dev/data/testdata.jar
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:194e372e448817d14bbc5b695cf783a570dafdbcb8cbdcc8658ed9f60ae16d3e
+oid sha256:9b76d1e3bc7e21552bbc2c78b258da2ddd60583f8c8a44735a3faa7957678098
 size 764853
diff --git a/src/com/ibm/icu/dev/test/format/DateIntervalFormatTest.java b/src/com/ibm/icu/dev/test/format/DateIntervalFormatTest.java
index 80db513..a707252 100644
--- a/src/com/ibm/icu/dev/test/format/DateIntervalFormatTest.java
+++ b/src/com/ibm/icu/dev/test/format/DateIntervalFormatTest.java
@@ -24,6 +24,7 @@
 import com.ibm.icu.util.DateInterval;
 import com.ibm.icu.text.DateIntervalInfo;
 import com.ibm.icu.text.DateIntervalFormat;
+import com.ibm.icu.util.ULocale;
 
 public class DateIntervalFormatTest extends com.ibm.icu.dev.test.TestFmwk {
 
@@ -613,7 +614,7 @@
         int i = 1;
         while (i<data_length) {
             String locName = data[i++];
-            Locale loc = new Locale(locName);
+            ULocale loc = new ULocale(locName);
             SimpleDateFormat ref = new SimpleDateFormat(data[0], loc);
             // 'f'
             String datestr = data[i++];
@@ -707,7 +708,7 @@
         int i = 1;
         while (i<data_length) {
             String locName = data[i++];
-            Locale loc = new Locale(locName);
+            ULocale loc = new ULocale(locName);
             SimpleDateFormat ref = new SimpleDateFormat(data[0], loc);
             // 'f'
             String datestr = data[i++];
@@ -782,7 +783,7 @@
         int i = 1;
         while (i<data_length) {
             String locName = data[i++];
-            Locale loc = new Locale(locName);
+            ULocale loc = new ULocale(locName);
             SimpleDateFormat ref = new SimpleDateFormat(data[0], loc);
             // 'f'
             String datestr = data[i++];
diff --git a/src/com/ibm/icu/dev/test/format/PluralFormatTest.java b/src/com/ibm/icu/dev/test/format/PluralFormatTest.java
index a382e12..5a141a9 100644
--- a/src/com/ibm/icu/dev/test/format/PluralFormatTest.java
+++ b/src/com/ibm/icu/dev/test/format/PluralFormatTest.java
@@ -1,6 +1,6 @@
 /*
  *******************************************************************************
- * Copyright (C) 2007, International Business Machines Corporation and         *
+ * Copyright (C) 2007-2008, International Business Machines Corporation and    *
  * others. All Rights Reserved.                                                *
  *******************************************************************************
  */
@@ -48,15 +48,19 @@
     */
     log("test pattern: '" + testPattern + "'");
     for (int i = 0; i < locales.length; ++i) {
-      PluralFormat plf = new PluralFormat(new ULocale(locales[i]), testPattern);
-      log("plf: " + plf);
-      String expected = (String) changes.get(new Integer(0));
-      for (int n = 0; n < 200; ++n) {
-        if (changes.get(new Integer(n)) != null) {
-          expected = (String) changes.get(new Integer(n));
+      try {
+        PluralFormat plf = new PluralFormat(new ULocale(locales[i]), testPattern);
+        log("plf: " + plf);
+        String expected = (String) changes.get(new Integer(0));
+        for (int n = 0; n < 200; ++n) {
+          if (changes.get(new Integer(n)) != null) {
+            expected = (String) changes.get(new Integer(n));
+          }
+          assertEquals("Locale: " + locales[i] + ", number: " + n,
+                       expected, plf.format(n));
         }
-        assertEquals("Locale: " + locales[i] + ", number: " + n,
-                     expected, plf.format(n));
+      } catch (IllegalArgumentException e) {
+        errln(e.getMessage() + " locale: " + locales[i] + " pattern: '" + testPattern + "' " + System.currentTimeMillis());
       }
     }
   }
@@ -70,7 +74,7 @@
   }
   
   public void TestSingular1Locales() {
-    String localeIDs = "da,de,el,en,eo,es,et,fi,fo,he,hu,it,nb,nl,nn,no,pt,sv";
+    String localeIDs = "da,de,el,en,eo,es,et,fi,fo,he,it,nb,nl,nn,no,pt_PT,sv";
     String testPattern = "one{one} other{other}";
     Map changes = new HashMap();
     changes.put(new Integer(0), "other");
@@ -118,13 +122,13 @@
   
   public void TestSingularZeroSome() {
       String localeIDs = "ro";
-      String testPattern = "zero{zero} one{one} other{other}";
+      String testPattern = "few{few} one{one} other{other}";
       Map changes = new HashMap();
-      changes.put(new Integer(0), "zero");
+      changes.put(new Integer(0), "few");
       changes.put(new Integer(1), "one");
-      changes.put(new Integer(2), "zero");
+      changes.put(new Integer(2), "few");
       changes.put(new Integer(20), "other");
-      changes.put(new Integer(101), "zero");
+      changes.put(new Integer(101), "few");
       changes.put(new Integer(120), "other");
       helperTestRules(localeIDs, testPattern, changes);
   }
@@ -187,7 +191,7 @@
       changes.put(new Integer(2), "few");
       changes.put(new Integer(5), "other");
       for (int i = 2; i < 20; ++i) {
-        if (i == 11) {
+        if (i == 2 || i == 11 || i == 12) {
           continue;
         }
         changes.put(new Integer(i*10 + 2), "few");
diff --git a/src/com/ibm/icu/dev/test/format/PluralRulesTest.java b/src/com/ibm/icu/dev/test/format/PluralRulesTest.java
index 55b87f7..83d8876 100644
--- a/src/com/ibm/icu/dev/test/format/PluralRulesTest.java
+++ b/src/com/ibm/icu/dev/test/format/PluralRulesTest.java
@@ -9,6 +9,7 @@
 import com.ibm.icu.dev.test.TestFmwk;
 import com.ibm.icu.impl.Utility;
 import com.ibm.icu.text.PluralRules;
+import com.ibm.icu.util.ULocale;
 
 import java.text.ParseException;
 import java.util.ArrayList;
@@ -131,4 +132,22 @@
             compareEquality(rules);
         }
     }
+
+    public void testBuiltInRules() {
+        // spot check
+        PluralRules rules = PluralRules.forLocale(ULocale.US);
+        assertEquals("us 0", PluralRules.KEYWORD_OTHER, rules.select(0));
+        assertEquals("us 1", PluralRules.KEYWORD_ONE, rules.select(1));
+        assertEquals("us 2", PluralRules.KEYWORD_OTHER, rules.select(2));
+
+        rules = PluralRules.forLocale(ULocale.JAPAN);
+        assertEquals("ja 0", PluralRules.KEYWORD_OTHER, rules.select(0));
+        assertEquals("ja 1", PluralRules.KEYWORD_OTHER, rules.select(1));
+        assertEquals("ja 2", PluralRules.KEYWORD_OTHER, rules.select(2));
+
+        rules = PluralRules.forLocale(ULocale.createCanonical("ru"));
+        assertEquals("ru 0", PluralRules.KEYWORD_MANY, rules.select(0));
+        assertEquals("ru 1", PluralRules.KEYWORD_ONE, rules.select(1));
+        assertEquals("ru 2", PluralRules.KEYWORD_FEW, rules.select(2));
+    }
 }
diff --git a/src/com/ibm/icu/impl/PluralRulesLoader.java b/src/com/ibm/icu/impl/PluralRulesLoader.java
new file mode 100644
index 0000000..79770d1
--- /dev/null
+++ b/src/com/ibm/icu/impl/PluralRulesLoader.java
@@ -0,0 +1,158 @@
+/*
+ *******************************************************************************
+ * Copyright (C) 2008, International Business Machines Corporation and         *
+ * others. All Rights Reserved.                                                *
+ *******************************************************************************
+ */
+package com.ibm.icu.impl;
+
+import com.ibm.icu.text.PluralRules;
+import com.ibm.icu.util.ULocale;
+import com.ibm.icu.util.UResourceBundle;
+
+import java.text.ParseException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.MissingResourceException;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * Loader for plural rules data.
+ */
+public class PluralRulesLoader {
+  private final Map rulesIdToRules;
+  private Map localeIdToRulesId; // lazy init, use getLocaleIdToRulesIdMap to access
+
+  /**
+   * Access through singleton.
+   */
+  private PluralRulesLoader() {
+    rulesIdToRules = new HashMap();
+  }
+
+  /**
+   * Returns the locales for which we have plurals data.
+   * Utility for testing.
+   */
+  public ULocale[] getAvailableULocales() {
+    Set keys = getLocaleIdToRulesIdMap().keySet();
+    ULocale[] locales = new ULocale[keys.size()];
+    int n = 0;
+    for (Iterator iter = keys.iterator(); iter.hasNext();) {
+      locales[n++] = ULocale.createCanonical((String) iter.next());
+    }
+    return locales;
+  }
+
+  /**
+   * Lazily construct the map from localeIds to rulesIds.  This
+   * map exactly reflects the contents of the locales resource
+   * in plurals.res.
+   */
+  private Map getLocaleIdToRulesIdMap() {
+    if (localeIdToRulesId == null) {
+      try {
+        UResourceBundle pluralb = getPluralBundle();
+        UResourceBundle localeb = pluralb.get("locales");
+        localeIdToRulesId = new TreeMap();  // sort for convenience of getAvailableULocales
+        for (int i = 0; i < localeb.getSize(); ++i) {
+          UResourceBundle b = localeb.get(i);
+          String id = b.getKey();
+          String value = b.getString().intern();
+          localeIdToRulesId.put(id, value);
+        }
+      }
+      catch (MissingResourceException e) {
+        localeIdToRulesId = new HashMap(); // dummy so we don't try again
+      }
+    }
+    return localeIdToRulesId;
+  }
+
+  /**
+   * Gets the rulesId from the locale,with locale fallback.  If there is no
+   * rulesId, return null.  The rulesId might be the empty string if the
+   * rule is the default rule.
+   */
+  public String getRulesIdForLocale(ULocale locale) {
+    Map idMap = getLocaleIdToRulesIdMap();
+    String localeId = ULocale.canonicalize(locale.getBaseName());
+    String rulesId = null;
+    while (null == (rulesId = (String) idMap.get(localeId))) {
+      int ix = localeId.lastIndexOf("_");
+      if (ix == -1) {
+        break;
+      }
+      localeId = localeId.substring(0, ix);
+    }
+    return rulesId;
+  }
+
+  /**
+   * Gets the rule from the rulesId.  If there is no rule for this rulesId,
+   * return null.
+   */
+  public PluralRules getRulesForRulesId(String rulesId) {
+    PluralRules rules = (PluralRules) rulesIdToRules.get(rulesId);
+    if (rules == null) {
+      try {
+        UResourceBundle pluralb = getPluralBundle();
+        UResourceBundle rulesb = pluralb.get("rules");
+        UResourceBundle setb = rulesb.get(rulesId);
+
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < setb.getSize(); ++i) {
+          UResourceBundle b = setb.get(i);
+          if (i > 0) {
+            sb.append("; ");
+          }
+          sb.append(b.getKey());
+          sb.append(": ");
+          sb.append(b.getString());
+        }
+        rules = PluralRules.parseDescription(sb.toString());
+      } catch (ParseException e) {
+      } catch (MissingResourceException e) {
+      }
+      rulesIdToRules.put(rulesId, rules); // put even if null
+    }
+    return rules;
+  }
+
+  /**
+   * Return the plurals resource.
+   * Note MissingResourceException is unchecked, listed here for clarity.
+   * Callers should handle this exception.
+   */
+  public UResourceBundle getPluralBundle() throws MissingResourceException {
+      return ICUResourceBundle.getBundleInstance(
+          ICUResourceBundle.ICU_BASE_NAME,
+          "plurals",
+          ICUResourceBundle.ICU_DATA_CLASS_LOADER,
+          true);
+  }
+
+  /**
+   * Returns the plural rules for the the locale.
+   * If we don't have data,
+   * com.ibm.icu.text.PluralRules.DEFAULT is returned.
+   */
+  public PluralRules forLocale(ULocale locale) {
+    String rulesId = getRulesIdForLocale(locale);
+    if (rulesId == null || rulesId.trim().length() == 0) {
+      return PluralRules.DEFAULT;
+    }
+    PluralRules rules = getRulesForRulesId(rulesId);
+    if (rules == null) {
+      rules = PluralRules.DEFAULT;
+    }
+    return rules;
+  }
+
+  /**
+   * The only instance of the loader.
+   */
+  public static final PluralRulesLoader loader = new PluralRulesLoader();
+}
diff --git a/src/com/ibm/icu/impl/data/icudata.jar b/src/com/ibm/icu/impl/data/icudata.jar
index 96707fd..f298122 100755
--- a/src/com/ibm/icu/impl/data/icudata.jar
+++ b/src/com/ibm/icu/impl/data/icudata.jar
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:8948a491d5f863049e5f7a08530406635f1b0fccd5f5913d9db9349c45e21008
-size 6604684
+oid sha256:81f2ec380c532d8fc2d4f808cb1d4fc27c251fc2b742cbaa0c24177fe45c7289
+size 6604691
diff --git a/src/com/ibm/icu/text/PluralRules.java b/src/com/ibm/icu/text/PluralRules.java
index 7b160fd..5b49e1d 100644
--- a/src/com/ibm/icu/text/PluralRules.java
+++ b/src/com/ibm/icu/text/PluralRules.java
@@ -7,17 +7,16 @@
 
 package com.ibm.icu.text;
 
-import com.ibm.icu.util.ULocale;
+import com.ibm.icu.impl.PluralRulesLoader;
 import com.ibm.icu.impl.Utility;
+import com.ibm.icu.util.ULocale;
 
 import java.io.Serializable;
 
 import java.text.ParseException;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
-import java.util.Map;
 import java.util.Set;
 
 /** 
@@ -78,8 +77,6 @@
 public class PluralRules implements Serializable {
     private static final long serialVersionUID = 1;
 
-    private static final Map ruleMap; // from locale string to PluralRules
-
     private final RuleList rules;
     private final Set keywords;
     private int repeatLimit; // for equality test
@@ -276,46 +273,6 @@
         int getRepeatLimit();
     }
 
-    // default data
-    static {
-        String[] ruledata = {
-          "other: n/ja,ko,tr,vi",  // not strictly necessary, default for all
-          "zero: n is 0; one: n is 1; two: n is 2; few: n in 3..10; " +
-          "many: n in 11..99/ar",
-            "one: n is 1/da,de,el,en,eo,es,et,fi,fo,he,hu,it,nb,nl,nn,no,pt,sv",
-            "one: n in 0..1/fr,pt_BR",
-            "zero: n is 0; one: n mod 10 is 1 and n mod 100 is not 11/lv",
-            "one: n is 1; two: n is 2/ga",
-            "zero: n is 0; one: n is 1; zero: n mod 100 in 1..19/ro",
-            "other: n mod 100 in 11..19; one: n mod 10 is 1; " + 
-                "few: n mod 10 in 2..9/lt",
-            "one: n mod 10 is 1 and n mod 100 is not 11; " +
-                "few: n mod 10 in 2..4 " +
-                "and n mod 100 not in 12..14/hr,ru,sr,uk",
-            "one: n is 1; few: n in 2..4/cs,sk",
-            "one: n is 1; few: n mod 10 in 2..4 and n mod 100 not in 12..14/pl",
-            "one: n mod 100 is 1; two: n mod 100 is 2; " +
-                "few: n mod 100 in 3..4/sl",
-        };
-
-        HashMap map = new HashMap();
-        for (int i = 0; i < ruledata.length; ++i) {
-            String[] data = Utility.split(ruledata[i], '/');
-            try {
-              PluralRules pluralRules = parseDescription(data[0]);
-              String[] locales = Utility.split(data[1], ',');
-              for (int j = 0; j < locales.length; ++j) {
-                map.put(locales[j].trim(), pluralRules);
-              }
-            } catch (Exception e) {
-              System.err.println("PluralRules init failure, " + 
-                                 e.getMessage() + " at line " + i);
-            }
-        }
-           
-        ruleMap = map;
-    }
-
     /**
      * syntax:
      * condition :     or_condition
@@ -724,14 +681,7 @@
      * @provisional This API might change or be removed in a future release.
      */
     public static PluralRules forLocale(ULocale locale) {
-        PluralRules result = null;
-        while (null == (result = (PluralRules) ruleMap.get(locale.getName()))) {
-            locale = locale.getFallback();
-            if (locale == null) {
-              return DEFAULT;
-            }
-        }
-        return result;
+      return PluralRulesLoader.loader.forLocale(locale);
     }
 
     /**
@@ -846,4 +796,4 @@
       }
       return repeatLimit;
     }
-}
+ }