]> 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>
Wed, 2 Dec 2015 22:54:54 +0000 (22:54 +0000)
committerMarkus Scherer <markus.icu@gmail.com>
Wed, 2 Dec 2015 22:54:54 +0000 (22:54 +0000)
X-SVN-Rev: 38103

icu4c/source/i18n/measfmt.cpp
icu4c/source/i18n/quantityformatter.cpp
icu4c/source/i18n/quantityformatter.h
icu4c/source/i18n/reldatefmt.cpp
icu4c/source/test/intltest/itutil.cpp
icu4c/source/test/intltest/measfmttest.cpp
icu4c/source/test/intltest/quantityformattertest.cpp
icu4c/source/test/intltest/reldatefmttest.cpp

index 5d7faa3fef6c1cdfe392a456e48d486708b09f88..274242d4f9ceb2ffde970248592860ae988f19b2 100644 (file)
@@ -241,10 +241,8 @@ struct UnitDataSink : public ResourceTableSink {
                 // The key must be one of the plural form strings. For example:
                 // one{"{0} hr"}
                 // other{"{0} hrs"}
-                if (!outer.hasPatterns) {
-                    outer.cacheData.formatters[outer.unitIndex][outer.width].add(
-                            key, value.getUnicodeString(errorCode), errorCode);
-                }
+                outer.cacheData.formatters[outer.unitIndex][outer.width].
+                        addIfAbsent(key, value, errorCode);
             }
         }
         UnitDataSink &outer;
