Index: source/i18n/rbnf.cpp |
diff --git a/source/i18n/rbnf.cpp b/source/i18n/rbnf.cpp |
index 682d449f38a6a6c53cc3ef29d7f2e593cb9b84cb..bdfd71a4dc387fca1d7b3a6412b88d6d6ced1b79 100644 |
--- a/source/i18n/rbnf.cpp |
+++ b/source/i18n/rbnf.cpp |
@@ -1,10 +1,11 @@ |
/* |
******************************************************************************* |
-* Copyright (C) 1997-2013, International Business Machines Corporation |
+* Copyright (C) 1997-2014, International Business Machines Corporation |
* and others. All Rights Reserved. |
******************************************************************************* |
*/ |
+#include "unicode/utypes.h" |
#include "utypeinfo.h" // for 'typeid' to work |
#include "unicode/rbnf.h" |
@@ -12,6 +13,7 @@ |
#if U_HAVE_RBNF |
#include "unicode/normlzr.h" |
+#include "unicode/plurfmt.h" |
#include "unicode/tblcoll.h" |
#include "unicode/uchar.h" |
#include "unicode/ucol.h" |
@@ -21,6 +23,8 @@ |
#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" |
@@ -29,9 +33,9 @@ |
#include "uresimp.h" |
// debugging |
-// #define DEBUG |
+// #define RBNF_DEBUG |
-#ifdef DEBUG |
+#ifdef RBNF_DEBUG |
#include "stdio.h" |
#endif |
@@ -324,10 +328,12 @@ private: |
UChar* nextString(void); |
}; |
-#ifdef DEBUG |
+#ifdef RBNF_DEBUG |
#define ERROR(msg) parseError(msg); return NULL; |
+#define EXPLANATION_ARG explanationArg |
#else |
#define ERROR(msg) parseError(NULL); return NULL; |
+#define EXPLANATION_ARG |
#endif |
@@ -525,8 +531,8 @@ LocDataParser::nextString() { |
return result; |
} |
-void |
-LocDataParser::parseError(const char* /*str*/) { |
+void LocDataParser::parseError(const char* EXPLANATION_ARG) |
+{ |
if (!data) { |
return; |
} |
@@ -551,14 +557,14 @@ LocDataParser::parseError(const char* /*str*/) { |
pe.postContext[limit-p] = 0; |
pe.offset = (int32_t)(p - data); |
-#ifdef DEBUG |
- fprintf(stderr, "%s at or near character %d: ", str, p-data); |
+#ifdef RBNF_DEBUG |
+ fprintf(stderr, "%s at or near character %ld: ", EXPLANATION_ARG, p-data); |
UnicodeString msg; |
msg.append(start, p - start); |
msg.append((UChar)0x002f); /* SOLIDUS/SLASH */ |
msg.append(p, limit-p); |
- msg.append("'"); |
+ msg.append(UNICODE_STRING_SIMPLE("'")); |
char buf[128]; |
int32_t len = msg.extract(0, msg.length(), buf, 128); |
@@ -658,6 +664,10 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, |
, 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); |
@@ -676,6 +686,10 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, |
, 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); |
@@ -694,6 +708,10 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, |
, lenient(FALSE) |
, lenientParseRules(NULL) |
, localizations(NULL) |
+ , capitalizationInfoSet(FALSE) |
+ , capitalizationForUIListMenu(FALSE) |
+ , capitalizationForStandAlone(FALSE) |
+ , capitalizationBrkIter(NULL) |
{ |
init(description, info, perror, status); |
} |
@@ -711,6 +729,10 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, |
, lenient(FALSE) |
, lenientParseRules(NULL) |
, localizations(NULL) |
+ , capitalizationInfoSet(FALSE) |
+ , capitalizationForUIListMenu(FALSE) |
+ , capitalizationForStandAlone(FALSE) |
+ , capitalizationBrkIter(NULL) |
{ |
init(description, NULL, perror, status); |
} |
@@ -729,6 +751,10 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const UnicodeString& description, |
, lenient(FALSE) |
, lenientParseRules(NULL) |
, localizations(NULL) |
+ , capitalizationInfoSet(FALSE) |
+ , capitalizationForUIListMenu(FALSE) |
+ , capitalizationForStandAlone(FALSE) |
+ , capitalizationBrkIter(NULL) |
{ |
init(description, NULL, perror, status); |
} |
@@ -744,6 +770,10 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(URBNFRuleSetTag tag, const Locale& |
, lenient(FALSE) |
, lenientParseRules(NULL) |
, localizations(NULL) |
+ , capitalizationInfoSet(FALSE) |
+ , capitalizationForUIListMenu(FALSE) |
+ , capitalizationForStandAlone(FALSE) |
+ , capitalizationBrkIter(NULL) |
{ |
if (U_FAILURE(status)) { |
return; |
@@ -804,6 +834,10 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs) |
, lenient(FALSE) |
, lenientParseRules(NULL) |
, localizations(NULL) |
+ , capitalizationInfoSet(FALSE) |
+ , capitalizationForUIListMenu(FALSE) |
+ , capitalizationForStandAlone(FALSE) |
+ , capitalizationBrkIter(NULL) |
{ |
this->operator=(rhs); |
} |
@@ -813,14 +847,26 @@ RuleBasedNumberFormat::RuleBasedNumberFormat(const RuleBasedNumberFormat& rhs) |
RuleBasedNumberFormat& |
RuleBasedNumberFormat::operator=(const RuleBasedNumberFormat& rhs) |
{ |
+ if (this == &rhs) { |
+ return *this; |
+ } |
+ NumberFormat::operator=(rhs); |
UErrorCode status = U_ZERO_ERROR; |
dispose(); |
locale = rhs.locale; |
lenient = rhs.lenient; |
- UnicodeString rules = rhs.getRules(); |
UParseError perror; |
- init(rules, rhs.localizations ? rhs.localizations->ref() : NULL, perror, status); |
+ 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; |
+#if !UCONFIG_NO_BREAK_ITERATION |
+ capitalizationBrkIter = (rhs.capitalizationBrkIter!=NULL)? rhs.capitalizationBrkIter->clone(): NULL; |
+#endif |
return *this; |
} |
@@ -833,23 +879,7 @@ RuleBasedNumberFormat::~RuleBasedNumberFormat() |
Format* |
RuleBasedNumberFormat::clone(void) const |
{ |
- RuleBasedNumberFormat * result = NULL; |
- UnicodeString rules = getRules(); |
- UErrorCode status = U_ZERO_ERROR; |
- UParseError perror; |
- result = new RuleBasedNumberFormat(rules, localizations, locale, perror, status); |
- /* test for NULL */ |
- if (result == 0) { |
- status = U_MEMORY_ALLOCATION_ERROR; |
- return 0; |
- } |
- if (U_FAILURE(status)) { |
- delete result; |
- result = 0; |
- } else { |
- result->lenient = lenient; |
- } |
- return result; |
+ return new RuleBasedNumberFormat(*this); |
} |
UBool |
@@ -861,6 +891,9 @@ RuleBasedNumberFormat::operator==(const Format& other) const |
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 |
@@ -1032,7 +1065,12 @@ RuleBasedNumberFormat::format(int32_t number, |
UnicodeString& toAppendTo, |
FieldPosition& /* pos */) const |
{ |
- if (defaultRuleSet) defaultRuleSet->format((int64_t)number, toAppendTo, toAppendTo.length()); |
+ if (defaultRuleSet) { |
+ UErrorCode status = U_ZERO_ERROR; |
+ int32_t startPos = toAppendTo.length(); |
+ defaultRuleSet->format((int64_t)number, toAppendTo, toAppendTo.length(), status); |
+ adjustForCapitalizationContext(startPos, toAppendTo); |
+ } |
return toAppendTo; |
} |
@@ -1042,7 +1080,12 @@ RuleBasedNumberFormat::format(int64_t number, |
UnicodeString& toAppendTo, |
FieldPosition& /* pos */) const |
{ |
- if (defaultRuleSet) defaultRuleSet->format(number, toAppendTo, toAppendTo.length()); |
+ if (defaultRuleSet) { |
+ UErrorCode status = U_ZERO_ERROR; |
+ int32_t startPos = toAppendTo.length(); |
+ defaultRuleSet->format(number, toAppendTo, toAppendTo.length(), status); |
+ adjustForCapitalizationContext(startPos, toAppendTo); |
+ } |
return toAppendTo; |
} |
@@ -1052,6 +1095,7 @@ RuleBasedNumberFormat::format(double number, |
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 |
@@ -1059,9 +1103,10 @@ RuleBasedNumberFormat::format(double number, |
toAppendTo += decFmtSyms->getConstSymbol(DecimalFormatSymbols::kNaNSymbol); |
} |
} else if (defaultRuleSet) { |
- defaultRuleSet->format(number, toAppendTo, toAppendTo.length()); |
+ UErrorCode status = U_ZERO_ERROR; |
+ defaultRuleSet->format(number, toAppendTo, toAppendTo.length(), status); |
} |
- return toAppendTo; |
+ return adjustForCapitalizationContext(startPos, toAppendTo); |
} |
@@ -1080,7 +1125,9 @@ RuleBasedNumberFormat::format(int32_t number, |
} else { |
NFRuleSet *rs = findRuleSet(ruleSetName, status); |
if (rs) { |
- rs->format((int64_t)number, toAppendTo, toAppendTo.length()); |
+ int32_t startPos = toAppendTo.length(); |
+ rs->format((int64_t)number, toAppendTo, toAppendTo.length(), status); |
+ adjustForCapitalizationContext(startPos, toAppendTo); |
} |
} |
} |
@@ -1102,7 +1149,9 @@ RuleBasedNumberFormat::format(int64_t number, |
} else { |
NFRuleSet *rs = findRuleSet(ruleSetName, status); |
if (rs) { |
- rs->format(number, toAppendTo, toAppendTo.length()); |
+ int32_t startPos = toAppendTo.length(); |
+ rs->format(number, toAppendTo, toAppendTo.length(), status); |
+ adjustForCapitalizationContext(startPos, toAppendTo); |
} |
} |
} |
@@ -1124,13 +1173,39 @@ RuleBasedNumberFormat::format(double number, |
} else { |
NFRuleSet *rs = findRuleSet(ruleSetName, status); |
if (rs) { |
- rs->format(number, toAppendTo, toAppendTo.length()); |
+ int32_t startPos = toAppendTo.length(); |
+ rs->format(number, toAppendTo, toAppendTo.length(), status); |
+ 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, |
@@ -1429,6 +1504,55 @@ RuleBasedNumberFormat::init(const UnicodeString& rules, LocalizationInfo* locali |
} else { |
defaultRuleSet = getDefaultRuleSet(); |
} |
+ 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); |
+ if (U_FAILURE(status)) { |
+ delete capitalizationBrkIter; |
+ capitalizationBrkIter = NULL; |
+ } |
+ } |
+#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); |
+ rb = ures_getByKeyWithFallback(rb, "number-spellout", 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 |
@@ -1498,6 +1622,11 @@ RuleBasedNumberFormat::dispose() |
delete lenientParseRules; |
lenientParseRules = NULL; |
+#if !UCONFIG_NO_BREAK_ITERATION |
+ delete capitalizationBrkIter; |
+ capitalizationBrkIter = NULL; |
+#endif |
+ |
if (localizations) localizations = localizations->unref(); |
} |
@@ -1512,7 +1641,7 @@ RuleBasedNumberFormat::dispose() |
* @return The collator to use for lenient parsing, or null if lenient parsing |
* is turned off. |
*/ |
-Collator* |
+const RuleBasedCollator* |
RuleBasedNumberFormat::getCollator() const |
{ |
#if !UCONFIG_NO_COLLATION |
@@ -1520,7 +1649,7 @@ RuleBasedNumberFormat::getCollator() const |
return NULL; |
} |
- // lazy-evaulate the collator |
+ // lazy-evaluate the collator |
if (collator == NULL && lenient) { |
// create a default collator based on the formatter's locale, |
// then pull out that collator's rules, append any additional |
@@ -1539,7 +1668,7 @@ RuleBasedNumberFormat::getCollator() const |
newCollator = new RuleBasedCollator(rules, status); |
// Exit if newCollator could not be created. |
if (newCollator == NULL) { |
- return NULL; |
+ return NULL; |
} |
} else { |
temp = NULL; |
@@ -1618,6 +1747,14 @@ RuleBasedNumberFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbo |
adoptDecimalFormatSymbols(new DecimalFormatSymbols(symbols)); |
} |
+PluralFormat * |
+RuleBasedNumberFormat::createPluralFormat(UPluralType pluralType, |
+ const UnicodeString &pattern, |
+ UErrorCode& status) const |
+{ |
+ return new PluralFormat(locale, pluralType, pattern, status); |
+} |
+ |
U_NAMESPACE_END |
/* U_HAVE_RBNF */ |