ICU-12763 Add uplrules_selectWithFormat and PluralRules::select that take & use [U]NumberFormat

X-SVN-Rev: 39591
This commit is contained in:
Peter Edberg 2017-01-21 01:03:32 +00:00
parent 183b124712
commit 47e1aaaf14
5 changed files with 135 additions and 20 deletions

View file

@ -17,6 +17,8 @@
#include "unicode/plurrule.h"
#include "unicode/upluralrules.h"
#include "unicode/ures.h"
#include "unicode/numfmt.h"
#include "unicode/decimfmt.h"
#include "charstr.h"
#include "cmemory.h"
#include "cstring.h"
@ -36,7 +38,6 @@
#include "digitinterval.h"
#include "visibledigits.h"
#if !UCONFIG_NO_FORMATTING
U_NAMESPACE_BEGIN
@ -246,6 +247,24 @@ PluralRules::select(double number) const {
return select(FixedDecimal(number));
}
UnicodeString
PluralRules::select(const Formattable& obj, const NumberFormat& fmt) const {
UErrorCode status = U_ZERO_ERROR;
const DecimalFormat *decFmt = dynamic_cast<const DecimalFormat *>(&fmt);
if (decFmt != NULL) {
VisibleDigitsWithExponent digits;
decFmt->initVisibleDigitsWithExponent(obj, digits, status);
if (U_SUCCESS(status)) {
return select(digits);
}
}
double number = obj.getDouble(status);
if (U_SUCCESS(status)) {
return select(number);
}
return getKeywordOther();
}
UnicodeString
PluralRules::select(const FixedDecimal &number) const {
if (mRules == NULL) {

View file

@ -29,6 +29,9 @@
#include "unicode/format.h"
#include "unicode/upluralrules.h"
#ifndef U_HIDE_INTERNAL_API
#include "unicode/numfmt.h"
#endif /* U_HIDE_INTERNAL_API */
/**
* Value returned by PluralRules::getUniqueKeywordValue() when there is no
@ -345,6 +348,19 @@ public:
UnicodeString select(double number) const;
#ifndef U_HIDE_INTERNAL_API
/**
* Given a number and a format, returns the keyword of the first applicable
* rule for this PluralRules object.
* Note: This internal preview interface may be removed in the future if
* an architecturally cleaner solution reaches stable status.
* @param obj The numeric object for which the rule should be determined.
* @param fmt The NumberFormat specifying how the number will be formatted
* (this can affect the plural form, e.g. "1 dollar" vs "1.0 dollars").
* @return The keyword of the selected rule.
* @internal ICU 59 technology preview, may be removed in the future
*/
UnicodeString select(const Formattable& obj, const NumberFormat& fmt) const;
/**
* @internal
*/

View file

@ -15,6 +15,9 @@
#if !UCONFIG_NO_FORMATTING
#include "unicode/localpointer.h"
#ifndef U_HIDE_INTERNAL_API
#include "unicode/unum.h"
#endif /* U_HIDE_INTERNAL_API */
/**
* \file
@ -144,6 +147,33 @@ uplrules_select(const UPluralRules *uplrules,
UChar *keyword, int32_t capacity,
UErrorCode *status);
#ifndef U_HIDE_INTERNAL_API
/**
* Given a number, returns the keyword of the first rule that applies to the
* number, according to the UPluralRules object and given the number format
* specified by the UNumberFormat object.
* Note: This internal preview interface may be removed in the future if
* an architecturally cleaner solution reaches stable status.
* @param uplrules The UPluralRules object specifying the rules.
* @param number The number for which the rule has to be determined.
* @param fmt The UNumberFormat specifying how the number will be formatted
* (this can affect the plural form, e.g. "1 dollar" vs "1.0 dollars").
* If this is NULL, the function behaves like uplrules_select.
* @param keyword The keyword of the rule that applies to number.
* @param capacity The capacity of the keyword buffer.
* @param status A pointer to a UErrorCode to receive any errors.
* @return The length of keyword.
* @internal ICU 59 technology preview, may be removed in the future
*/
U_INTERNAL int32_t U_EXPORT2
uplrules_selectWithFormat(const UPluralRules *uplrules,
double number,
const UNumberFormat *fmt,
UChar *keyword, int32_t capacity,
UErrorCode *status);
#endif /* U_HIDE_INTERNAL_API */
#endif /* #if !UCONFIG_NO_FORMATTING */
#endif

View file

@ -15,6 +15,8 @@
#include "unicode/plurrule.h"
#include "unicode/locid.h"
#include "unicode/unistr.h"
#include "unicode/unum.h"
#include "unicode/numfmt.h"
U_NAMESPACE_USE
@ -54,5 +56,25 @@ uplrules_select(const UPluralRules *uplrules,
return result.extract(keyword, capacity, *status);
}
U_CAPI int32_t U_EXPORT2
uplrules_selectWithFormat(const UPluralRules *uplrules,
double number,
const UNumberFormat *fmt,
UChar *keyword, int32_t capacity,
UErrorCode *status)
{
if (U_FAILURE(*status)) {
return 0;
}
const PluralRules* plrules = reinterpret_cast<const PluralRules*>(uplrules);
const NumberFormat* nf = reinterpret_cast<const NumberFormat*>(fmt);
if (plrules == NULL || nf == NULL || ((keyword == NULL)? capacity != 0 : capacity < 0)) {
*status = U_ILLEGAL_ARGUMENT_ERROR;
return 0;
}
Formattable obj(number);
UnicodeString result = plrules->select(obj, *nf);
return result.extract(keyword, capacity, *status);
}
#endif /* #if !UCONFIG_NO_FORMATTING */

View file

@ -32,31 +32,34 @@ typedef struct {
const char * locale;
double number;
const char * keywordExpected;
const char * keywordExpectedForDecimals;
} PluralRulesTestItem;
/* Just a small set of tests for now, other functionality is tested in the C++ tests */
static const PluralRulesTestItem testItems[] = {
{ "en", 0, "other" },
{ "en", 0.5, "other" },
{ "en", 1, "one" },
{ "en", 1.5, "other" },
{ "en", 2, "other" },
{ "fr", 0, "one" },
{ "fr", 0.5, "one" },
{ "fr", 1, "one" },
{ "fr", 1.5, "one" },
{ "fr", 2, "other" },
{ "ru", 0, "many" },
{ "ru", 0.5, "other" },
{ "ru", 1, "one" },
{ "ru", 1.5, "other" },
{ "ru", 2, "few" },
{ "ru", 5, "many" },
{ "ru", 10, "many" },
{ "ru", 11, "many" },
{ NULL, 0, NULL }
{ "en", 0, "other", "other" },
{ "en", 0.5, "other", "other" },
{ "en", 1, "one", "other" },
{ "en", 1.5, "other", "other" },
{ "en", 2, "other", "other" },
{ "fr", 0, "one", "one" },
{ "fr", 0.5, "one", "one" },
{ "fr", 1, "one", "one" },
{ "fr", 1.5, "one", "one" },
{ "fr", 2, "other", "other" },
{ "ru", 0, "many", "other" },
{ "ru", 0.5, "other", "other" },
{ "ru", 1, "one", "other" },
{ "ru", 1.5, "other", "other" },
{ "ru", 2, "few", "other" },
{ "ru", 5, "many", "other" },
{ "ru", 10, "many", "other" },
{ "ru", 11, "many", "other" },
{ NULL, 0, NULL, NULL }
};
static const UChar twoDecimalPat[] = { 0x23,0x30,0x2E,0x30,0x30,0 }; /* "#0.00" */
enum {
kKeywordBufLen = 32
};
@ -69,6 +72,7 @@ static void TestPluralRules()
UErrorCode status = U_ZERO_ERROR;
UPluralRules* uplrules = uplrules_open(testItemPtr->locale, &status);
if ( U_SUCCESS(status) ) {
UNumberFormat* unumfmt;
UChar keyword[kKeywordBufLen];
UChar keywordExpected[kKeywordBufLen];
int32_t keywdLen = uplrules_select(uplrules, testItemPtr->number, keyword, kKeywordBufLen, &status);
@ -86,6 +90,30 @@ static void TestPluralRules()
log_err("FAIL: uplrules_select for locale %s, number %.1f: %s\n",
testItemPtr->locale, testItemPtr->number, myErrorName(status) );
}
status = U_ZERO_ERROR;
unumfmt = unum_open(UNUM_PATTERN_DECIMAL, twoDecimalPat, -1, testItemPtr->locale, NULL, &status);
if ( U_SUCCESS(status) ) {
keywdLen = uplrules_selectWithFormat(uplrules, testItemPtr->number, unumfmt, keyword, kKeywordBufLen, &status);
if (keywdLen >= kKeywordBufLen) {
keyword[kKeywordBufLen-1] = 0;
}
if ( U_SUCCESS(status) ) {
u_unescape(testItemPtr->keywordExpectedForDecimals, keywordExpected, kKeywordBufLen);
if ( u_strcmp(keyword, keywordExpected) != 0 ) {
char bcharBuf[kKeywordBufLen];
log_data_err("ERROR: uplrules_selectWithFormat for locale %s, number %.1f: expect %s, get %s\n",
testItemPtr->locale, testItemPtr->number, testItemPtr->keywordExpectedForDecimals, u_austrcpy(bcharBuf,keyword) );
}
} else {
log_err("FAIL: uplrules_selectWithFormat for locale %s, number %.1f: %s\n",
testItemPtr->locale, testItemPtr->number, myErrorName(status) );
}
unum_close(unumfmt);
} else {
log_err("FAIL: unum_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) );
}
uplrules_close(uplrules);
} else {
log_err("FAIL: uplrules_open for locale %s: %s\n", testItemPtr->locale, myErrorName(status) );