]> granicus.if.org Git - icu/commitdiff
ICU-11986 MeasureFormat unit display patterns need to fall back to the parent locales...
authorMarkus Scherer <markus.icu@gmail.com>
Mon, 30 Nov 2015 22:44:04 +0000 (22:44 +0000)
committerMarkus Scherer <markus.icu@gmail.com>
Mon, 30 Nov 2015 22:44:04 +0000 (22:44 +0000)
X-SVN-Rev: 38098

icu4j/main/classes/core/src/com/ibm/icu/text/MeasureFormat.java
icu4j/main/classes/core/src/com/ibm/icu/text/QuantityFormatter.java
icu4j/main/classes/core/src/com/ibm/icu/text/RelativeDateTimeFormatter.java
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/TimeUnitTest.java

index 7e9f0d8d64b19946576054af237b1ee1a4237cbc..28ad541f3b7d6f9ce7328110816183861530c35e 100644 (file)
@@ -746,8 +746,6 @@ public class MeasureFormat extends UFormat {
          * unitsShort/duration/hour contains other{"{0} hrs"}.
          */
         class UnitPatternSink extends UResource.TableSink {
-            QuantityFormatter.Builder builder = new QuantityFormatter.Builder();
-
             @Override
             public void put(UResource.Key key, UResource.Value value) {
                 if (key.contentEquals("dnam")) {
@@ -759,22 +757,22 @@ public class MeasureFormat extends UFormat {
                     // The key must be one of the plural form strings. For example:
                     // one{"{0} hr"}
                     // other{"{0} hrs"}
-                    if (!hasPatterns) {
-                        builder.add(key, value.getString());
-                    }
-                }
-            }
-            @Override
-            public void leave() {
-                if (builder.hasPatterns()) {
+                    QuantityFormatter countToFormat;
                     EnumMap<FormatWidth, QuantityFormatter> styleToCountToFormat =
                             cacheData.unitToStyleToCountToFormat.get(unit);
                     if (styleToCountToFormat == null) {
                         styleToCountToFormat =
                                 new EnumMap<FormatWidth, QuantityFormatter>(FormatWidth.class);
                         cacheData.unitToStyleToCountToFormat.put(unit, styleToCountToFormat);
+                        countToFormat = null;
+                    } else {
+                        countToFormat = styleToCountToFormat.get(width);
+                    }
+                    if (countToFormat == null) {
+                        countToFormat = new QuantityFormatter();
+                        styleToCountToFormat.put(width, countToFormat);
                     }
-                    styleToCountToFormat.put(width, builder.build());
+                    countToFormat.addIfAbsent(key, value);
                 }
             }
         }
@@ -789,9 +787,6 @@ public class MeasureFormat extends UFormat {
             public UResource.TableSink getOrCreateTableSink(UResource.Key key, int initialSize) {
                 // Should we ignore or reject unknown units?
                 unit = MeasureUnit.internalGetInstance(type, key.toString());  // never null
-                Map<FormatWidth, QuantityFormatter> styleToCountToFormat =
-                        cacheData.unitToStyleToCountToFormat.get(unit);
-                hasPatterns = styleToCountToFormat != null && styleToCountToFormat.containsKey(width);
                 return patternSink;
             }
         }
@@ -905,9 +900,6 @@ public class MeasureFormat extends UFormat {
         FormatWidth width;
         String type;
         MeasureUnit unit;
-
-        /** True if we already have plural-form display patterns for width/type/subtype. */
-        boolean hasPatterns;
     }
 
     /**
index 17b9a8288953f5dd69a09a3598660a4f375f0719..b513347cfda15b627f2f57f3c7389bf2d4a14048 100644 (file)
@@ -7,6 +7,7 @@
 package com.ibm.icu.text;
 
 import com.ibm.icu.impl.SimplePatternFormatter;
+import com.ibm.icu.impl.UResource;
 
 /**
  * QuantityFormatter represents an unknown quantity of something and formats a known quantity
@@ -51,79 +52,64 @@ class QuantityFormatter {
     }
     private static final int INDEX_COUNT = 6;
 
+    private final SimplePatternFormatter[] templates = new SimplePatternFormatter[INDEX_COUNT];
+
+    public QuantityFormatter() {}
+
     /**
-     * Builder builds a QuantityFormatter.
-     * 
-     * @author rocketman
+     * Adds a template if there is none yet for the plural form.
+     *
+     * @param variant the plural variant, e.g "zero", "one", "two", "few", "many", "other"
+     * @param template the text for that plural variant with "{0}" as the quantity. For
+     * example, in English, the template for the "one" variant may be "{0} apple" while the
+     * template for the "other" variant may be "{0} apples"
+     * @throws IllegalArgumentException if variant is not recognized or
+     *  if template has more than just the {0} placeholder.
      */
-    static class Builder {
-        private SimplePatternFormatter[] templates;
+    public void addIfAbsent(CharSequence variant, String template) {
+        addIfAbsent(variant, template, null);
+    }
 
-        boolean hasPatterns() {
-            return templates != null;
-        }
+    /**
+     * Adds a template if there is none yet for the plural form.
+     * This version only calls UResource.Value.getString()
+     * if there is no template yet for the plural form.
+     *
+     * @param variant the plural variant, e.g "zero", "one", "two", "few", "many", "other"
+     * @param template the text for that plural variant with "{0}" as the quantity. For
+     * example, in English, the template for the "one" variant may be "{0} apple" while the
+     * template for the "other" variant may be "{0} apples"
+     * @throws IllegalArgumentException if variant is not recognized or
+     *  if template has more than just the {0} placeholder.
+     */
+    public void addIfAbsent(CharSequence variant, UResource.Value template) {
+        addIfAbsent(variant, null, template);
+    }
 
-        /**
-         * Adds a template.
-         * @param variant the plural variant, e.g "zero", "one", "two", "few", "many", "other"
-         * @param template the text for that plural variant with "{0}" as the quantity. For
-         * example, in English, the template for the "one" variant may be "{0} apple" while the
-         * template for the "other" variant may be "{0} apples"
-         * @return a reference to this Builder for chaining.
-         * @throws IllegalArgumentException if variant is not recognized or
-         *  if template has more than just the {0} placeholder.
-         */
-        public Builder add(CharSequence variant, String template) {
-            int idx = getPluralIndex(variant);
-            if (idx < 0) {
-                throw new IllegalArgumentException(variant.toString());
-            }
-            SimplePatternFormatter newT = SimplePatternFormatter.compile(template);
-            if (newT.getPlaceholderCount() > 1) {
-                throw new IllegalArgumentException(
-                        "Extra placeholders: " + template);
-            }
-            // Keep templates == null until we add one.
-            ensureCapacity();
-            templates[idx] = newT;
-            return this;
+    private void addIfAbsent(CharSequence variant, String template, UResource.Value templateValue) {
+        int idx = getPluralIndex(variant);
+        if (idx < 0) {
+            throw new IllegalArgumentException(variant.toString());
         }
-
-        /**
-         * Builds the new QuantityFormatter and resets this Builder to its initial state.
-         * @return the new QuantityFormatter object.
-         * @throws IllegalStateException if no template is specified for the "other" variant.
-         *  When throwing this exception, build leaves this builder in its current state.
-         */
-        public QuantityFormatter build() {
-            if (templates == null || templates[0] == null) {
-                throw new IllegalStateException("At least other variant must be set.");
-            }
-            QuantityFormatter result = new QuantityFormatter(templates);
-            templates = null;
-            return result;          
+        if (templates[idx] != null) {
+            return;
         }
-
-        /**
-         * Resets this builder to its initial state.
-         */
-        public Builder reset() {
-            templates = null;
-            return this;
+        if (template == null) {
+            template = templateValue.getString();
         }
-        
-        private void ensureCapacity() {
-            if (templates == null) {
-                templates = new SimplePatternFormatter[INDEX_COUNT];
-            }
+        SimplePatternFormatter newT = SimplePatternFormatter.compile(template);
+        if (newT.getPlaceholderCount() > 1) {
+            throw new IllegalArgumentException(
+                    "Extra placeholders: " + template);
         }
-
+        templates[idx] = newT;
     }
 
-    private final SimplePatternFormatter[] templates;
-
-    private QuantityFormatter(SimplePatternFormatter[] templates) {
-        this.templates = templates;
+    /**
+     * @return true if this object has at least the "other" variant
+     */
+    public boolean isValid() {
+        return templates[0] != null;
     }
 
     /**
@@ -146,6 +132,7 @@ class QuantityFormatter {
      * @return the SimplePatternFormatter
      */
     public SimplePatternFormatter getByVariant(CharSequence variant) {
+        assert isValid();
         int idx = getPluralIndex(variant);
         SimplePatternFormatter template = templates[idx < 0 ? 0 : idx];
         return template == null ? templates[0] : template;
index 777559921ceae34b86d90d55b8d60cb7a8dc3b4e..d928ca50a5b221c259eecaa6b17da1a5b4942b3e 100644 (file)
@@ -792,8 +792,8 @@ public final class RelativeDateTimeFormatter {
                 ICUResourceBundle timeUnitBundle,
                 RelativeUnit relativeUnit,
                 EnumMap<RelativeUnit, QuantityFormatter[]> quantitativeUnitMap) {
-            QuantityFormatter.Builder future = new QuantityFormatter.Builder();
-            QuantityFormatter.Builder past = new QuantityFormatter.Builder();
+            QuantityFormatter future = new QuantityFormatter();
+            QuantityFormatter past = new QuantityFormatter();
             timeUnitBundle = timeUnitBundle.getWithFallback("relativeTime");
             addTimeUnit(
                     timeUnitBundle.getWithFallback("future"),
@@ -802,15 +802,15 @@ public final class RelativeDateTimeFormatter {
                     timeUnitBundle.getWithFallback("past"),
                     past);
             quantitativeUnitMap.put(
-                    relativeUnit, new QuantityFormatter[] { past.build(), future.build() });
+                    relativeUnit, new QuantityFormatter[] { past, future });
         }
 
         private static void addTimeUnit(
-                ICUResourceBundle pastOrFuture, QuantityFormatter.Builder builder) {
+                ICUResourceBundle pastOrFuture, QuantityFormatter qf) {
             int size = pastOrFuture.getSize();
             for (int i = 0; i < size; i++) {
                 UResourceBundle r = pastOrFuture.get(i);
-                builder.add(r.getKey(), r.getString());
+                qf.addIfAbsent(r.getKey(), r.getString());
             }
         }
         
index 3d33fac3ad802922f7520fca219aeac3c942f770..5465b0ac4132c1178198d21a0621fdf78b2ad63c 100644 (file)
@@ -278,6 +278,15 @@ public class TimeUnitTest extends TestFmwk {
         TimeUnitFormat formatter = new TimeUnitFormat(en_GB, TimeUnitFormat.ABBREVIATED_NAME);
         String result = formatter.format(oneHour);
         assertEquals("TestBritishShortHourFallback()", "1 hr", result);
+
+        // Check that we can load the time unit formatting data for all locales.
+        for (ULocale locale : ULocale.getAvailableLocales()) {
+            try {
+                new TimeUnitFormat(locale, TimeUnitFormat.ABBREVIATED_NAME);
+            } catch (RuntimeException e) {
+                errln("failed to load TimeUnitFormat data for " + locale);
+            }
+        }
     }
 
     private void formatParsing(TimeUnitFormat format) {