@@ -262,8 +260,6 @@ struct UnitDataSink : public ResourceTableSink {
             if (U_FAILURE(errorCode)) { return NULL; }
             outer.unitIndex = MeasureUnit::internalGetIndexForTypeAndSubtype(outer.type, key);
             if (outer.unitIndex >= 0) {
-                outer.hasPatterns =
-                    outer.cacheData.formatters[outer.unitIndex][outer.width].isValid();
                 return &outer.patternSink;
             }
             return NULL;
@@ -316,7 +312,7 @@ struct UnitDataSink : public ResourceTableSink {
     UnitDataSink(MeasureFormatCacheData &outputData)
             : patternSink(*this), subtypeSink(*this), compoundSink(*this), typeSink(*this),
               cacheData(outputData),
-              width(UMEASFMT_WIDTH_COUNT), type(NULL), unitIndex(0), hasPatterns(FALSE) {}
+              width(UMEASFMT_WIDTH_COUNT), type(NULL), unitIndex(0) {}
     ~UnitDataSink();
     virtual void put(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
         // Handle aliases like
@@ -388,9 +384,6 @@ struct UnitDataSink : public ResourceTableSink {
     UMeasureFormatWidth width;
     const char *type;
     int32_t unitIndex;
-
-    /** True if we already have plural-form display patterns for width/type/unitIndex. */
-    UBool hasPatterns;
 };
 
 // Virtual destructors must be defined out of line.
index 22d19a95550ba7bd47973f25a55c0d3153988571..901b3f7edb2b4a36de5523d24d6eeed618413416 100644 (file)
@@ -5,6 +5,11 @@
 ******************************************************************************
 * quantityformatter.cpp
 */
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
 #include "quantityformatter.h"
 #include "simplepatternformatter.h"
 #include "uassert.h"
@@ -15,9 +20,9 @@
 #include "charstr.h"
 #include "unicode/fmtable.h"
 #include "unicode/fieldpos.h"
+#include "resource.h"
 #include "visibledigits.h"
-
-#if !UCONFIG_NO_FORMATTING
+#include "uassert.h"
 
 U_NAMESPACE_BEGIN
 
@@ -101,20 +106,25 @@ void QuantityFormatter::reset() {
     }
 }
 
-UBool QuantityFormatter::add(
+UBool QuantityFormatter::addIfAbsent(
         const char *variant,
-        const UnicodeString &rawPattern,
+        const UnicodeString *rawPattern,
+        const ResourceValue *patternValue,
         UErrorCode &status) {
     if (U_FAILURE(status)) {
         return FALSE;
     }
     int32_t pluralIndex = getPluralIndex(variant);
-    if (pluralIndex == -1) {
+    if (pluralIndex < 0) {
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return FALSE;
     }
-    SimplePatternFormatter *newFmt =
-            new SimplePatternFormatter(rawPattern);
+    if (formatters[pluralIndex] != NULL) {
+        return TRUE;
+    }
+    const UnicodeString &pattern =
+            rawPattern != NULL ? *rawPattern : patternValue->getUnicodeString(status);
+    SimplePatternFormatter *newFmt = new SimplePatternFormatter(pattern);
     if (newFmt == NULL) {
         status = U_MEMORY_ALLOCATION_ERROR;
         return FALSE;
@@ -124,7 +134,6 @@ UBool QuantityFormatter::add(
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return FALSE;
     }
-    delete formatters[pluralIndex];
     formatters[pluralIndex] = newFmt;
     return TRUE;
 }
@@ -135,6 +144,7 @@ UBool QuantityFormatter::isValid() const {
 
 const SimplePatternFormatter *QuantityFormatter::getByVariant(
         const char *variant) const {
+    U_ASSERT(isValid());
     int32_t pluralIndex = getPluralIndex(variant);
     if (pluralIndex == -1) {
         pluralIndex = 0;
index 4e19085964e9a44a519e404f3eb00addc3b94db3..97bf91c40bfd6d90a51bb375e9ec84e21851b078 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ******************************************************************************
-* Copyright (C) 2014, International Business Machines
+* Copyright (C) 2014-2015, International Business Machines
 * Corporation and others.  All Rights Reserved.
 ******************************************************************************
 * quantityformatter.h
@@ -14,6 +14,8 @@
 
 #if !UCONFIG_NO_FORMATTING
 
+#include "resource.h"
+
 U_NAMESPACE_BEGIN
 
 class SimplePatternFormatter;
@@ -64,17 +66,30 @@ public:
     void reset();
 
     /**
-      * Adds a plural variant.
-      *
-      * @param variant "zero", "one", "two", "few", "many", "other"
-      * @param rawPattern the pattern for the variant e.g "{0} meters"
-      * @param status any error returned here.
-      * @return TRUE on success; FALSE if status was set to a non zero error.
-      */
-    UBool add(
-            const char *variant,
-            const UnicodeString &rawPattern,
-            UErrorCode &status);
+     * Adds a plural variant if there is none yet for the plural form.
+     *
+     * @param variant "zero", "one", "two", "few", "many", "other"
+     * @param rawPattern the pattern for the variant e.g "{0} meters"
+     * @param status any error returned here.
+     * @return TRUE on success; FALSE if status was set to a non zero error.
+     */
+    UBool addIfAbsent(const char *variant, const UnicodeString &rawPattern, UErrorCode &status) {
+        return addIfAbsent(variant, &rawPattern, NULL, status);
+    }
+
+    /**
+     * Adds a plural variant if there is none yet for the plural form.
+     * This version only calls ResourceValue::getString()
+     * if there is no template yet for the plural form.
+     *
+     * @param variant "zero", "one", "two", "few", "many", "other"
+     * @param rawPattern the pattern for the variant e.g "{0} meters"
+     * @param status any error returned here.
+     * @return TRUE on success; FALSE if status was set to a non zero error.
+     */
+    UBool addIfAbsent(const char *variant, const ResourceValue &rawPattern, UErrorCode &status) {
+        return addIfAbsent(variant, NULL, &rawPattern, status);
+    }
 
     /**
      * returns TRUE if this object has at least the "other" variant.
@@ -109,6 +124,12 @@ public:
             UErrorCode &status) const;
 
 private:
+    UBool addIfAbsent(
+            const char *variant,
+            const UnicodeString *rawPattern,
+            const ResourceValue *patternValue,
+            UErrorCode &status);
+
     SimplePatternFormatter *formatters[6];
 };
 
index b4bfe429dd6aca723392dc746e3f8bc50c6604a4..4d8ca06f98a75242475ee71953ea2050fbd2929d 100644 (file)
@@ -1,10 +1,10 @@
 /*
 ******************************************************************************
-* Copyright (C) 2014, International Business Machines Corporation and         
-* others. All Rights Reserved.                                                
+* Copyright (C) 2014-2015, International Business Machines Corporation and
+* others. All Rights Reserved.
 ******************************************************************************
-*                                                                             
-* File RELDATEFMT.CPP                                                             
+*
+* File reldatefmt.cpp
 ******************************************************************************
 */
 
@@ -186,7 +186,7 @@ static void initQuantityFormatter(
         if (!getString(pluralBundle.getAlias(), rawPattern, status)) {
             return;
         }
-        if (!formatter.add(
+        if (!formatter.addIfAbsent(
                 ures_getKey(pluralBundle.getAlias()),
                 rawPattern,
                 status)) {
index 7880c7b8a4d78b4bd0345f1d833dc9daab20c571..f529d6fca90282963224cd15dc0ac45dfb8e0dd6 100644 (file)
@@ -124,6 +124,7 @@ void IntlTestUtilities::runIndexedTest( int32_t index, UBool exec, const char* &
                 LocalPointer<IntlTest> test(createQuantityFormatterTest());
                 callTest(*test, par);
             }
+            break;
         case 23: 
             name = "PluralMapTest"; 
             if (exec) { 
index f2f2d09734c8f2a0885eb6fef16d5195e0960eff..4732f612fa8c331beb571dd2596a6fc91a94cbf4 100644 (file)
@@ -61,6 +61,7 @@ private:
     void TestGroupingSeparator();
     void TestDoubleZero();
     void TestUnitPerUnitResolution();
+    void TestIndividualPluralFallback();
     void verifyFormat(
         const char *description,
         const MeasureFormat &fmt,
@@ -141,6 +142,7 @@ void MeasureFormatTest::runIndexedTest(
     TESTCASE_AUTO(TestGroupingSeparator);
     TESTCASE_AUTO(TestDoubleZero);
     TESTCASE_AUTO(TestUnitPerUnitResolution);
+    TESTCASE_AUTO(TestIndividualPluralFallback);
     TESTCASE_AUTO_END;
 }
 
@@ -1588,6 +1590,19 @@ void MeasureFormatTest::TestUnitPerUnitResolution() {
     assertEquals("", "50 psi", actual);
 }
 
+void MeasureFormatTest::TestIndividualPluralFallback() {
+    // See ticket #11986 "incomplete fallback in MeasureFormat".
+    // In CLDR 28, fr_CA temperature-generic/short has only the "one" form,
+    // and falls back to fr for the "other" form.
+    IcuTestErrorCode errorCode(*this, "TestIndividualPluralFallback");
+    MeasureFormat mf("fr_CA", UMEASFMT_WIDTH_SHORT, errorCode);
+    LocalPointer<Measure> twoDeg(
+        new Measure(2, MeasureUnit::createGenericTemperature(errorCode), errorCode), errorCode);
+    UnicodeString expected = UNICODE_STRING_SIMPLE("2\\u00B0").unescape();
+    UnicodeString actual;
+    assertEquals("2 deg temp in fr_CA", expected, mf.format(twoDeg.orphan(), actual, errorCode));
+}
+
 void MeasureFormatTest::verifyFieldPosition(
         const char *description,
         const MeasureFormat &fmt,
index 0167075f5bc5babbd82a2424d0e06b79d44ecf5f..c641de2a686f52b011443859788c41c9e17fe6f4 100644 (file)
@@ -1,7 +1,7 @@
 /*
 *******************************************************************************
-* Copyright (C) 2014, International Business Machines Corporation and         *
-* others. All Rights Reserved.                                                *
+* Copyright (C) 2014-2015, International Business Machines Corporation and
+* others. All Rights Reserved.
 *******************************************************************************
 *
 * File QUANTITYFORMATTERTEST.CPP
@@ -37,25 +37,25 @@ void QuantityFormatterTest::TestBasic() {
     QuantityFormatter fmt;
     assertFalse(
             "adding bad variant",
-            fmt.add("a bad variant", "{0} pounds", status));
+            fmt.addIfAbsent("a bad variant", "{0} pounds", status));
     assertEquals("adding bad variant status", U_ILLEGAL_ARGUMENT_ERROR, status);
     status = U_ZERO_ERROR;
     assertFalse(
             "Adding bad pattern",
-            fmt.add("other", "{0} {1} too many placeholders", status));
+            fmt.addIfAbsent("other", "{0} {1} too many placeholders", status));
     assertEquals("adding bad pattern status", U_ILLEGAL_ARGUMENT_ERROR, status);
     status = U_ZERO_ERROR;
     assertFalse("isValid with no patterns", fmt.isValid());
     assertTrue(
             "Adding good pattern with no placeholders",
-            fmt.add("other", "no placeholder", status));
+            fmt.addIfAbsent("zero", "no placeholder", status));
     assertTrue(
             "Adding good pattern",
-            fmt.add("other", "{0} pounds", status));
+            fmt.addIfAbsent("other", "{0} pounds", status));
     assertTrue("isValid with other", fmt.isValid());
     assertTrue(
             "Adding good pattern",
-            fmt.add("one", "{0} pound", status));
+            fmt.addIfAbsent("one", "{0} pound", status));
 
     assertEquals(
             "getByVariant",
index 91f548374ba4f9db23c548175d41456fe04decb6..f11adb60f5a55d83b72e5f363717e8bda3f71c39 100644 (file)
@@ -231,9 +231,9 @@ static WithQuantityExpected kSerbian[] = {
 };
 
 static WithQuantityExpected kSerbianNarrow[] = {
-        {0.0, UDAT_DIRECTION_NEXT, UDAT_RELATIVE_MONTHS, "\\u0437\\u0430 0 \\u043c\\u0435\\u0441."},
-        {1.2, UDAT_DIRECTION_NEXT, UDAT_RELATIVE_MONTHS, "\\u0437\\u0430 1,2 \\u043c\\u0435\\u0441."},
-        {21.0, UDAT_DIRECTION_NEXT, UDAT_RELATIVE_MONTHS, "\\u0437\\u0430 21 \\u043c\\u0435\\u0441."}
+        {0.0, UDAT_DIRECTION_NEXT, UDAT_RELATIVE_MONTHS, "\\u0437\\u0430 0 \\u043c."},
+        {1.2, UDAT_DIRECTION_NEXT, UDAT_RELATIVE_MONTHS, "\\u0437\\u0430 1,2 \\u043c."},
+        {21.0, UDAT_DIRECTION_NEXT, UDAT_RELATIVE_MONTHS, "\\u0437\\u0430 21 \\u043c."}
 };
 
 static WithoutQuantityExpected kEnglishNoQuantity[] = {