*******************************************************************************
*/
+#include "unicode/utypes.h"
#include "utypeinfo.h" // for 'typeid' to work
#include "unicode/rbnf.h"
#include "unicode/ustring.h"
#include "unicode/utf16.h"
#include "unicode/udata.h"
+#include "unicode/udisplaycontext.h"
+#include "unicode/brkiter.h"
#include "nfrs.h"
#include "cmemory.h"
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
LocalizationInfo* locinfo = StringLocalizationInfo::create(locs, perror, status);
init(description, locinfo, perror, status);
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
LocalizationInfo* locinfo = StringLocalizationInfo::create(locs, perror, status);
init(description, locinfo, perror, status);
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
init(description, info, perror, status);
}
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
init(description, NULL, perror, status);
}
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
init(description, NULL, perror, status);
}
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
if (U_FAILURE(status)) {
return;
, lenient(FALSE)
, lenientParseRules(NULL)
, localizations(NULL)
+ , capitalizationInfoSet(FALSE)
+ , capitalizationForUIListMenu(FALSE)
+ , capitalizationForStandAlone(FALSE)
+ , capitalizationBrkIter(NULL)
{
this->operator=(rhs);
}
init(rhs.originalDescription, rhs.localizations ? rhs.localizations->ref() : NULL, perror, status);
setDecimalFormatSymbols(*rhs.getDecimalFormatSymbols());
setDefaultRuleSet(rhs.getDefaultRuleSetName(), status);
+
+ capitalizationInfoSet = rhs.capitalizationInfoSet;
+ capitalizationForUIListMenu = rhs.capitalizationForUIListMenu;
+ capitalizationForStandAlone = rhs.capitalizationForStandAlone;
+ capitalizationBrkIter = (rhs.capitalizationBrkIter!=NULL)? rhs.capitalizationBrkIter->clone(): NULL;
+
return *this;
}
if (typeid(*this) == typeid(other)) {
const RuleBasedNumberFormat& rhs = (const RuleBasedNumberFormat&)other;
+ // test for capitalization info equality is adequately handled
+ // by the NumberFormat test for fCapitalizationContext equality;
+ // the info here is just derived from that.
if (locale == rhs.locale &&
lenient == rhs.lenient &&
(localizations == NULL
UnicodeString& toAppendTo,
FieldPosition& /* pos */) const
{
- if (defaultRuleSet) defaultRuleSet->format((int64_t)number, toAppendTo, toAppendTo.length());
+ if (defaultRuleSet) {
+ int32_t startPos = toAppendTo.length();
+ defaultRuleSet->format((int64_t)number, toAppendTo, toAppendTo.length());
+ adjustForCapitalizationContext(startPos, toAppendTo);
+ }
return toAppendTo;
}
UnicodeString& toAppendTo,
FieldPosition& /* pos */) const
{
- if (defaultRuleSet) defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
+ if (defaultRuleSet) {
+ int32_t startPos = toAppendTo.length();
+ defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
+ adjustForCapitalizationContext(startPos, toAppendTo);
+ }
return toAppendTo;
}
UnicodeString& toAppendTo,
FieldPosition& /* pos */) const
{
+ int32_t startPos = toAppendTo.length();
// Special case for NaN; adapted from what DecimalFormat::_format( double number,...) does.
if (uprv_isNaN(number)) {
DecimalFormatSymbols* decFmtSyms = getDecimalFormatSymbols(); // RuleBasedNumberFormat internal
} else if (defaultRuleSet) {
defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
}
- return toAppendTo;
+ return adjustForCapitalizationContext(startPos, toAppendTo);
}
} else {
NFRuleSet *rs = findRuleSet(ruleSetName, status);
if (rs) {
+ int32_t startPos = toAppendTo.length();
rs->format((int64_t)number, toAppendTo, toAppendTo.length());
+ adjustForCapitalizationContext(startPos, toAppendTo);
}
}
}
} else {
NFRuleSet *rs = findRuleSet(ruleSetName, status);
if (rs) {
+ int32_t startPos = toAppendTo.length();
rs->format(number, toAppendTo, toAppendTo.length());
+ adjustForCapitalizationContext(startPos, toAppendTo);
}
}
}
} else {
NFRuleSet *rs = findRuleSet(ruleSetName, status);
if (rs) {
+ int32_t startPos = toAppendTo.length();
rs->format(number, toAppendTo, toAppendTo.length());
+ adjustForCapitalizationContext(startPos, toAppendTo);
}
}
}
return toAppendTo;
}
+UnicodeString&
+RuleBasedNumberFormat::adjustForCapitalizationContext(int32_t startPos,
+ UnicodeString& currentResult) const
+{
+#if !UCONFIG_NO_BREAK_ITERATION
+ if (startPos==0 && currentResult.length() > 0) {
+ // capitalize currentResult according to context
+ UChar32 ch = currentResult.char32At(0);
+ UErrorCode status = U_ZERO_ERROR;
+ UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
+ if ( u_islower(ch) && U_SUCCESS(status) && capitalizationBrkIter!= NULL &&
+ ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
+ (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
+ (capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
+ // titlecase first word of currentResult, here use sentence iterator unlike current implementations
+ // in LocaleDisplayNamesImpl::adjustForUsageAndContext and RelativeDateFormat::format
+ currentResult.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
+ }
+ }
+#endif
+ return currentResult;
+}
+
+
void
RuleBasedNumberFormat::parse(const UnicodeString& text,
Formattable& result,
originalDescription = rules;
}
+// override the NumberFormat implementation in order to
+// lazily initialize relevant items
+void
+RuleBasedNumberFormat::setContext(UDisplayContext value, UErrorCode& status)
+{
+ NumberFormat::setContext(value, status);
+ if (U_SUCCESS(status)) {
+ if (!capitalizationInfoSet &&
+ (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE)) {
+ initCapitalizationContextInfo(locale);
+ capitalizationInfoSet = TRUE;
+ }
+#if !UCONFIG_NO_BREAK_ITERATION
+ if ( capitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
+ (value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && capitalizationForUIListMenu) ||
+ (value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && capitalizationForStandAlone)) ) {
+ UErrorCode status = U_ZERO_ERROR;
+ capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
+ }
+#endif
+ }
+}
+
+void
+RuleBasedNumberFormat::initCapitalizationContextInfo(const Locale& thelocale)
+{
+#if !UCONFIG_NO_BREAK_ITERATION
+ const char * localeID = (thelocale != NULL)? thelocale.getBaseName(): NULL;
+ UErrorCode status = U_ZERO_ERROR;
+ UResourceBundle *rb = ures_open(NULL, localeID, &status);
+ rb = ures_getByKeyWithFallback(rb, "contextTransforms", rb, &status);
+ // Have't got a good contextTransforms type for RBNF number spellout,
+ // fix that with CLDR #6857. In the meantime use "symbol".
+ rb = ures_getByKeyWithFallback(rb, "symbol", rb, &status);
+ if (U_SUCCESS(status) && rb != NULL) {
+ int32_t len = 0;
+ const int32_t * intVector = ures_getIntVector(rb, &len, &status);
+ if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
+ capitalizationForUIListMenu = intVector[0];
+ capitalizationForStandAlone = intVector[1];
+ }
+ }
+ ures_close(rb);
+#endif
+}
+
void
RuleBasedNumberFormat::stripWhitespace(UnicodeString& description)
{
delete lenientParseRules;
lenientParseRules = NULL;
+ delete capitalizationBrkIter;
+ capitalizationBrkIter = NULL;
+
if (localizations) localizations = localizations->unref();
}
#include "unicode/unum.h"
#include "unicode/unumsys.h"
#include "unicode/ustring.h"
+#include "unicode/udisplaycontext.h"
#include "cintltst.h"
#include "cnumtst.h"
localeString, currencyISOCode, DATA[i][3 + sIndex]);
}
}
+ unum_close(unumFmt);
}
}
}
+typedef struct {
+ const char * locale;
+ UNumberFormatStyle style;
+ UDisplayContext context;
+ const char * expectedResult;
+} TestContextItem;
+
+/* currently no locales have contextTransforms data for "symbol" type */
+static const TestContextItem tcItems[] = { /* results for 123.45 */
+ { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_MIDDLE_OF_SENTENCE, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
+ { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, "Ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
+ { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
+ { "sv", UNUM_SPELLOUT, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, "ett\\u00ADhundra\\u00ADtjugo\\u00ADtre komma fyra fem" },
+ { NULL, (UNumberFormatStyle)0, (UDisplayContext)0, NULL }
+};
+
static void TestContext(void) {
- /* just a minimal sanity check for now */
UErrorCode status = U_ZERO_ERROR;
+ const TestContextItem* itemPtr;
+
UNumberFormat *unum = unum_open(UNUM_SPELLOUT, NULL, 0, "en", NULL, &status);
if ( U_SUCCESS(status) ) {
UDisplayContext context = unum_getContext(unum, UDISPCTX_TYPE_CAPITALIZATION, &status);
} else {
log_data_err("unum_open UNUM_SPELLOUT for en fails with status %s\n", myErrorName(status));
}
+
+ for (itemPtr = tcItems; itemPtr->locale != NULL; itemPtr++) {
+ UChar ubufResult[kUBufMax];
+ int32_t ulenRes;
+
+ status = U_ZERO_ERROR;
+ unum = unum_open(itemPtr->style, NULL, 0, itemPtr->locale, NULL, &status);
+ if (U_FAILURE(status)) {
+ log_data_err("FAIL: unum_open, locale %s, style %d - %s\n",
+ itemPtr->locale, (int)itemPtr->style, myErrorName(status));
+ continue;
+ }
+ unum_setContext(unum, itemPtr->context, &status);
+ ulenRes = unum_formatDouble(unum, 123.45, ubufResult, kUBufMax, NULL, &status);
+ if (U_FAILURE(status)) {
+ log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d - %s\n",
+ itemPtr->locale, (int)itemPtr->style, (int)itemPtr->context, myErrorName(status));
+ } else {
+ UChar ubufExpected[kUBufMax];
+ int32_t ulenExp = u_unescape(itemPtr->expectedResult, ubufExpected, kUBufMax);
+ if (ulenRes != ulenExp || u_strncmp(ubufResult, ubufExpected, ulenExp) != 0) {
+ char bbuf[kUBufMax*2];
+ u_austrncpy(bbuf, ubufResult, sizeof(bbuf));
+ log_err("FAIL: unum_formatDouble, locale %s, style %d, context %d, expected %d:\"%s\", got %d:\"%s\"\n",
+ itemPtr->locale, (int)itemPtr->style, (int)itemPtr->context, ulenExp,
+ itemPtr->expectedResult, ulenRes, bbuf);
+ }
+ }
+ unum_close(unum);
+ }
}
#endif /* #if !UCONFIG_NO_FORMATTING */