]> granicus.if.org Git - icu/commitdiff
ICU-9132 ordinal-plural formatting in C/C++
authorMarkus Scherer <markus.icu@gmail.com>
Sat, 7 Apr 2012 04:27:27 +0000 (04:27 +0000)
committerMarkus Scherer <markus.icu@gmail.com>
Sat, 7 Apr 2012 04:27:27 +0000 (04:27 +0000)
X-SVN-Rev: 31687

18 files changed:
icu4c/source/common/messagepattern.cpp
icu4c/source/common/unicode/messagepattern.h
icu4c/source/data/misc/plurals.txt
icu4c/source/i18n/msgfmt.cpp
icu4c/source/i18n/plurfmt.cpp
icu4c/source/i18n/plurrule.cpp
icu4c/source/i18n/unicode/msgfmt.h
icu4c/source/i18n/unicode/plurfmt.h
icu4c/source/i18n/unicode/plurrule.h
icu4c/source/i18n/unicode/upluralrules.h
icu4c/source/i18n/upluralrules.cpp
icu4c/source/test/cintltst/cpluralrulestest.c
icu4c/source/test/intltest/plurfmts.cpp
icu4c/source/test/intltest/plurfmts.h
icu4c/source/test/intltest/plurults.cpp
icu4c/source/test/intltest/plurults.h
icu4c/source/test/intltest/tmsgfmt.cpp
icu4c/source/test/intltest/tmsgfmt.h

index b9c15f9c14b2e4e852cc7cc1b38dbeceb8b257ae..a1dd02793fca7102e904239b0a7f4bc43808b6c9 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-*   Copyright (C) 2011, International Business Machines
+*   Copyright (C) 2011-2012, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *******************************************************************************
 *   file name:  messagepattern.cpp
@@ -41,10 +41,12 @@ static const UChar u_lessThan=0x3C;
 static const UChar u_equal=0x3D;
 static const UChar u_A=0x41;
 static const UChar u_C=0x43;
+static const UChar u_D=0x44;
 static const UChar u_E=0x45;
 static const UChar u_H=0x48;
 static const UChar u_I=0x49;
 static const UChar u_L=0x4C;
+static const UChar u_N=0x4E;
 static const UChar u_O=0x4F;
 static const UChar u_P=0x50;
 static const UChar u_R=0x52;
@@ -52,13 +54,16 @@ static const UChar u_S=0x53;
 static const UChar u_T=0x54;
 static const UChar u_U=0x55;
 static const UChar u_Z=0x5A;
+static const UChar u__=0x5F;  // '_'
 static const UChar u_a=0x61;
 static const UChar u_c=0x63;
+static const UChar u_d=0x64;
 static const UChar u_e=0x65;
 static const UChar u_f=0x66;
 static const UChar u_h=0x68;
 static const UChar u_i=0x69;
 static const UChar u_l=0x6C;
+static const UChar u_n=0x6E;
 static const UChar u_o=0x6F;
 static const UChar u_p=0x70;
 static const UChar u_r=0x72;
@@ -459,7 +464,7 @@ MessagePattern::parseMessage(int32_t index, int32_t msgStartLength,
                     aposMode==UMSGPAT_APOS_DOUBLE_REQUIRED ||
                     c==u_leftCurlyBrace || c==u_rightCurlyBrace ||
                     (parentType==UMSGPAT_ARG_TYPE_CHOICE && c==u_pipe) ||
-                    (parentType==UMSGPAT_ARG_TYPE_PLURAL && c==u_pound)
+                    (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(parentType) && c==u_pound)
                 ) {
                     // skip the quote-starting apostrophe
                     addPart(UMSGPAT_PART_TYPE_SKIP_SYNTAX, index-1, 1, 0, errorCode);
@@ -494,7 +499,7 @@ MessagePattern::parseMessage(int32_t index, int32_t msgStartLength,
                     needsAutoQuoting=TRUE;
                 }
             }
-        } else if(parentType==UMSGPAT_ARG_TYPE_PLURAL && c==u_pound) {
+        } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(parentType) && c==u_pound) {
             // The unquoted # in a plural message fragment will be replaced
             // with the (number-offset).
             addPart(UMSGPAT_PART_TYPE_REPLACE_NUMBER, index-1, 1, 0, errorCode);
@@ -613,6 +618,10 @@ MessagePattern::parseArg(int32_t index, int32_t argStartLength, int32_t nestingL
             } else if(isSelect(typeIndex)) {
                 argType=UMSGPAT_ARG_TYPE_SELECT;
             }
+        } else if(length==9) {
+            if(isOrdinal(typeIndex)) {
+                argType=UMSGPAT_ARG_TYPE_ORDINAL;
+            }
         }
         // change the ARG_START type from NONE to argType
         partsList->a[argStart].value=(int16_t)argType;
@@ -783,7 +792,7 @@ MessagePattern::parsePluralOrSelectStyle(UMessagePatternArgType argType,
             return index;
         }
         int32_t selectorIndex=index;
