]> granicus.if.org Git - icu/commitdiff
ICU-12763 Add uplrules_selectWithFormat and PluralRules::select that take & use ...
authorPeter Edberg <pedberg@unicode.org>
Sat, 21 Jan 2017 01:03:32 +0000 (01:03 +0000)
committerPeter Edberg <pedberg@unicode.org>
Sat, 21 Jan 2017 01:03:32 +0000 (01:03 +0000)
X-SVN-Rev: 39591

icu4c/source/i18n/plurrule.cpp
icu4c/source/i18n/unicode/plurrule.h
icu4c/source/i18n/unicode/upluralrules.h
icu4c/source/i18n/upluralrules.cpp
icu4c/source/test/cintltst/cpluralrulestest.c

index 1362eb5d0784f49a14b2f14acf507ec3bbcecc90..0ce378cba9d824a8913037fea9aee011533d36bf 100644 (file)
@@ -17,6 +17,8 @@
 #include "unicode/plurrule.h"
 #include "unicode/upluralrules.h"
 #include "unicode/ures.h"
+#include "unicode/numfmt.h"
+#include "unicode/decimfmt.h"
 #include "charstr.h"
 #include "cmemory.h"
 #include "cstring.h"
@@ -36,7 +38,6 @@
 #include "digitinterval.h" 
 #include "visibledigits.h"
 
-
 #if !UCONFIG_NO_FORMATTING
 
 U_NAMESPACE_BEGIN
@@ -246,6 +247,24 @@ PluralRules::select(double number) const {
     return select(FixedDecimal(number));
 }
 
