ICU-9132 ordinal-plural formatting in C/C++

X-SVN-Rev: 31687
This commit is contained in:
Markus Scherer 2012-04-07 04:27:27 +00:00
parent a89b4cc093
commit 8d7428d1b3
18 changed files with 516 additions and 177 deletions

View 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;

View 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.

View 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"}
}

View 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);
}

View 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

View 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);
}

View 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).

View 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.

View 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;

View File

@ -37,6 +37,32 @@
* 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);
/**
* Close a UPluralRules object. Once closed it may no longer be used.
* 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);
/**
* Closes a UPluralRules object. Once closed it may no longer be used.
* @param uplrules The UPluralRules object to close.
* @stable ICU 4.8
*/

View 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

View 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 */

View 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.
********************************************************************/
@ -31,15 +31,14 @@
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) {

View 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);

View 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.
********************************************************************************
@ -15,13 +15,14 @@
#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 */

View 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,

View 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 */

View 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);