-        if(argType==UMSGPAT_ARG_TYPE_PLURAL && msg.charAt(selectorIndex)==u_equal) {
+        if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) && msg.charAt(selectorIndex)==u_equal) {
             // explicit-value plural selector: =double
             index=skipDouble(index+1);
             int32_t length=index-selectorIndex;
@@ -809,7 +818,7 @@ MessagePattern::parsePluralOrSelectStyle(UMessagePatternArgType argType,
                 return 0;
             }
             // Note: The ':' in "offset:" is just beyond the skipIdentifier() range.
-            if( argType==UMSGPAT_ARG_TYPE_PLURAL && length==6 && index<msg.length() &&
+            if( UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) && length==6 && index<msg.length() &&
                 0==msg.compare(selectorIndex, 7, kOffsetColon, 0, 7)
             ) {
                 // plural offset, not a selector
@@ -1060,6 +1069,21 @@ MessagePattern::isSelect(int32_t index) {
         ((c=msg.charAt(index))==u_t || c==u_T);
 }
 
+UBool
+MessagePattern::isOrdinal(int32_t index) {
+    UChar c;
+    return
+        ((c=msg.charAt(index++))==u_p || c==u_P) &&
+        ((c=msg.charAt(index++))==u_l || c==u_L) &&
+        ((c=msg.charAt(index++))==u_o || c==u_O) &&
+        ((c=msg.charAt(index++))==u_r || c==u_R) &&
+        ((c=msg.charAt(index++))==u_d || c==u_D) &&
+        ((c=msg.charAt(index++))==u_i || c==u_I) &&
+        ((c=msg.charAt(index++))==u_n || c==u_N) &&
+        ((c=msg.charAt(index++))==u_a || c==u_A) &&
+        ((c=msg.charAt(index))==u_l || c==u_L);
+}
+
 UBool
 MessagePattern::inMessageFormatPattern(int32_t nestingLevel) {
     return nestingLevel>0 || partsList->a[0].type==UMSGPAT_PART_TYPE_MSG_START;
index 84af565fb59e58311b8dde5006f97eeeb7844790..140a9f6a4786f1b74461f026c36926ebc10892b4 100644 (file)
@@ -233,7 +233,7 @@ enum UMessagePatternArgType {
      */
     UMSGPAT_ARG_TYPE_CHOICE,
     /**
-     * The argument is a PluralFormat with an optional ARG_INT or ARG_DOUBLE offset
+     * The argument is a cardinal-number PluralFormat with an optional ARG_INT or ARG_DOUBLE offset
      * (e.g., offset:1)
      * and one or more (ARG_SELECTOR [explicit-value] message) tuples.
      * If the selector has an explicit value (e.g., =2), then
@@ -246,13 +246,27 @@ enum UMessagePatternArgType {
      * The argument is a SelectFormat with one or more (ARG_SELECTOR, message) pairs.
      * @stable ICU 4.8
      */
-    UMSGPAT_ARG_TYPE_SELECT
+    UMSGPAT_ARG_TYPE_SELECT,
+    /**
+     * The argument is an ordinal-number PluralFormat
+     * with the same style parts sequence and semantics as UMSGPAT_ARG_TYPE_PLURAL.
+     * @draft ICU 50
+     */
+    UMSGPAT_ARG_TYPE_ORDINAL
 };
 /**
  * @stable ICU 4.8
  */
 typedef enum UMessagePatternArgType UMessagePatternArgType;
 
+/**
+ * Returns TRUE if the argument type has a plural style part sequence and semantics,
+ * for example UMSGPAT_ARG_TYPE_PLURAL and UMSGPAT_ARG_TYPE_ORDINAL.
+ * @draft ICU 50
+ */
+#define UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) \
+    ((argType)==UMSGPAT_ARG_TYPE_PLURAL || (argType)==UMSGPAT_ARG_TYPE_ORDINAL)
+
 enum {
     /**
      * Return value from MessagePattern.validateArgumentName() for when
@@ -878,6 +892,8 @@ private:
 
     UBool isSelect(int32_t index);
 
+    UBool isOrdinal(int32_t index);
+
     /**
      * @return TRUE if we are inside a MessageFormat (sub-)pattern,
      *         as opposed to inside a top-level choice/plural/select pattern.
index 67ea7f3816b93ef7dcc8b499191f98ff809c1327..cefd502edcea92a6a3ede10e6b193958aa09eb57 100644 (file)
@@ -179,6 +179,63 @@ plurals:table(nofallback){
         zh{""}
         zu{"set2"}
     }
+    locales_ordinals{
+        af{""}
+        am{""}
+        ar{""}
+        bg{""}
+        bn{"set31"}
+        ca{"set28"}
+        cs{""}
+        da{""}
+        de{""}
+        el{""}
+        en{"set26"}
+        es{""}
+        et{""}
+        eu{""}
+        fa{""}
+        fi{""}
+        fil{"set2"}
+        fr{"set2"}
+        gl{""}
+        gu{"set30"}
+        hi{"set30"}
+        hr{""}
+        hu{"set24"}
+        id{""}
+        is{""}
+        it{"set27"}
+        iw{""}
+        ja{""}
+        kn{""}
+        ko{""}
+        lt{""}
+        lv{""}
+        ml{""}
+        mr{"set29"}
+        ms{"set2"}
+        nl{""}
+        no{""}
+        pl{""}
+        pt{""}
+        ro{"set2"}
+        ru{""}
+        sk{""}
+        sl{""}
+        sr{""}
+        sv{"set25"}
+        sw{""}
+        ta{""}
+        te{""}
+        th{""}
+        tr{""}
+        uk{""}
+        ur{""}
+        vi{"set2"}
+        zh{""}
+        zu{"set32"}
+    }
     rules{
         set1{
             few{"n mod 100 in 3..10"}
@@ -256,9 +313,50 @@ plurals:table(nofallback){
             one{"n in 1,11"}
             two{"n in 2,12"}
         }
+        set24{
+            one{"n in 1,5"}
+        }
+        set25{
+            one{"n mod 10 in 1,2 and n mod 100 not in 11,12"}
+        }
+        set26{
+            few{"n mod 10 is 3 and n mod 100 is not 13"}
+            one{"n mod 10 is 1 and n mod 100 is not 11"}
+            two{"n mod 10 is 2 and n mod 100 is not 12"}
+        }
+        set27{
+            many{"n in 11,8,80,800"}
+        }
+        set28{
+            few{"n is 4"}
+            one{"n in 1,3"}
+            two{"n is 2"}
+        }
+        set29{
+            few{"n is 4"}
+            one{"n is 1"}
+            two{"n in 2,3"}
+        }
         set3{
             one{"n in 0..1"}
         }
+        set30{
+            few{"n is 4"}
+            many{"n is 6"}
+            one{"n is 1"}
+            two{"n in 2,3"}
+        }
+        set31{
+            few{"n is 4"}
+            many{"n is 6"}
+            one{"n in 1,5,7,8,9,10"}
+            two{"n in 2,3"}
+        }
+        set32{
+            few{"n in 2..9"}
+            many{"n in 10..19,100..199,1000..1999"}
+            one{"n is 1"}
+        }
         set4{
             one{"n within 0..2 and n is not 2"}
         }
index 9fcadec0d0d3f87b5e40d5b1da7e96ca0fc8ae5b..dd8eb1eee0bae4fea81a4b362b74b52d582e826a 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 1997-2011, International Business Machines Corporation and
+ * Copyright (c) 1997-2012, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************
  *
@@ -230,7 +230,8 @@ MessageFormat::MessageFormat(const UnicodeString& pattern,
   defaultDateFormat(NULL),
   cachedFormatters(NULL),
   customFormatArgStarts(NULL),
-  pluralProvider(&fLocale)
+  pluralProvider(&fLocale, UPLURAL_TYPE_CARDINAL),
+  ordinalProvider(&fLocale, UPLURAL_TYPE_ORDINAL)
 {
     setLocaleIDs(fLocale.getName(), fLocale.getName());
     applyPattern(pattern, success);
@@ -251,7 +252,8 @@ MessageFormat::MessageFormat(const UnicodeString& pattern,
   defaultDateFormat(NULL),
   cachedFormatters(NULL),
   customFormatArgStarts(NULL),
-  pluralProvider(&fLocale)
+  pluralProvider(&fLocale, UPLURAL_TYPE_CARDINAL),
+  ordinalProvider(&fLocale, UPLURAL_TYPE_ORDINAL)
 {
     setLocaleIDs(fLocale.getName(), fLocale.getName());
     applyPattern(pattern, success);
@@ -273,7 +275,8 @@ MessageFormat::MessageFormat(const UnicodeString& pattern,
   defaultDateFormat(NULL),
   cachedFormatters(NULL),
   customFormatArgStarts(NULL),
-  pluralProvider(&fLocale)
+  pluralProvider(&fLocale, UPLURAL_TYPE_CARDINAL),
+  ordinalProvider(&fLocale, UPLURAL_TYPE_ORDINAL)
 {
     setLocaleIDs(fLocale.getName(), fLocale.getName());
     applyPattern(pattern, parseError, success);
@@ -294,7 +297,8 @@ MessageFormat::MessageFormat(const MessageFormat& that)
   defaultDateFormat(NULL),
   cachedFormatters(NULL),
   customFormatArgStarts(NULL),
-  pluralProvider(&fLocale)
+  pluralProvider(&fLocale, UPLURAL_TYPE_CARDINAL),
+  ordinalProvider(&fLocale, UPLURAL_TYPE_ORDINAL)
 {
     // This will take care of creating the hash tables (since they are NULL).
     UErrorCode ec = U_ZERO_ERROR;
@@ -438,6 +442,7 @@ MessageFormat::setLocale(const Locale& theLocale)
         fLocale = theLocale;
         setLocaleIDs(fLocale.getName(), fLocale.getName());
         pluralProvider.reset(&fLocale);
+        ordinalProvider.reset(&fLocale);
     }
 }
 
@@ -1057,15 +1062,17 @@ void MessageFormat::format(int32_t msgStart, double pluralNumber,
             int32_t subMsgStart = ChoiceFormat::findSubMessage(msgPattern, i, number);
             formatComplexSubMessage(subMsgStart, 0, arguments, argumentNames,
                                     cnt, appendTo, success);
-        } else if (argType == UMSGPAT_ARG_TYPE_PLURAL) {
+        } else if (UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType)) {
             if (!arg->isNumeric()) {
                 success = U_ILLEGAL_ARGUMENT_ERROR;
                 return;
             }
+            const PluralFormat::PluralSelector &selector =
+                argType == UMSGPAT_ARG_TYPE_PLURAL ? pluralProvider : ordinalProvider;
             // We must use the Formattable::getDouble() variant with the UErrorCode parameter
             // because only this one converts non-double numeric types to double.
             double number = arg->getDouble(success);
-            int32_t subMsgStart = PluralFormat::findSubMessage(msgPattern, i, pluralProvider, number,
+            int32_t subMsgStart = PluralFormat::findSubMessage(msgPattern, i, selector, number,
                                                                success);
             double offset = msgPattern.getPluralOffset(i);
             formatComplexSubMessage(subMsgStart, number-offset, arguments, argumentNames,
@@ -1345,7 +1352,7 @@ MessageFormat::parse(int32_t msgStart,
             argResult.setDouble(choiceResult);
             haveArgResult = TRUE;
             sourceOffset = tempStatus.getIndex();
-        } else if(argType==UMSGPAT_ARG_TYPE_PLURAL || argType==UMSGPAT_ARG_TYPE_SELECT) {
+        } else if(UMSGPAT_ARG_TYPE_HAS_PLURAL_STYLE(argType) || argType==UMSGPAT_ARG_TYPE_SELECT) {
             // Parsing not supported.
             ec = U_UNSUPPORTED_ERROR;
             return NULL;
@@ -1524,6 +1531,7 @@ void MessageFormat::cacheExplicitFormats(UErrorCode& status) {
         }
         case UMSGPAT_ARG_TYPE_CHOICE:
         case UMSGPAT_ARG_TYPE_PLURAL:
+        case UMSGPAT_ARG_TYPE_ORDINAL:
             formattableType = Formattable::kDouble;
             break;
         case UMSGPAT_ARG_TYPE_SELECT:
@@ -1770,8 +1778,8 @@ FormatNameEnumeration::~FormatNameEnumeration() {
 }
 
 
-MessageFormat::PluralSelectorProvider::PluralSelectorProvider(const Locale* loc)
-        : locale(loc), rules(NULL) {
+MessageFormat::PluralSelectorProvider::PluralSelectorProvider(const Locale* loc, UPluralType t)
+        : locale(loc), rules(NULL), type(t) {
 }
 
 MessageFormat::PluralSelectorProvider::~PluralSelectorProvider() {
@@ -1785,7 +1793,7 @@ UnicodeString MessageFormat::PluralSelectorProvider::select(double number, UErro
     }
     MessageFormat::PluralSelectorProvider* t = const_cast<MessageFormat::PluralSelectorProvider*>(this);
     if(rules == NULL) {
-        t->rules = PluralRules::forLocale(*locale, ec);
+        t->rules = PluralRules::forLocale(*locale, type, ec);
         if (U_FAILURE(ec)) {
             return UnicodeString(FALSE, OTHER_STRING, 5);
         }
index 510b832453e8d4bd9f24159293cf5fa899eaa1a4..22f6939d43e08fdaecfb1bc7fea6d51f9caaa8ad 100644 (file)
@@ -37,7 +37,7 @@ PluralFormat::PluralFormat(UErrorCode& status)
           msgPattern(status),
           numberFormat(NULL),
           offset(0) {
-    init(NULL, status);
+    init(NULL, UPLURAL_TYPE_CARDINAL, status);
 }
 
 PluralFormat::PluralFormat(const Locale& loc, UErrorCode& status)
@@ -45,7 +45,7 @@ PluralFormat::PluralFormat(const Locale& loc, UErrorCode& status)
           msgPattern(status),
           numberFormat(NULL),
           offset(0) {
-    init(NULL, status);
+    init(NULL, UPLURAL_TYPE_CARDINAL, status);
 }
 
 PluralFormat::PluralFormat(const PluralRules& rules, UErrorCode& status)
@@ -53,7 +53,7 @@ PluralFormat::PluralFormat(const PluralRules& rules, UErrorCode& status)
           msgPattern(status),
           numberFormat(NULL),
           offset(0) {
-    init(&rules, status);
+    init(&rules, UPLURAL_TYPE_COUNT, status);
 }
 
 PluralFormat::PluralFormat(const Locale& loc,
@@ -63,7 +63,17 @@ PluralFormat::PluralFormat(const Locale& loc,
           msgPattern(status),
           numberFormat(NULL),
           offset(0) {
-    init(&rules, status);
+    init(&rules, UPLURAL_TYPE_COUNT, status);
+}
+
+PluralFormat::PluralFormat(const Locale& loc,
+                           UPluralType type,
+                           UErrorCode& status)
+        : locale(loc),
+          msgPattern(status),
+          numberFormat(NULL),
+          offset(0) {
+    init(NULL, type, status);
 }
 
 PluralFormat::PluralFormat(const UnicodeString& pat,
@@ -72,7 +82,7 @@ PluralFormat::PluralFormat(const UnicodeString& pat,
           msgPattern(status),
           numberFormat(NULL),
           offset(0) {
-    init(NULL, status);
+    init(NULL, UPLURAL_TYPE_CARDINAL, status);
     applyPattern(pat, status);
 }
 
@@ -83,7 +93,7 @@ PluralFormat::PluralFormat(const Locale& loc,
           msgPattern(status),
           numberFormat(NULL),
           offset(0) {
-    init(NULL, status);
+    init(NULL, UPLURAL_TYPE_CARDINAL, status);
     applyPattern(pat, status);
 }
 
@@ -94,7 +104,7 @@ PluralFormat::PluralFormat(const PluralRules& rules,
           msgPattern(status),
           numberFormat(NULL),
           offset(0) {
-    init(&rules, status);
+    init(&rules, UPLURAL_TYPE_COUNT, status);
     applyPattern(pat, status);
 }
 
@@ -106,7 +116,19 @@ PluralFormat::PluralFormat(const Locale& loc,
           msgPattern(status),
           numberFormat(NULL),
           offset(0) {
-    init(&rules, status);
+    init(&rules, UPLURAL_TYPE_COUNT, status);
+    applyPattern(pat, status);
+}
+
+PluralFormat::PluralFormat(const Locale& loc,
+                           UPluralType type,
+                           const UnicodeString& pat,
+                           UErrorCode& status)
+        : locale(loc),
+          msgPattern(status),
+          numberFormat(NULL),
+          offset(0) {
+    init(NULL, type, status);
     applyPattern(pat, status);
 }
 
@@ -147,13 +169,13 @@ PluralFormat::~PluralFormat() {
 }
 
 void
-PluralFormat::init(const PluralRules* rules, UErrorCode& status) {
+PluralFormat::init(const PluralRules* rules, UPluralType type, UErrorCode& status) {
     if (U_FAILURE(status)) {
         return;
     }
 
     if (rules==NULL) {
-        pluralRulesWrapper.pluralRules = PluralRules::forLocale(locale, status);
+        pluralRulesWrapper.pluralRules = PluralRules::forLocale(locale, type, status);
     } else {
         pluralRulesWrapper.pluralRules = rules->clone();
         if (pluralRulesWrapper.pluralRules == NULL) {
@@ -278,7 +300,7 @@ PluralFormat::setLocale(const Locale& loc, UErrorCode& status) {
     offset = 0;
     numberFormat = NULL;
     pluralRulesWrapper.reset();
-    init(NULL, status);
+    init(NULL, UPLURAL_TYPE_CARDINAL, status);
 }
 
 void
index ba9b9bd4488e66ba7b30c1f2adde9d2246b27a9d..e343fef14811f87cd4b526ae5d10ed165d0430b6 100644 (file)
@@ -1,21 +1,16 @@
 /*
 *******************************************************************************
-* Copyright (C) 2007-2011, International Business Machines Corporation and
+* Copyright (C) 2007-2012, International Business Machines Corporation and
 * others. All Rights Reserved.
 *******************************************************************************
 *
-* File PLURRULE.CPP
-*
-* Modification History:
-*
-*   Date        Name        Description
-*******************************************************************************
+* File plurrule.cpp
 */
 
-
 #include "unicode/utypes.h"
 #include "unicode/localpointer.h"
 #include "unicode/plurrule.h"
+#include "unicode/upluralrules.h"
 #include "unicode/ures.h"
 #include "cmemory.h"
 #include "cstring.h"
@@ -146,16 +141,25 @@ PluralRules::createDefaultRules(UErrorCode& status) {
 
 PluralRules* U_EXPORT2
 PluralRules::forLocale(const Locale& locale, UErrorCode& status) {
+    return forLocale(locale, UPLURAL_TYPE_CARDINAL, status);
+}
+
+PluralRules* U_EXPORT2
+PluralRules::forLocale(const Locale& locale, UPluralType type, UErrorCode& status) {
     RuleChain   rChain;
     if (U_FAILURE(status)) {
         return NULL;
     }
+    if (type >= UPLURAL_TYPE_COUNT) {
+        status = U_ILLEGAL_ARGUMENT_ERROR;
+        return NULL;
+    }
     PluralRules *newObj = new PluralRules(status);
     if (newObj==NULL || U_FAILURE(status)) {
         delete newObj;
         return NULL;
     }
-    UnicodeString locRule = newObj->getRuleFromResource(locale, status);
+    UnicodeString locRule = newObj->getRuleFromResource(locale, type, status);
     if ((locRule.length() != 0) && U_SUCCESS(status)) {
         newObj->parseDescription(locRule, rChain, status);
         if (U_SUCCESS(status)) {
@@ -660,25 +664,36 @@ PluralRules::addRules(RuleChain& rules) {
 }
 
 UnicodeString
-PluralRules::getRuleFromResource(const Locale& locale, UErrorCode& errCode) {
+PluralRules::getRuleFromResource(const Locale& locale, UPluralType type, UErrorCode& errCode) {
     UnicodeString emptyStr;
 
     if (U_FAILURE(errCode)) {
         return emptyStr;
     }
-    UResourceBundle *rb=ures_openDirect(NULL, "plurals", &errCode);
+    LocalUResourceBundlePointer rb(ures_openDirect(NULL, "plurals", &errCode));
     if(U_FAILURE(errCode)) {
-        /* total failure, not even root could be opened */
         return emptyStr;
     }
-    UResourceBundle *locRes=ures_getByKey(rb, "locales", NULL, &errCode);
+    const char *typeKey;
+    switch (type) {
+    case UPLURAL_TYPE_CARDINAL:
+        typeKey = "locales";
+        break;
+    case UPLURAL_TYPE_ORDINAL:
+        typeKey = "locales_ordinals";
+        break;
+    default:
+        // Must not occur: The caller should have checked for valid types.
+        errCode = U_ILLEGAL_ARGUMENT_ERROR;
+        return emptyStr;
+    }
+    LocalUResourceBundlePointer locRes(ures_getByKey(rb.getAlias(), typeKey, NULL, &errCode));
     if(U_FAILURE(errCode)) {
-        ures_close(rb);
         return emptyStr;
     }
     int32_t resLen=0;
     const char *curLocaleName=locale.getName();
-    const UChar* s = ures_getStringByKey(locRes, curLocaleName, &resLen, &errCode);
+    const UChar* s = ures_getStringByKey(locRes.getAlias(), curLocaleName, &resLen, &errCode);
 
     if (s == NULL) {
         // Check parent locales.
@@ -691,7 +706,7 @@ PluralRules::getRuleFromResource(const Locale& locale, UErrorCode& errCode) {
         while ((localeNameLen=uloc_getParent(parentLocaleName, parentLocaleName,
                                        ULOC_FULLNAME_CAPACITY, &status)) > 0) {
             resLen=0;
-            s = ures_getStringByKey(locRes, parentLocaleName, &resLen, &status);
+            s = ures_getStringByKey(locRes.getAlias(), parentLocaleName, &resLen, &status);
             if (s != NULL) {
                 errCode = U_ZERO_ERROR;
                 break;
@@ -700,8 +715,6 @@ PluralRules::getRuleFromResource(const Locale& locale, UErrorCode& errCode) {
         }
     }
     if (s==NULL) {
-        ures_close(locRes);
-        ures_close(rb);
         return emptyStr;
     }
 
@@ -711,28 +724,23 @@ PluralRules::getRuleFromResource(const Locale& locale, UErrorCode& errCode) {
     // printf("\n PluralRule: %s\n", setKey);
 
 
-    UResourceBundle *ruleRes=ures_getByKey(rb, "rules", NULL, &errCode);
+    LocalUResourceBundlePointer ruleRes(ures_getByKey(rb.getAlias(), "rules", NULL, &errCode));
     if(U_FAILURE(errCode)) {
-        ures_close(locRes);
-        ures_close(rb);
         return emptyStr;
     }
     resLen=0;
-    UResourceBundle *setRes = ures_getByKey(ruleRes, setKey, NULL, &errCode);
+    LocalUResourceBundlePointer setRes(ures_getByKey(ruleRes.getAlias(), setKey, NULL, &errCode));
     if (U_FAILURE(errCode)) {
-        ures_close(ruleRes);
-        ures_close(locRes);
-        ures_close(rb);
         return emptyStr;
     }
 
-    int32_t numberKeys = ures_getSize(setRes);
+    int32_t numberKeys = ures_getSize(setRes.getAlias());
     char *key=NULL;
     int32_t len=0;
     for(int32_t i=0; i<numberKeys; ++i) {
         int32_t keyLen;
         resLen=0;
-        s=ures_getNextString(setRes, &resLen, (const char**)&key, &errCode);
+        s=ures_getNextString(setRes.getAlias(), &resLen, (const char**)&key, &errCode);
         keyLen = (int32_t)uprv_strlen(key);
         u_charsToUChars(key, result+len, keyLen);
         len += keyLen;
@@ -745,10 +753,6 @@ PluralRules::getRuleFromResource(const Locale& locale, UErrorCode& errCode) {
     u_UCharsToChars(result, setKey, len);
     // printf(" Rule: %s\n", setKey);
 
-    ures_close(setRes);
-    ures_close(ruleRes);
-    ures_close(locRes);
-    ures_close(rb);
     return UnicodeString(result);
 }
 
index 54692b7b3d51f4cc5765168ccd3a05f4221a9121..0c93305feaeff064c823be034aa6cf1351f73865 100644 (file)
@@ -104,12 +104,13 @@ class NumberFormat;
  * <pre>
  * message = messageText (argument messageText)*
  * argument = noneArg | simpleArg | complexArg
- * complexArg = choiceArg | pluralArg | selectArg
+ * complexArg = choiceArg | pluralArg | ordinalArg | selectArg
  *
  * noneArg = '{' argNameOrNumber '}'
  * simpleArg = '{' argNameOrNumber ',' argType [',' argStyle] '}'
  * choiceArg = '{' argNameOrNumber ',' "choice" ',' choiceStyle '}'
  * pluralArg = '{' argNameOrNumber ',' "plural" ',' pluralStyle '}'
+ * ordinalArg = '{' argNameOrNumber ',' "plordinal" ',' pluralStyle '}'
  * selectArg = '{' argNameOrNumber ',' "select" ',' selectStyle '}'
  *
  * choiceStyle: see {@link ChoiceFormat}
@@ -892,7 +893,7 @@ private:
       */
     class U_I18N_API PluralSelectorProvider : public PluralFormat::PluralSelector {
     public:
-        PluralSelectorProvider(const Locale* loc);
+        PluralSelectorProvider(const Locale* loc, UPluralType type);
         virtual ~PluralSelectorProvider();
         virtual UnicodeString select(double number, UErrorCode& ec) const;
 
@@ -900,6 +901,7 @@ private:
     private:
         const Locale* locale;
         PluralRules* rules;
+        UPluralType type;
     };
 
     /**
@@ -938,6 +940,7 @@ private:
     UHashtable* customFormatArgStarts;
 
     PluralSelectorProvider pluralProvider;
+    PluralSelectorProvider ordinalProvider;
 
     /**
      * Method to retrieve default formats (or NULL on failure).
index a5fd7ab2fc61cb78330dab2f43ed00227453dd12..be3152ba3f619cd7b2967c414e537f206ab362eb 100644 (file)
@@ -148,7 +148,7 @@ class U_I18N_API PluralFormat : public Format {
 public:
 
     /**
-     * Creates a new <code>PluralFormat</code> for the default locale.
+     * Creates a new cardinal-number <code>PluralFormat</code> for the default locale.
      * This locale will be used to get the set of plural rules and for standard
      * number formatting.
      * @param status  output param set to success/failure code on exit, which
@@ -158,7 +158,7 @@ public:
     PluralFormat(UErrorCode& status);
 
     /**
-     * Creates a new <code>PluralFormat</code> for a given locale.
+     * Creates a new cardinal-number <code>PluralFormat</code> for a given locale.
      * @param locale the <code>PluralFormat</code> will be configured with
      *               rules for this locale. This locale will also be used for
      *               standard number formatting.
@@ -193,7 +193,19 @@ public:
     PluralFormat(const Locale& locale, const PluralRules& rules, UErrorCode& status);
 
     /**
-     * Creates a new <code>PluralFormat</code> for a given pattern string.
+     * Creates a new <code>PluralFormat</code> for the plural type.
+     * The standard number formatting will be done using the given locale.
+     * @param locale  the default number formatting will be done using this
+     *                locale.
+     * @param type    The plural type (e.g., cardinal or ordinal).
+     * @param status  output param set to success/failure code on exit, which
+     *                must not indicate a failure before the function call.
+     * @draft ICU 50
+     */
+    PluralFormat(const Locale& locale, UPluralType type, UErrorCode& status);
+
+    /**
+     * Creates a new cardinal-number <code>PluralFormat</code> for a given pattern string.
      * The default locale will be used to get the set of plural rules and for
      * standard number formatting.
      * @param  pattern the pattern for this <code>PluralFormat</code>.
@@ -205,7 +217,7 @@ public:
     PluralFormat(const UnicodeString& pattern, UErrorCode& status);
 
     /**
-     * Creates a new <code>PluralFormat</code> for a given pattern string and
+     * Creates a new cardinal-number <code>PluralFormat</code> for a given pattern string and
      * locale.
      * The locale will be used to get the set of plural rules and for
      * standard number formatting.
@@ -254,6 +266,24 @@ public:
                  const UnicodeString& pattern,
                  UErrorCode& status);
 
+    /**
+     * Creates a new <code>PluralFormat</code> for a plural type, a
+     * pattern and a locale.
+     * @param locale  the <code>PluralFormat</code> will be configured with
+     *                rules for this locale. This locale will also be used for
+     *                standard number formatting.
+     * @param type    The plural type (e.g., cardinal or ordinal).
+     * @param pattern the pattern for this <code>PluralFormat</code>.
+     *                errors are returned to status if the pattern is invalid.
+     * @param status  output param set to success/failure code on exit, which
+     *                must not indicate a failure before the function call.
+     * @draft ICU 50
+     */
+    PluralFormat(const Locale& locale,
+                 UPluralType type,
+                 const UnicodeString& pattern,
+                 UErrorCode& status);
+
     /**
       * copy constructor.
       * @stable ICU 4.0
@@ -359,7 +389,7 @@ public:
      *     i.e., a pattern that was applied previously will be removed,
      *     and the NumberFormat is set to the default number format for
      *     the locale.  The resulting format behaves the same as one
-     *     constructed from {@link #PluralFormat(const Locale& locale, UErrorCode& status)}.
+     *     constructed from {@link #PluralFormat(const Locale& locale, UPLURAL_TYPE_CARDINAL, UErrorCode& status)}.
      * @param locale  the <code>locale</code> to use to configure the formatter.
      * @param status  output param set to success/failure code on exit, which
      *                must not indicate a failure before the function call.
@@ -532,7 +562,7 @@ private:
     PluralSelectorAdapter pluralRulesWrapper;
 
     PluralFormat();   // default constructor not implemented
-    void init(const PluralRules* rules, UErrorCode& status);
+    void init(const PluralRules* rules, UPluralType type, UErrorCode& status);
     /**
      * Copies dynamically allocated values (pointer fields).
      * Others are copied using their copy constructors and assignment operators.
index 7321133e90f56aefe547f07bcb4d2aef4cdb02c2..5a227a21785ab9d7b723cbf8fd7b973cbd0b9f65 100644 (file)
@@ -26,6 +26,7 @@
 #if !UCONFIG_NO_FORMATTING
 
 #include "unicode/format.h"
+#include "unicode/upluralrules.h"
 
 /**
  * Value returned by PluralRules::getUniqueKeywordValue() when there is no
@@ -183,8 +184,9 @@ public:
     static PluralRules* U_EXPORT2 createDefaultRules(UErrorCode& status);
 
     /**
-     * Provides access to the predefined <code>PluralRules</code> for a given
+     * Provides access to the predefined cardinal-number <code>PluralRules</code> for a given
      * locale.
+     * Same as forLocale(locale, UPLURAL_TYPE_CARDINAL, status).
      *
      * @param locale  The locale for which a <code>PluralRules</code> object is
      *                returned.
@@ -199,6 +201,24 @@ public:
      */
     static PluralRules* U_EXPORT2 forLocale(const Locale& locale, UErrorCode& status);
 
+    /**
+     * Provides access to the predefined <code>PluralRules</code> for a given
+     * locale and the plural type.
+     *
+     * @param locale  The locale for which a <code>PluralRules</code> object is
+     *                returned.
+     * @param type    The plural type (e.g., cardinal or ordinal).
+     * @param status  Output param set to success/failure code on exit, which
+     *                must not indicate a failure before the function call.
+     * @return        The predefined <code>PluralRules</code> object pointer for
+     *                this locale. If there's no predefined rules for this locale,
+     *                the rules for the closest parent in the locale hierarchy
+     *                that has one will  be returned.  The final fallback always
+     *                returns the default 'other' rules.
+     * @draft ICU 50
+     */
+    static PluralRules* U_EXPORT2 forLocale(const Locale& locale, UPluralType type, UErrorCode& status);
+
     /**
      * Given a number, returns the keyword of the first rule that applies to
      * the number.  This function can be used with isKeyword* functions to
@@ -359,7 +379,7 @@ private:
     void getNextLocale(const UnicodeString& localeData, int32_t* curIndex, UnicodeString& localeName);
     void addRules(RuleChain& rules);
     int32_t getNumberValue(const UnicodeString& token) const;
-    UnicodeString getRuleFromResource(const Locale& locale, UErrorCode& status);
+    UnicodeString getRuleFromResource(const Locale& locale, UPluralType type, UErrorCode& status);
 
     static const int32_t MAX_SAMPLES = 3;
 
index 35cb4319041e9a3b7757e9616ea32c8b5ba1fb4d..f6adcf54249cebbdbe8d02312d2214fd397f92df 100644 (file)
  * http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html
  */
 
+/**
+ * Type of plurals and PluralRules.
+ * @draft ICU 50
+ */
+enum UPluralType {
+    /**
+     * Plural rules for cardinal numbers: 1 file vs. 2 files.
+     * @draft ICU 50
+     */
+    UPLURAL_TYPE_CARDINAL,
+    /**
+     * Plural rules for ordinal numbers: 1st file, 2nd file, 3rd file, 4th file, etc.
+     * @draft ICU 50
+     */
+    UPLURAL_TYPE_ORDINAL,
+    /**
+     * Number of Plural rules types.
+     * @draft ICU 50
+     */
+    UPLURAL_TYPE_COUNT
+};
+/**
+ * @draft ICU 50
+ */
+typedef enum UPluralType UPluralType;
+
 /**
  * Opaque UPluralRules object for use in C programs.
  * @stable ICU 4.8
@@ -45,19 +71,31 @@ struct UPluralRules;
 typedef struct UPluralRules UPluralRules;  /**< C typedef for struct UPluralRules. @stable ICU 4.8 */
 
 /**
- * Open a new UPluralRules object using the predefined plural rules for a
+ * Opens a new UPluralRules object using the predefined cardinal-number plural rules for a
  * given locale.
+ * Same as uplrules_openForType(locale, UPLURAL_TYPE_CARDINAL, status).
  * @param locale The locale for which the rules are desired.
  * @param status A pointer to a UErrorCode to receive any errors.
- * @return A UPluralRules for the specified locale, or 0 if an error occurred.
+ * @return A UPluralRules for the specified locale, or NULL if an error occurred.
  * @stable ICU 4.8
  */
 U_DRAFT UPluralRules* U_EXPORT2
-uplrules_open(const char *locale,
-             UErrorCode *status);
+uplrules_open(const char *locale, UErrorCode *status);
+
+/**
+ * Opens a new UPluralRules object using the predefined plural rules for a
+ * given locale and the plural type.
+ * @param locale The locale for which the rules are desired.
+ * @param type The plural type (e.g., cardinal or ordinal).
+ * @param status A pointer to a UErrorCode to receive any errors.
+ * @return A UPluralRules for the specified locale, or NULL if an error occurred.
+ * @draft ICU 50
+ */
+U_DRAFT UPluralRules* U_EXPORT2
+uplrules_openForType(const char *locale, UPluralType type, UErrorCode *status);
 
 /**
- * Close a UPluralRules object. Once closed it may no longer be used.
+ * Closes a UPluralRules object. Once closed it may no longer be used.
  * @param uplrules The UPluralRules object to close.
  * @stable ICU 4.8
  */
index 5e95125c3f41121ec2d0807a5ee4545fa1fbf1d4..1e92c8840f30a9b9cf13039000d9ca2cc8d7b9b8 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *****************************************************************************************
-* Copyright (C) 2010-2011, International Business Machines
+* Copyright (C) 2010-2012, International Business Machines
 * Corporation and others. All Rights Reserved.
 *****************************************************************************************
 */
@@ -18,10 +18,15 @@ U_NAMESPACE_USE
 
 
 U_CAPI UPluralRules* U_EXPORT2
-uplrules_open(const char *locale,
-              UErrorCode *status)
+uplrules_open(const char *locale, UErrorCode *status)
 {
-    return (UPluralRules*)PluralRules::forLocale(Locale(locale), *status);
+    return uplrules_openForType(locale, UPLURAL_TYPE_CARDINAL, status);
+}
+
+U_CAPI UPluralRules* U_EXPORT2
+uplrules_openForType(const char *locale, UPluralType type, UErrorCode *status)
+{
+    return (UPluralRules*)PluralRules::forLocale(Locale(locale), type, *status);
 }
 
 U_CAPI void U_EXPORT2
index 7b12fadd9f177ae04927874e0f46a0a9f02469ea..be08e31e021c96c2d2cb717e79e57e15717bc792 100644 (file)
@@ -1,5 +1,5 @@
 /********************************************************************
- * Copyright (c) 2011, International Business Machines Corporation
+ * Copyright (c) 2011-2012, International Business Machines Corporation
  * and others. All Rights Reserved.
  ********************************************************************/
 /* C API TEST FOR PLURAL RULES */
@@ -14,6 +14,7 @@
 #include "cmemory.h"
 
 static void TestPluralRules(void);
+static void TestOrdinalRules(void);
 
 void addPluralRulesTest(TestNode** root);
 
@@ -22,6 +23,7 @@ void addPluralRulesTest(TestNode** root);
 void addPluralRulesTest(TestNode** root)
 {
     TESTCASE(TestPluralRules);
+    TESTCASE(TestOrdinalRules);
 }
 
 typedef struct {
@@ -89,4 +91,22 @@ static void TestPluralRules()
     }
 }
 
+static void TestOrdinalRules() {
+    U_STRING_DECL(two, "two", 3);
+    UChar keyword[8];
+    int32_t length;
+    UErrorCode errorCode = U_ZERO_ERROR;
+    UPluralRules* upr = uplrules_openForType("en", UPLURAL_TYPE_ORDINAL, &errorCode);
+    if (U_FAILURE(errorCode)) {
+        log_err("uplrules_openForType(en, ordinal) failed - %s\n", u_errorName(errorCode));
+        return;
+    }
+    U_STRING_INIT(two, "two", 3);
+    length = uplrules_select(upr, 2., keyword, 8, &errorCode);
+    if (U_FAILURE(errorCode) || u_strCompare(keyword, length, two, 3, FALSE) != 0) {
+        log_err("uplrules_select(en-ordinal, 2) failed - %s\n", u_errorName(errorCode));
+    }
+    uplrules_close(upr);
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index b45b262134969620705ff90e12f2ac94bfa8ca75..f653b2fae832c64966b5be57393592da0a01e980 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 2007-2011, International Business Machines Corporation and
+ * Copyright (c) 2007-2012, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 
 void PluralFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
 {
     if (exec) logln("TestSuite PluralFormat");
-    switch (index) {
-        TESTCASE(0, pluralFormatBasicTest);
-        TESTCASE(1, pluralFormatUnitTest);
-        TESTCASE(2, pluralFormatLocaleTest);
-        TESTCASE(3, pluralFormatExtendedTest);
-        TESTCASE(4, pluralFormatExtendedParseTest);
-        default: name = "";
-            break;
-    }
+    TESTCASE_AUTO_BEGIN;
+    TESTCASE_AUTO(pluralFormatBasicTest);
+    TESTCASE_AUTO(pluralFormatUnitTest);
+    TESTCASE_AUTO(pluralFormatLocaleTest);
+    TESTCASE_AUTO(pluralFormatExtendedTest);
+    TESTCASE_AUTO(pluralFormatExtendedParseTest);
+    TESTCASE_AUTO(ordinalFormatTest);
+    TESTCASE_AUTO_END;
 }
 
 /**
@@ -319,7 +318,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
     UnicodeString testPattern = UNICODE_STRING_SIMPLE("other{other}");
     uprv_memset(pluralResults, -1, sizeof(pluralResults));
     pluralResults[0]= PFT_OTHER; // other
-    helperTestRusults(oneRuleLocales, 4, testPattern, pluralResults);
+    helperTestResults(oneRuleLocales, 4, testPattern, pluralResults);
     
     // ====== Test Singular1 locales.
     logln("Testing singular1 locales.");
@@ -332,7 +331,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
     pluralResults[0]= PFT_OTHER;
     pluralResults[1]= PFT_ONE;
     pluralResults[2]= PFT_OTHER;
-    helperTestRusults(singular1Locales, 52, testPattern, pluralResults);
+    helperTestResults(singular1Locales, 52, testPattern, pluralResults);
     
     // ======== Test Singular01 locales.
     logln("Testing singular1 locales.");
@@ -341,7 +340,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
     uprv_memset(pluralResults, -1, sizeof(pluralResults));
     pluralResults[0]= PFT_ONE;
     pluralResults[2]= PFT_OTHER;
-    helperTestRusults(singular01Locales, 3, testPattern, pluralResults);
+    helperTestResults(singular01Locales, 3, testPattern, pluralResults);
     
     // ======== Test ZeroSingular locales.
     logln("Testing singular1 locales.");
@@ -356,7 +355,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
         pluralResults[i*10+1] = PFT_ONE;
         pluralResults[i*10+2] = PFT_OTHER;
     }
-    helperTestRusults(zeroSingularLocales, 1, testPattern, pluralResults);
+    helperTestResults(zeroSingularLocales, 1, testPattern, pluralResults);
     
     // ======== Test singular dual locales.
     logln("Testing singular1 locales.");
@@ -367,7 +366,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
     pluralResults[1]= PFT_ONE;
     pluralResults[2]= PFT_TWO;
     pluralResults[3]= PFT_OTHER;
-    helperTestRusults(singularDualLocales, 1, testPattern, pluralResults);
+    helperTestResults(singularDualLocales, 1, testPattern, pluralResults);
     
     // ======== Test Singular Zero Some locales.
     logln("Testing singular1 locales.");
@@ -381,7 +380,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
         pluralResults[100+i] = PFT_FEW;
     }
     pluralResults[1]= PFT_ONE;
-    helperTestRusults(singularZeroSomeLocales, 1, testPattern, pluralResults);
+    helperTestResults(singularZeroSomeLocales, 1, testPattern, pluralResults);
     
     // ======== Test Special 12/19.
     logln("Testing special 12 and 19.");
@@ -398,7 +397,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
         pluralResults[i*10+2] = PFT_FEW;
         pluralResults[(i+1)*10] = PFT_OTHER;
     }
-    helperTestRusults(special12_19Locales, 1, testPattern, pluralResults);
+    helperTestResults(special12_19Locales, 1, testPattern, pluralResults);
     
     // ======== Test Paucal Except 11 14.
     logln("Testing Paucal Except 11 and 14.");
@@ -423,7 +422,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
         pluralResults[i*10+8] = PFT_MANY;
         pluralResults[i*10+9] = PFT_MANY;
     }
-    helperTestRusults(paucal01Locales, 4, testPattern, pluralResults);
+    helperTestResults(paucal01Locales, 4, testPattern, pluralResults);
     
     // ======== Test Singular Paucal.
     logln("Testing Singular Paucal.");
@@ -434,7 +433,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
     pluralResults[1]= PFT_ONE;
     pluralResults[2]= PFT_FEW;
     pluralResults[5]= PFT_OTHER;
-    helperTestRusults(singularPaucalLocales, 2, testPattern, pluralResults);
+    helperTestResults(singularPaucalLocales, 2, testPattern, pluralResults);
 
     // ======== Test Paucal (1), (2,3,4).
     logln("Testing Paucal (1), (2,3,4).");
@@ -457,7 +456,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
             pluralResults[i*10+5] = PFT_OTHER;
         }
     }
-    helperTestRusults(paucal02Locales, 1, testPattern, pluralResults);
+    helperTestResults(paucal02Locales, 1, testPattern, pluralResults);
     
     // ======== Test Paucal (1), (2), (3,4).
     logln("Testing Paucal (1), (2), (3,4).");
@@ -473,7 +472,7 @@ PluralFormatTest::pluralFormatLocaleTest(/*char *par*/)
     pluralResults[102]= PFT_TWO;
     pluralResults[103]= PFT_FEW;
     pluralResults[105]= PFT_OTHER;
-    helperTestRusults(paucal03Locales, 1, testPattern, pluralResults);
+    helperTestResults(paucal03Locales, 1, testPattern, pluralResults);
     
     // TODO: move this test to Unit Test after CLDR 1.6 is final and we support float
     // ======= Test French "WITHIN rule
@@ -580,6 +579,48 @@ PluralFormatTest::pluralFormatExtendedParseTest(void) {
   }
 }
 
+void
+PluralFormatTest::ordinalFormatTest(void) {
+    IcuTestErrorCode errorCode(*this, "ordinalFormatTest");
+    UnicodeString pattern("one{#st file}two{#nd file}few{#rd file}other{#th file}");
+    PluralFormat pf(Locale::getEnglish(), UPLURAL_TYPE_ORDINAL, pattern, errorCode);
+    if (errorCode.logIfFailureAndReset("PluralFormat(en, UPLURAL_TYPE_ORDINAL, pattern) failed")) {
+      return;
+    }
+    UnicodeString result = pf.format(321, errorCode);
+    if (!errorCode.logIfFailureAndReset("PluralFormat.format(321) failed") &&
+        result != UNICODE_STRING_SIMPLE("321st file")) {
+      errln(UnicodeString("PluralFormat.format(321) wrong result string: ") + result);
+    }
+    result = pf.format(22, errorCode);
+    if (!errorCode.logIfFailureAndReset("PluralFormat.format(22) failed") &&
+        result != UNICODE_STRING_SIMPLE("22nd file")) {
+      errln(UnicodeString("PluralFormat.format(22) wrong result string: ") + result);
+    }
+    result = pf.format(3, errorCode);
+    if (!errorCode.logIfFailureAndReset("PluralFormat.format(3) failed") &&
+        result != UNICODE_STRING_SIMPLE("3rd file")) {
+      errln(UnicodeString("PluralFormat.format(3) wrong result string: ") + result);
+    }
+
+    // Code coverage: Use the other new-for-UPluralType constructor as well.
+    PluralFormat pf2(Locale::getEnglish(), UPLURAL_TYPE_ORDINAL, errorCode);
+    pf2.applyPattern(pattern, errorCode);
+    if (errorCode.logIfFailureAndReset("PluralFormat(en, UPLURAL_TYPE_ORDINAL, pattern) failed")) {
+      return;
+    }
+    result = pf2.format(456, errorCode);
+    if (!errorCode.logIfFailureAndReset("PluralFormat.format(456) failed") &&
+        result != UNICODE_STRING_SIMPLE("456th file")) {
+      errln(UnicodeString("PluralFormat.format(456) wrong result string: ") + result);
+    }
+    result = pf2.format(111, errorCode);
+    if (!errorCode.logIfFailureAndReset("PluralFormat.format(111) failed") &&
+        result != UNICODE_STRING_SIMPLE("111th file")) {
+      errln(UnicodeString("PluralFormat.format(111) wrong result string: ") + result);
+    }
+}
+
 void
 PluralFormatTest::numberFormatTest(PluralFormat* plFmt, 
                                    NumberFormat *numFmt,
@@ -634,7 +675,7 @@ PluralFormatTest::numberFormatTest(PluralFormat* plFmt,
 
 
 void
-PluralFormatTest::helperTestRusults(const char** localeArray, 
+PluralFormatTest::helperTestResults(const char** localeArray, 
                                     int32_t capacityOfArray, 
                                     UnicodeString& testPattern,
                                     int8_t *expResults) {
index beea2e7430850dda9a5480f1f31ff4861000923b..e16b0e13a3d18669e6850eb643dbd9d3b3ef9811 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 1997-2011, International Business Machines Corporation and
+ * Copyright (c) 1997-2012, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 
@@ -31,6 +31,7 @@ private:
     void pluralFormatLocaleTest(/* char* par */);
     void pluralFormatExtendedTest();
     void pluralFormatExtendedParseTest();
+    void ordinalFormatTest();
     void numberFormatTest(PluralFormat* plFmt, 
                           NumberFormat *numFmt, 
                           int32_t start, 
@@ -39,7 +40,7 @@ private:
                           UnicodeString* numEvenAppendStr, 
                           UBool overwrite, // overwrite the numberFormat.format result
                           UnicodeString *message);
-    void helperTestRusults(const char** localeArray, 
+    void helperTestResults(const char** localeArray, 
                            int32_t capacityOfArray, 
                            UnicodeString& testPattern, 
                            int8_t *expectingResults);
index 2a599077a627a0b7dffa9ca8b4518513adf2d8df..fd80ebc83066d6c4dc3c08166e2b7074de9cce92 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 2007-2011, International Business Machines Corporation and
+* Copyright (C) 2007-2012, International Business Machines Corporation and
 * others. All Rights Reserved.
 ********************************************************************************
 
 
 #include <stdlib.h> // for strtod
 #include "plurults.h"
+#include "unicode/localpointer.h"
 #include "unicode/plurrule.h"
 
 #define LENGTHOF(array) (int32_t)(sizeof(array)/sizeof(array[0]))
 
 void setupResult(const int32_t testSource[], char result[], int32_t* max);
-UBool checkEqual(PluralRules *test, char *result, int32_t max);
-UBool testEquality(PluralRules *test);
+UBool checkEqual(const PluralRules &test, char *result, int32_t max);
+UBool testEquality(const PluralRules &test);
 
 // This is an API test, not a unit test.  It doesn't test very many cases, and doesn't
 // try to test the full functionality.  It just calls each function in the class and
@@ -30,14 +31,14 @@ UBool testEquality(PluralRules *test);
 void PluralRulesTest::runIndexedTest( int32_t index, UBool exec, const char* &name, char* /*par*/ )
 {
     if (exec) logln("TestSuite PluralRulesAPI");
-    switch (index) {
-        TESTCASE(0, testAPI);
-        TESTCASE(1, testGetUniqueKeywordValue);
-        TESTCASE(2, testGetSamples);
-        TESTCASE(3, testWithin);
-        TESTCASE(4, testGetAllKeywordValues);
-        default: name = ""; break;
-    }
+    TESTCASE_AUTO_BEGIN;
+    TESTCASE_AUTO(testAPI);
+    TESTCASE_AUTO(testGetUniqueKeywordValue);
+    TESTCASE_AUTO(testGetSamples);
+    TESTCASE_AUTO(testWithin);
+    TESTCASE_AUTO(testGetAllKeywordValues);
+    TESTCASE_AUTO(testOrdinal);
+    TESTCASE_AUTO_END;
 }
 
 #define PLURAL_TEST_NUM    18
@@ -94,19 +95,17 @@ void PluralRulesTest::testAPI(/*char *par*/)
     logln("\n start default locale test case ..\n");
 
     PluralRules defRule(status);
-    PluralRules* test=new PluralRules(status);
-    PluralRules* newEnPlural= test->forLocale(Locale::getEnglish(), status);
+    LocalPointer<PluralRules> test(new PluralRules(status));
+    LocalPointer<PluralRules> newEnPlural(test->forLocale(Locale::getEnglish(), status));
     if(U_FAILURE(status)) {
         dataerrln("ERROR: Could not create PluralRules (default) - exitting");
-        delete test;
         return;
     }
 
     // ======= Test clone, assignment operator && == operator.
-    PluralRules *dupRule = defRule.clone();
+    LocalPointer<PluralRules> dupRule(defRule.clone());
     if (dupRule==NULL) {
         errln("ERROR: clone plural rules test failed!");
-        delete test;
         return;
     } else {
         if ( *dupRule != defRule ) {
@@ -118,15 +117,12 @@ void PluralRulesTest::testAPI(/*char *par*/)
         if ( *dupRule != *newEnPlural ) {
             errln("ERROR:  clone plural rules test failed!");
         }
-        delete dupRule;
     }
 
-    delete newEnPlural;
-
     // ======= Test empty plural rules
     logln("Testing Simple PluralRules");
 
-    PluralRules* empRule = test->createRules(UNICODE_STRING_SIMPLE("a:n"), status);
+    LocalPointer<PluralRules> empRule(test->createRules(UNICODE_STRING_SIMPLE("a:n"), status));
     UnicodeString key;
     for (int32_t i=0; i<10; ++i) {
         key = empRule->select(i);
@@ -134,9 +130,6 @@ void PluralRulesTest::testAPI(/*char *par*/)
             errln("ERROR:  empty plural rules test failed! - exitting");
         }
     }
-    if (empRule!=NULL) {
-        delete empRule;
-    }
 
     // ======= Test simple plural rules
     logln("Testing Simple PluralRules");
@@ -145,19 +138,14 @@ void PluralRulesTest::testAPI(/*char *par*/)
     int32_t max;
 
     for (int32_t i=0; i<PLURAL_TEST_NUM-1; ++i) {
-       PluralRules *newRules = test->createRules(pluralTestData[i], status);
+       LocalPointer<PluralRules> newRules(test->createRules(pluralTestData[i], status));
        setupResult(pluralTestResult[i], result, &max);
-       if ( !checkEqual(newRules, result, max) ) {
+       if ( !checkEqual(*newRules, result, max) ) {
             errln("ERROR:  simple plural rules failed! - exitting");
-            delete test;
             return;
         }
-       if (newRules!=NULL) {
-           delete newRules;
-       }
     }
 
-
     // ======= Test complex plural rules
     logln("Testing Complex PluralRules");
     // TODO: the complex test data is hard coded. It's better to implement
@@ -179,35 +167,24 @@ void PluralRulesTest::testAPI(/*char *par*/)
        0x6F, // 'o'
        0x63  // 'c'
     };
-    PluralRules *newRules = test->createRules(complexRule, status);
-    if ( !checkEqual(newRules, cRuleResult, 12) ) {
+    LocalPointer<PluralRules> newRules(test->createRules(complexRule, status));
+    if ( !checkEqual(*newRules, cRuleResult, 12) ) {
          errln("ERROR:  complex plural rules failed! - exitting");
-         delete test;
          return;
-     }
-    if (newRules!=NULL) {
-        delete newRules;
-        newRules=NULL;
     }
-    newRules = test->createRules(complexRule2, status);
-    if ( !checkEqual(newRules, cRuleResult, 12) ) {
+    newRules.adoptInstead(test->createRules(complexRule2, status));
+    if ( !checkEqual(*newRules, cRuleResult, 12) ) {
          errln("ERROR:  complex plural rules failed! - exitting");
-         delete test;
          return;
-     }
-    if (newRules!=NULL) {
-        delete newRules;
-        newRules=NULL;
     }
 
     // ======= Test decimal fractions plural rules
     UnicodeString decimalRule= UNICODE_STRING_SIMPLE("a: n not in 0..100;");
     UnicodeString KEYWORD_A = UNICODE_STRING_SIMPLE("a");
     status = U_ZERO_ERROR;
-    newRules = test->createRules(decimalRule, status);
+    newRules.adoptInstead(test->createRules(decimalRule, status));
     if (U_FAILURE(status)) {
         dataerrln("ERROR: Could not create PluralRules for testing fractions - exitting");
-        delete test;
         return;
     }
     double fData[10] = {-100, -1, -0.0, 0, 0.1, 1, 1.999, 2.0, 100, 100.001 };
@@ -218,20 +195,12 @@ void PluralRulesTest::testAPI(/*char *par*/)
              errln("ERROR: plural rules for decimal fractions test failed!");
         }
     }
-    if (newRules!=NULL) {
-        delete newRules;
-        newRules=NULL;
-    }
-
-
 
     // ======= Test Equality
     logln("Testing Equality of PluralRules");
 
-
-    if ( !testEquality(test) ) {
+    if ( !testEquality(*test) ) {
          errln("ERROR:  complex plural rules failed! - exitting");
-         delete test;
          return;
      }
 
@@ -243,26 +212,21 @@ void PluralRulesTest::testAPI(/*char *par*/)
         errln("ERROR: getDynamicClassID() didn't return the expected value");
     }
     // ====== Test fallback to parent locale
-    PluralRules *en_UK = test->forLocale(Locale::getUK(), status);
-    PluralRules *en = test->forLocale(Locale::getEnglish(), status);
-    if (en_UK != NULL && en != NULL) {
+    LocalPointer<PluralRules> en_UK(test->forLocale(Locale::getUK(), status));
+    LocalPointer<PluralRules> en(test->forLocale(Locale::getEnglish(), status));
+    if (en_UK.isValid() && en.isValid()) {
         if ( *en_UK != *en ) {
             errln("ERROR:  test locale fallback failed!");
         }
     }
-    delete en;
-    delete en_UK;
 
-    PluralRules *zh_Hant = test->forLocale(Locale::getTaiwan(), status);
-    PluralRules *zh = test->forLocale(Locale::getChinese(), status);
-    if (zh_Hant != NULL && zh != NULL) {
+    LocalPointer<PluralRules> zh_Hant(test->forLocale(Locale::getTaiwan(), status));
+    LocalPointer<PluralRules> zh(test->forLocale(Locale::getChinese(), status));
+    if (zh_Hant.isValid() && zh.isValid()) {
         if ( *zh_Hant != *zh ) {
             errln("ERROR:  test locale fallback failed!");
         }
     }
-    delete zh_Hant;
-    delete zh;
-    delete test;
 }
 
 void setupResult(const int32_t testSource[], char result[], int32_t* max) {
@@ -280,11 +244,11 @@ void setupResult(const int32_t testSource[], char result[], int32_t* max) {
 }
 
 
-UBool checkEqual(PluralRules *test, char *result, int32_t max) {
+UBool checkEqual(const PluralRules &test, char *result, int32_t max) {
     UnicodeString key;
     UBool isEqual = TRUE;
     for (int32_t i=0; i<max; ++i) {
-        key= test->select(i);
+        key= test.select(i);
         if ( key.charAt(0)!=result[i] ) {
             isEqual = FALSE;
         }
@@ -294,7 +258,7 @@ UBool checkEqual(PluralRules *test, char *result, int32_t max) {
 
 #define MAX_EQ_ROW  2
 #define MAX_EQ_COL  5
-UBool testEquality(PluralRules *test) {
+UBool testEquality(const PluralRules &test) {
     UnicodeString testEquRules[MAX_EQ_ROW][MAX_EQ_COL] = {
         {   UNICODE_STRING_SIMPLE("a: n in 2..3"),
             UNICODE_STRING_SIMPLE("a: n is 2 or n is 3"),
@@ -318,7 +282,7 @@ UBool testEquality(PluralRules *test) {
         }
         int32_t totalRules=0;
         while((totalRules<MAX_EQ_COL) && (testEquRules[i][totalRules].length()>0) ) {
-            rules[totalRules]=test->createRules(testEquRules[i][totalRules], status);
+            rules[totalRules]=test.createRules(testEquRules[i][totalRules], status);
             totalRules++;
         }
         for (int32_t n=0; n<300 && ret ; ++n) {
@@ -572,4 +536,16 @@ PluralRulesTest::testGetAllKeywordValues() {
     }
 }
 
+void PluralRulesTest::testOrdinal() {
+    IcuTestErrorCode errorCode(*this, "testOrdinal");
+    LocalPointer<PluralRules> pr(PluralRules::forLocale("en", UPLURAL_TYPE_ORDINAL, errorCode));
+    if (errorCode.logIfFailureAndReset("PluralRules::forLocale(en, UPLURAL_TYPE_ORDINAL) failed")) {
+        return;
+    }
+    UnicodeString keyword = pr->select(2.);
+    if (keyword != UNICODE_STRING("two", 3)) {
+        errln("PluralRules(en-ordinal).select(2) failed");
+    }
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 02c26363c7504b75d94c6f521b3e9f2f4ad31429..6170ef97f5996ed6543da92c982f17ded0b2dc49 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT:
- * Copyright (c) 1997-2011, International Business Machines Corporation and
+ * Copyright (c) 1997-2012, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 
@@ -28,6 +28,7 @@ private:
     void testGetSamples();
     void testWithin();
     void testGetAllKeywordValues();
+    void testOrdinal();
 
     void assertRuleValue(const UnicodeString& rule, double expected);
     void assertRuleKeyValue(const UnicodeString& rule, const UnicodeString& key,
index 236313fcdc22889a6cf893e2bdd72985be130fbf..59389db030b813d7a9e21ed8b244c1112aef685b 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 1997-2011, International Business Machines Corporation and
+ * Copyright (c) 1997-2012, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************
  * File TMSGFMT.CPP
@@ -64,6 +64,7 @@ TestMessageFormat::runIndexedTest(int32_t index, UBool exec,
     TESTCASE_AUTO(TestCompatibleApostrophe);
     TESTCASE_AUTO(testCoverage);
     TESTCASE_AUTO(TestTrimArgumentName);
+    TESTCASE_AUTO(TestOrdinalPlural);
     TESTCASE_AUTO_END;
 }
 
@@ -1812,4 +1813,34 @@ void TestMessageFormat::TestTrimArgumentName() {
                   m.format(&argName, args, 1, result, errorCode));
 }
 
+void TestMessageFormat::TestOrdinalPlural() {
+    IcuTestErrorCode errorCode(*this, "TestOrdinalPlural");
+    // Test plural & ordinal together,
+    // to make sure that we get the correct cached PluralSelector for each.
+    MessageFormat m(
+        "{0,plural,one{1 file}other{# files}}, "
+        "{0,plordinal,one{#st file}two{#nd file}few{#rd file}other{#th file}}",
+        Locale::getEnglish(), errorCode);
+    if (errorCode.logDataIfFailureAndReset("Unable to instantiate MessageFormat")) {
+        return;
+    }
+    Formattable args[1] = { (int32_t)21 };
+    FieldPosition ignore(0);
+    UnicodeString result;
+    assertEquals("plural-ordinal format(21) failed", "21 files, 21st file",
+                 m.format(args, 1, result, ignore, errorCode));
+
+    args[0].setLong(2);
+    assertEquals("plural-ordinal format(2) failed", "2 files, 2nd file",
+                 m.format(args, 1, result.remove(), ignore, errorCode));
+
+    args[0].setLong(1);
+    assertEquals("plural-ordinal format(1) failed", "1 file, 1st file",
+                 m.format(args, 1, result.remove(), ignore, errorCode));
+
+    args[0].setLong(3);
+    assertEquals("plural-ordinal format(3) failed", "3 files, 3rd file",
+                 m.format(args, 1, result.remove(), ignore, errorCode));
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 80b31b4a90f3810d9a5eefcf291a04f52997173d..dc69866d10e29eeef1745d700c19ddb691efab24 100644 (file)
@@ -1,6 +1,6 @@
 /********************************************************************
  * COPYRIGHT: 
- * Copyright (c) 1997-2011, International Business Machines Corporation and
+ * Copyright (c) 1997-2012, International Business Machines Corporation and
  * others. All Rights Reserved.
  ********************************************************************/
 #ifndef _TESTMESSAGEFORMAT
@@ -114,6 +114,7 @@ public:
     void TestTurkishCasing(void);
     void testAutoQuoteApostrophe(void);
     void TestTrimArgumentName();
+    void TestOrdinalPlural();
 
     /* Provide better code coverage */
     void testCoverage(void);