+UnicodeString
+PluralRules::select(const Formattable& obj, const NumberFormat& fmt) const {
+    UErrorCode status = U_ZERO_ERROR;
+    const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
+    if (decFmt != NULL) {
+        VisibleDigitsWithExponent digits;
+        decFmt->initVisibleDigitsWithExponent(obj, digits, status);
+        if (U_SUCCESS(status)) {
+            return select(digits);
+        }
+    }
+    double number = obj.getDouble(status);
+    if (U_SUCCESS(status)) {
+        return select(number);
+    }
+    return getKeywordOther();
+}
+
 UnicodeString
 PluralRules::select(const FixedDecimal &number) const {
     if (mRules == NULL) {
index d56b23ab4badd538f7cb88c53e169a14b62f3797..a46abee85e68fa53ac4008005b50038f78a014ec 100644 (file)
@@ -29,6 +29,9 @@
 
 #include "unicode/format.h"
 #include "unicode/upluralrules.h"
+#ifndef U_HIDE_INTERNAL_API
+#include "unicode/numfmt.h"
+#endif  /* U_HIDE_INTERNAL_API */
 
 /**
  * Value returned by PluralRules::getUniqueKeywordValue() when there is no
@@ -345,6 +348,19 @@ public:
     UnicodeString select(double number) const;
 
 #ifndef U_HIDE_INTERNAL_API
+    /**
+     * Given a number and a format, returns the keyword of the first applicable
+     * rule for this PluralRules object.
+     * Note: This internal preview interface may be removed in the future if
+     * an architecturally cleaner solution reaches stable status.
+     * @param obj The numeric object for which the rule should be determined.
+     * @param fmt The NumberFormat specifying how the number will be formatted
+     *        (this can affect the plural form, e.g. "1 dollar" vs "1.0 dollars").
+     * @return The keyword of the selected rule.
+     * @internal ICU 59 technology preview, may be removed in the future
+     */
+    UnicodeString select(const Formattable& obj, const NumberFormat& fmt) const;
+
     /**
       * @internal
       */
index f9b2668d1984a2dfb02b2e6f3d76d69a6ed91921..7f2d000c95ab415ba469ca054bd2e90a3b08e5ca 100644 (file)
@@ -15,6 +15,9 @@
 #if !UCONFIG_NO_FORMATTING
 
 #include "unicode/localpointer.h"
+#ifndef U_HIDE_INTERNAL_API
+#include "unicode/unum.h"
+#endif  /* U_HIDE_INTERNAL_API */
 
 /**
  * \file
@@ -144,6 +147,33 @@ uplrules_select(const UPluralRules *uplrules,
                UChar *keyword, int32_t capacity,
                UErrorCode *status);
 
+#ifndef U_HIDE_INTERNAL_API
+/**
+ * Given a number, returns the keyword of the first rule that applies to the
+ * number, according to the UPluralRules object and given the number format
+ * specified by the UNumberFormat object.
+ * Note: This internal preview interface may be removed in the future if
+ * an architecturally cleaner solution reaches stable status.
+ * @param uplrules The UPluralRules object specifying the rules.
+ * @param number The number for which the rule has to be determined.
+ * @param fmt The UNumberFormat specifying how the number will be formatted
+ *        (this can affect the plural form, e.g. "1 dollar" vs "1.0 dollars").
+ *        If this is NULL, the function behaves like uplrules_select.
+ * @param keyword The keyword of the rule that applies to number.
+ * @param capacity The capacity of the keyword buffer.
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return The length of keyword.
+ * @internal ICU 59 technology preview, may be removed in the future
+ */
+U_INTERNAL int32_t U_EXPORT2
+uplrules_selectWithFormat(const UPluralRules *uplrules,
+                          double number,
+                          const UNumberFormat *fmt,
+                          UChar *keyword, int32_t capacity,
+                          UErrorCode *status);
+
+#endif  /* U_HIDE_INTERNAL_API */
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
 
 #endif
index 7647637d7c179e027e0d30211862a5e5aec2362e..384a87c6b05829f251561963d319c7df5564f8ba 100644 (file)
@@ -15,6 +15,8 @@
 #include "unicode/plurrule.h"
 #include "unicode/locid.h"
 #include "unicode/unistr.h"
+#include "unicode/unum.h"
+#include "unicode/numfmt.h"
 
 U_NAMESPACE_USE
 
@@ -54,5 +56,25 @@ uplrules_select(const UPluralRules *uplrules,
     return result.extract(keyword, capacity, *status);
 }
 
+U_CAPI int32_t U_EXPORT2
+uplrules_selectWithFormat(const UPluralRules *uplrules,
+                          double number,
+                          const UNumberFormat *fmt,
+                          UChar *keyword, int32_t capacity,
+                          UErrorCode *status)
+{
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+    const PluralRules* plrules = reinterpret_cast<const PluralRules*>(uplrules);
+    const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
+    if (plrules == NULL || nf == NULL || ((keyword == NULL)? capacity != 0 : capacity < 0)) {
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return 0;
+    }
+    Formattable obj(number);
+    UnicodeString result = plrules->select(obj, *nf);
+    return result.extract(keyword, capacity, *status);
+}
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 5582ff2ecace19ed27e094f1727b044a227c1a57..1a784a9f5a868d9e89112bac8ab2bfbce0450e39 100644 (file)
@@ -32,31 +32,34 @@ typedef struct {
     const char * locale;
     double       number;
     const char * keywordExpected;
+    const char * keywordExpectedForDecimals;
 } PluralRulesTestItem;
 
 /* Just a small set of tests for now, other functionality is tested in the C++ tests */
 static const PluralRulesTestItem testItems[] = {
-    { "en",   0, "other" },
-    { "en", 0.5, "other" },
-    { "en",   1, "one" },
-    { "en", 1.5, "other" },
-    { "en",   2, "other" },
-    { "fr",   0, "one" },
-    { "fr", 0.5, "one" },
-    { "fr",   1, "one" },
-    { "fr", 1.5, "one" },
-    { "fr",   2, "other" },
-    { "ru",   0, "many" },
-    { "ru", 0.5, "other" },
-    { "ru",   1, "one" },
-    { "ru", 1.5, "other" },
-    { "ru",   2, "few" },
-    { "ru",   5, "many" },
-    { "ru",  10, "many" },
-    { "ru",  11, "many" },
-    { NULL,   0, NULL }
+    { "en",   0, "other", "other" },
+    { "en", 0.5, "other", "other" },
+    { "en",   1, "one",   "other" },
+    { "en", 1.5, "other", "other" },
+    { "en",   2, "other", "other" },
+    { "fr",   0, "one",   "one" },
+    { "fr", 0.5, "one",   "one" },
+    { "fr",   1, "one",   "one" },
+    { "fr", 1.5, "one",   "one" },
+    { "fr",   2, "other", "other" },
+    { "ru",   0, "many",  "other" },
+    { "ru", 0.5, "other", "other" },
+    { "ru",   1, "one",   "other" },
+    { "ru", 1.5, "other", "other" },
+    { "ru",   2, "few",   "other" },
+    { "ru",   5, "many",  "other" },
+    { "ru",  10, "many",  "other" },
+    { "ru",  11, "many",  "other" },
+    { NULL,   0, NULL,    NULL }
 };
 
+static const UChar twoDecimalPat[] = { 0x23,0x30,0x2E,0x30,0x30,0 }; /* "#0.00" */
+
 enum {
     kKeywordBufLen = 32
 };
@@ -69,6 +72,7 @@ static void TestPluralRules()
         UErrorCode status = U_ZERO_ERROR;
         UPluralRules* uplrules = uplrules_open(testItemPtr->locale, &status);
         if ( U_SUCCESS(status) ) {
+            UNumberFormat* unumfmt;
             UChar keyword[kKeywordBufLen];
             UChar keywordExpected[kKeywordBufLen];
             int32_t keywdLen = uplrules_select(uplrules, testItemPtr->number, keyword, kKeywordBufLen, &status);
@@ -86,6 +90,30 @@ static void TestPluralRules()
                 log_err("FAIL: uplrules_select for locale %s, number %.1f: %s\n",
                         testItemPtr->locale, testItemPtr->number, myErrorName(status) );
             }
+
+            status = U_ZERO_ERROR;
+            unumfmt = unum_open(UNUM_PATTERN_DECIMAL, twoDecimalPat, -1, testItemPtr->locale, NULL, &status);
+            if ( U_SUCCESS(status) ) {
+                keywdLen = uplrules_selectWithFormat(uplrules, testItemPtr->number, unumfmt, keyword, kKeywordBufLen, &status);
+                if (keywdLen >= kKeywordBufLen) {
+                    keyword[kKeywordBufLen-1] = 0;
+                }
+                if ( U_SUCCESS(status) ) {
+                    u_unescape(testItemPtr->keywordExpectedForDecimals, keywordExpected, kKeywordBufLen);
+                    if ( u_strcmp(keyword, keywordExpected) != 0 ) {
+                        char bcharBuf[kKeywordBufLen];
+                        log_data_err("ERROR: uplrules_selectWithFormat for locale %s, number %.1f: expect %s, get %s\n",
+                                 testItemPtr->locale, testItemPtr->number, testItemPtr->keywordExpectedForDecimals, u_austrcpy(bcharBuf,keyword) );
+                    }
+                } else {
+                    log_err("FAIL: uplrules_selectWithFormat for locale %s, number %.1f: %s\n",
+                            testItemPtr->locale, testItemPtr->number, myErrorName(status) );
+                }
+                unum_close(unumfmt);
+            } else {
+                log_err("FAIL: unum_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) );
+            }
+
             uplrules_close(uplrules);
         } else {
             log_err("FAIL: uplrules_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) );