]> granicus.if.org Git - icu/commitdiff
ICU-22088 Various fixes to make dealing with NUMBERING_SYSTEM formatters easier.
authorRich Gillam <62772518+richgillam@users.noreply.github.com>
Sat, 23 Jul 2022 00:56:00 +0000 (17:56 -0700)
committerRich Gillam <62772518+richgillam@users.noreply.github.com>
Thu, 28 Jul 2022 23:18:01 +0000 (16:18 -0700)
icu4c/source/data/rbnf/root.txt
icu4c/source/i18n/numfmt.cpp
icu4c/source/i18n/unicode/rbnf.h
icu4c/source/i18n/unum.cpp
icu4c/source/test/cintltst/cnumtst.c
icu4c/source/test/intltest/itrbnf.cpp
icu4c/source/test/intltest/itrbnf.h
icu4c/source/test/intltest/numfmtst.cpp
icu4c/source/test/intltest/numfmtst.h
icu4j/main/shared/data/icudata.jar
icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/RbnfTest.java

index 6db5ee9add698f3db066679444d2d1c3e805ad58..c1b9cc2696fa19e813a42b02097c835508b9cae4 100644 (file)
@@ -661,6 +661,8 @@ root{
             "%%tamil-thousands:",
             "0: =%tamil=;",
             "1000: <<\u0BF2[>>];",
+            "%zDefault:",
+            "0: =#,##0=;",
         }
         OrdinalRules{
             "%digits-ordinal:",
index 8c90fdd5b761877508668be7f70c54cb76b221dd..0adad07379c596407519969ca2abe0142754a735 100644 (file)
@@ -117,7 +117,7 @@ static const UChar * const gLastResortNumberPatterns[UNUM_FORMAT_STYLE_COUNT] =
     NULL,  // UNUM_SPELLOUT
     NULL,  // UNUM_ORDINAL
     NULL,  // UNUM_DURATION
-    NULL,  // UNUM_NUMBERING_SYSTEM
+    gLastResortDecimalPat,  // UNUM_NUMBERING_SYSTEM
     NULL,  // UNUM_PATTERN_RULEBASED
     gLastResortIsoCurrencyPat,  // UNUM_CURRENCY_ISO
     gLastResortPluralCurrencyPat,  // UNUM_CURRENCY_PLURAL
@@ -1310,6 +1310,14 @@ NumberFormat::makeInstance(const Locale& desiredLocale,
         status = U_ILLEGAL_ARGUMENT_ERROR;
         return NULL;
     }
+    
+    // For the purposes of general number formatting, UNUM_NUMBERING_SYSTEM should behave the same
+    // was as UNUM_DECIMAL.  In both cases, you get either a DecimalFormat or a RuleBasedNumberFormat
+    // depending on the locale's numbering system (either the default one for the locale or a specific
+    // one specified by using the "@numbers=" or "-u-nu-" parameter in the locale ID.
+    if (style == UNUM_NUMBERING_SYSTEM) {
+        style = UNUM_DECIMAL;
+    }
 
     // Some styles are not supported. This is a result of merging
     // the @draft ICU 4.2 NumberFormat::EStyles into the long-existing UNumberFormatStyle.
index d4d7e22518106a90746c4e2045026106d81d202a..70d92dd549d890b8cf4d382627065492767f8f65 100644 (file)
@@ -54,9 +54,27 @@ class RuleBasedCollator;
  * @stable ICU 2.2
  */
 enum URBNFRuleSetTag {
+    /**
+     * Requests predefined ruleset for spelling out numeric values in words.
+     * @stable ICU 2.2
+     */
     URBNF_SPELLOUT,
+    /**
+     * Requests predefined ruleset for the ordinal form of a number.
+     * @stable ICU 2.2
+     */
     URBNF_ORDINAL,
+    /**
+     * Requests predefined ruleset for formatting a value as a duration in hours, minutes, and seconds.
+     * @stable ICU 2.2
+     */
     URBNF_DURATION,
+    /**
+     * Requests predefined ruleset for various non-place-value numbering systems.
+     * WARNING: The same resource contains rule sets for a variety of different numbering systems.
+     * You need to call setDefaultRuleSet() on the formatter to choose the actual numbering system.
+     * @stable ICU 2.2
+     */
     URBNF_NUMBERING_SYSTEM,
 #ifndef U_HIDE_DEPRECATED_API
     /**
@@ -662,6 +680,9 @@ public:
    * URBNF_DURATION, which formats a duration in seconds as hours, minutes, and seconds always rounding down,
    * and URBNF_NUMBERING_SYSTEM, which is used to invoke rules for alternate numbering
    * systems such as the Hebrew numbering system, or for Roman Numerals, etc.
+   * NOTE: If you use URBNF_NUMBERING_SYSTEM, you must also call setDefaultRuleSet() to
+   * specify the exact numbering system you want to use.  If you want the default numbering system
+   * for the locale, call NumberFormat::createInstance() instead of creating a RuleBasedNumberFormat directly.
    * @param locale The locale for the formatter.
    * @param status The status indicating whether the constructor succeeded.
    * @stable ICU 2.0
index 769d59290e7865e89e60e660f1803fb3d044525c..d2ba7ae3a2d6e093e823e1fd60dba72aa9665f8a 100644 (file)
@@ -60,6 +60,7 @@ unum_open(  UNumberFormatStyle    style,
     case UNUM_CURRENCY_ACCOUNTING:
     case UNUM_CASH_CURRENCY:
     case UNUM_CURRENCY_STANDARD:
+    case UNUM_NUMBERING_SYSTEM:
         retVal = NumberFormat::createInstance(Locale(locale), style, *status);
         break;
 
@@ -112,10 +113,6 @@ unum_open(  UNumberFormatStyle    style,
     case UNUM_DURATION:
         retVal = new RuleBasedNumberFormat(URBNF_DURATION, Locale(locale), *status);
         break;
-
-    case UNUM_NUMBERING_SYSTEM:
-        retVal = new RuleBasedNumberFormat(URBNF_NUMBERING_SYSTEM, Locale(locale), *status);
-        break;
 #endif
 
     case UNUM_DECIMAL_COMPACT_SHORT:
index e80e021fe8623c1b2bcc408db4ae8cbcf4374bcb..fd9abe3a94349609355c75bbb1c5c494ae6108b3 100644 (file)
@@ -76,6 +76,7 @@ static void TestIgnorePadding(void);
 static void TestSciNotationMaxFracCap(void);
 static void TestMinIntMinFracZero(void);
 static void Test21479_ExactCurrency(void);
+static void Test22088_Ethiopic(void);
 
 #define TESTCASE(x) addTest(root, &x, "tsformat/cnumtst/" #x)
 
@@ -118,6 +119,7 @@ void addNumForTest(TestNode** root)
     TESTCASE(TestSciNotationMaxFracCap);
     TESTCASE(TestMinIntMinFracZero);
     TESTCASE(Test21479_ExactCurrency);
+    TESTCASE(Test22088_Ethiopic);
 }
 
 /* test Parse int 64 */
@@ -3605,4 +3607,30 @@ static void Test21479_ExactCurrency(void) {
     unum_close(nf);
 }
 
+static void Test22088_Ethiopic(void) {
+    UErrorCode err = U_ZERO_ERROR;
+    UNumberFormat* nf1 = unum_open(UNUM_DEFAULT, NULL, 0, "am_ET@numbers=ethi", NULL, &err);
+    UNumberFormat* nf2 = unum_open(UNUM_NUMBERING_SYSTEM, NULL, 0, "am_ET@numbers=ethi", NULL, &err);
+    UNumberFormat* nf3 = unum_open(UNUM_NUMBERING_SYSTEM, NULL, 0, "en_US", NULL, &err);
+    
+    if (assertSuccess("Creation of number formatters failed", &err)) {
+        UChar result[200];
+        
+        unum_formatDouble(nf1, 123, result, 200, NULL, &err);
+        assertSuccess("Formatting of number failed", &err);
+        assertUEquals("Wrong result with UNUM_DEFAULT", u"፻፳፫", result);
+        
+        unum_formatDouble(nf2, 123, result, 200, NULL, &err);
+        assertSuccess("Formatting of number failed", &err);
+        assertUEquals("Wrong result with UNUM_NUMBERING_SYSTEM", u"፻፳፫", result);
+        
+        unum_formatDouble(nf3, 123, result, 200, NULL, &err);
+        assertSuccess("Formatting of number failed", &err);
+        assertUEquals("Wrong result with UNUM_NUMBERING_SYSTEM and English", u"123", result);
+    }
+    unum_close(nf1);
+    unum_close(nf2);
+    unum_close(nf3);
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 847b84128400ec1b44c4cf7753f0698efd191784..672b73ddd660fc4b6a7a50a144a6e71cabf86880 100644 (file)
@@ -78,6 +78,7 @@ void IntlTestRBNF::runIndexedTest(int32_t index, UBool exec, const char* &name,
         TESTCASE(26, TestParseFailure);
         TESTCASE(27, TestMinMaxIntegerDigitsIgnored);
         TESTCASE(28, TestNorwegianSpellout);
+        TESTCASE(29, TestNumberingSystem);
 #else
         TESTCASE(0, TestRBNFDisabled);
 #endif
@@ -2489,6 +2490,21 @@ IntlTestRBNF::doLenientParseTest(RuleBasedNumberFormat* formatter, const char* t
     }
 }
 
+void
+IntlTestRBNF::TestNumberingSystem() {
+    IcuTestErrorCode err(*this, "TestNumberingSystem");
+    RuleBasedNumberFormat rbnf(URBNF_NUMBERING_SYSTEM, Locale::getUS(), err);
+    
+    if (!err.errIfFailureAndReset("Failed to create RBNF with URBNF_NUMBERING_SYSTEM")) {
+        UnicodeString result;
+        assertEquals("Wrong result with default rule set", u"123", rbnf.format(123, result, err));
+        
+        result.remove();
+        rbnf.setDefaultRuleSet(u"%ethiopic", err);
+        assertEquals("Wrong result with Ethiopic rule set", u"፻፳፫", rbnf.format(123, result, err));
+    }
+}
+
 /* U_HAVE_RBNF */
 #else
 
index 9fae1755cf190a973e07fbe74083724d4f262488..96147ea224d30c3e162a4e426ccd8a97eae2b3f6 100644 (file)
@@ -154,6 +154,7 @@ class IntlTestRBNF : public IntlTest {
     void TestCompactDecimalFormatStyle();
     void TestParseFailure();
     void TestMinMaxIntegerDigitsIgnored();
+    void TestNumberingSystem();
 
 protected:
   virtual void doTest(RuleBasedNumberFormat* formatter, const char* const testData[][2], UBool testParsing);
index 1ed8cb2d4107ea4156a801a16aa33919b7f3cea3..3c5ec751214219e2a8bdd9ffe9c57f05f4434d58 100644 (file)
@@ -252,6 +252,7 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
   TESTCASE_AUTO(Test21232_ParseTimeout);
   TESTCASE_AUTO(Test10997_FormatCurrency);
   TESTCASE_AUTO(Test21556_CurrencyAsDecimal);
+  TESTCASE_AUTO(Test22088_Ethiopic);
   TESTCASE_AUTO_END;
 }
 
@@ -10145,4 +10146,20 @@ void NumberFormatTest::Test21556_CurrencyAsDecimal() {
     }
 }
 
+void NumberFormatTest::Test22088_Ethiopic() {
+    IcuTestErrorCode err(*this, "Test22088_Ethiopic");
+    LocalPointer<NumberFormat> nf1(NumberFormat::createInstance(Locale("am_ET@numbers=ethi"), UNUM_DEFAULT, err));
+    LocalPointer<NumberFormat> nf2(NumberFormat::createInstance(Locale("am_ET@numbers=ethi"), UNUM_NUMBERING_SYSTEM, err));
+    LocalPointer<NumberFormat> nf3(NumberFormat::createInstance(Locale::getUS(), UNUM_NUMBERING_SYSTEM, err));
+    
+    if (!err.errIfFailureAndReset("Creation of number formatters failed")) {
+        UnicodeString result;
+        assertEquals("Wrong result with UNUM_DEFAULT", u"፻፳፫", nf1->format(123, result));
+        result.remove();
+        assertEquals("Wrong result with UNUM_NUMBERING_SYSTEM", u"፻፳፫", nf2->format(123, result));
+        result.remove();
+        assertEquals("Wrong result with UNUM_NUMBERING_SYSTEM and English", u"123", nf3->format(123, result));
+    }
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index abd828d644bccdcdd597fd391e7315f400d65142..526e90cd36719f17145456dfc477baa1adafda6b 100644 (file)
@@ -308,6 +308,7 @@ class NumberFormatTest: public CalendarTimeZoneTest {
     void Test21232_ParseTimeout();
     void Test10997_FormatCurrency();
     void Test21556_CurrencyAsDecimal();
+    void Test22088_Ethiopic();
 
  private:
     UBool testFormattableAsUFormattable(const char *file, int line, Formattable &f);
index 533224a0798344be96295c58ef5ecf109814cbad..40f7742b28dd909d491fa117e186bbc51ba722d5 100644 (file)
@@ -1,3 +1,3 @@
 version https://git-lfs.github.com/spec/v1
-oid sha256:f3112f5cdf386100bc201a1fabc3a15a190d662d100712619a83ca211639d0fb
-size 13891395
+oid sha256:7280fe2b5614523890959916529e198ee81e51dcdbc02d61882c0257f3346e8d
+size 13891411
index e7973255982a479fda897922179577e2ab248972..2ebafe2b52256d47283a791efffe897e34745db4 100644 (file)
@@ -1839,4 +1839,14 @@ public class RbnfTest extends TestFmwk {
         assertEquals("infinity", rbnf.format(Double.POSITIVE_INFINITY));
         assertEquals("not a number", rbnf.format(Double.NaN));
     }
+
+    @Test
+    public void TestNumberingSystem() {
+        RuleBasedNumberFormat rbnf = new RuleBasedNumberFormat(ULocale.US, RuleBasedNumberFormat.NUMBERING_SYSTEM);
+
+        assertEquals("Wrong result with default rule set", "123", rbnf.format(123));
+
+        rbnf.setDefaultRuleSet("%ethiopic");
+        assertEquals("Wrong result with Ethiopic rule set", "፻፳፫", rbnf.format(123));
+    }
 }