ICU-10681 Lazily get and cache BreakIterator for titlecasing; lazily get contextTransform info if possible (C)

X-SVN-Rev: 35287
This commit is contained in:
Peter Edberg 2014-03-02 00:44:35 +00:00
parent 11676f470f
commit 27cfaed4d8
8 changed files with 242 additions and 146 deletions

View file

@ -12,6 +12,7 @@
#include "unicode/locdspnm.h"
#include "unicode/msgfmt.h"
#include "unicode/ures.h"
#include "unicode/udisplaycontext.h"
#include "unicode/brkiter.h"
#include "cmemory.h"
@ -275,6 +276,7 @@ class LocaleDisplayNamesImpl : public LocaleDisplayNames {
MessageFormat *format;
MessageFormat *keyTypeFormat;
UDisplayContext capitalizationContext;
BreakIterator* capitalizationBrkIter;
UnicodeString formatOpenParen;
UnicodeString formatReplaceOpenParen;
UnicodeString formatCloseParen;
@ -290,10 +292,9 @@ class LocaleDisplayNamesImpl : public LocaleDisplayNames {
kCapContextUsageKeyValue,
kCapContextUsageCount
};
// Capitalization transforms. For each usage type, the first array element indicates
// whether to titlecase for uiListOrMenu context, the second indicates whether to
// titlecase for stand-alone context.
UBool fCapitalization[kCapContextUsageCount][2];
// Capitalization transforms. For each usage type, indicates whether to titlecase for
// the context specified in capitalizationContext (which we know at construction time)
UBool fCapitalization[kCapContextUsageCount];
public:
// constructor
@ -341,6 +342,7 @@ LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
, format(NULL)
, keyTypeFormat(NULL)
, capitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
, capitalizationBrkIter(NULL)
{
initialize();
}
@ -354,6 +356,7 @@ LocaleDisplayNamesImpl::LocaleDisplayNamesImpl(const Locale& locale,
, format(NULL)
, keyTypeFormat(NULL)
, capitalizationContext(UDISPCTX_CAPITALIZATION_NONE)
, capitalizationBrkIter(NULL)
{
while (length-- > 0) {
UDisplayContext value = *contexts++;
@ -429,35 +432,52 @@ LocaleDisplayNamesImpl::initialize(void) {
{ "variant", kCapContextUsageVariant },
{ NULL, (CapContextUsage)0 },
};
int32_t len = 0;
UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &status);
if (U_SUCCESS(status)) {
UResourceBundle *contextTransforms = ures_getByKeyWithFallback(localeBundle, "contextTransforms", NULL, &status);
// Only get the context data if we need it! This is a const object so we know now...
// Also check whether we will need a break iterator (depends on the data)
UBool needBrkIter = FALSE;
if (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_STANDALONE) {
int32_t len = 0;
UResourceBundle *localeBundle = ures_open(NULL, locale.getName(), &status);
if (U_SUCCESS(status)) {
UResourceBundle *contextTransformUsage;
while ( (contextTransformUsage = ures_getNextResource(contextTransforms, NULL, &status)) != NULL ) {
const int32_t * intVector = ures_getIntVector(contextTransformUsage, &len, &status);
if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
const char* usageKey = ures_getKey(contextTransformUsage);
if (usageKey != NULL) {
const ContextUsageNameToEnum * typeMapPtr = contextUsageTypeMap;
int32_t compResult = 0;
// linear search; list is short and we cannot be sure that bsearch is available
while ( typeMapPtr->usageName != NULL && (compResult = uprv_strcmp(usageKey, typeMapPtr->usageName)) > 0 ) {
++typeMapPtr;
}
if (typeMapPtr->usageName != NULL && compResult == 0) {
fCapitalization[typeMapPtr->usageEnum][0] = intVector[0];
fCapitalization[typeMapPtr->usageEnum][1] = intVector[1];
UResourceBundle *contextTransforms = ures_getByKeyWithFallback(localeBundle, "contextTransforms", NULL, &status);
if (U_SUCCESS(status)) {
UResourceBundle *contextTransformUsage;
while ( (contextTransformUsage = ures_getNextResource(contextTransforms, NULL, &status)) != NULL ) {
const int32_t * intVector = ures_getIntVector(contextTransformUsage, &len, &status);
if (U_SUCCESS(status) && intVector != NULL && len >= 2) {
const char* usageKey = ures_getKey(contextTransformUsage);
if (usageKey != NULL) {
const ContextUsageNameToEnum * typeMapPtr = contextUsageTypeMap;
int32_t compResult = 0;
// linear search; list is short and we cannot be sure that bsearch is available
while ( typeMapPtr->usageName != NULL && (compResult = uprv_strcmp(usageKey, typeMapPtr->usageName)) > 0 ) {
++typeMapPtr;
}
if (typeMapPtr->usageName != NULL && compResult == 0) {
int32_t titlecaseInt = (capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU)? intVector[0]: intVector[1];
if (titlecaseInt != 0) {
fCapitalization[typeMapPtr->usageEnum] = TRUE;;
needBrkIter = TRUE;
}
}
}
}
status = U_ZERO_ERROR;
ures_close(contextTransformUsage);
}
status = U_ZERO_ERROR;
ures_close(contextTransformUsage);
ures_close(contextTransforms);
}
ures_close(contextTransforms);
ures_close(localeBundle);
}
}
// Get a sentence break iterator if we will need it
if (needBrkIter || capitalizationContext == UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE) {
status = U_ZERO_ERROR;
capitalizationBrkIter = BreakIterator::createSentenceInstance(locale, status);
if (U_FAILURE(status)) {
delete capitalizationBrkIter;
capitalizationBrkIter = NULL;
}
ures_close(localeBundle);
}
#endif
}
@ -466,6 +486,7 @@ LocaleDisplayNamesImpl::~LocaleDisplayNamesImpl() {
delete separatorFormat;
delete format;
delete keyTypeFormat;
delete capitalizationBrkIter;
}
const Locale&
@ -496,51 +517,10 @@ LocaleDisplayNamesImpl::adjustForUsageAndContext(CapContextUsage usage,
UnicodeString& result) const {
#if !UCONFIG_NO_BREAK_ITERATION
// check to see whether we need to titlecase result
UBool titlecase = FALSE;
switch (capitalizationContext) {
case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
titlecase = TRUE;
break;
case UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU:
titlecase = fCapitalization[usage][0];
break;
case UDISPCTX_CAPITALIZATION_FOR_STANDALONE:
titlecase = fCapitalization[usage][1];
break;
default:
// titlecase = FALSE;
break;
}
if (titlecase) {
// TODO: Fix this titlecase hack when we figure out something better to do.
// We don't want to titlecase the whole text, only something like the first word,
// of the first segment long enough to have a complete cluster, whichever is
// shorter. We could have keep a word break iterator around, but I am not sure
// that will do the ight thing for the purposes here. For now we assume that in
// languages for which titlecasing makes a difference, we can stop at non-letter
// characters in 0x0000-0x00FF and only titlecase up to the first occurrence of
// any of those, or to a small number of chars, whichever comes first.
int32_t stopPos, stopPosLimit = 8, len = result.length();
if ( stopPosLimit > len ) {
stopPosLimit = len;
}
for ( stopPos = 0; stopPos < stopPosLimit; stopPos++ ) {
UChar32 ch = result.char32At(stopPos);
if ( (ch < 0x41) || (ch > 0x5A && ch < 0x61) || (ch > 0x7A && ch < 0xC0) ) {
break;
}
if (ch >= 0x10000) {
stopPos++;
}
}
if ( stopPos > 0 && stopPos < len ) {
UnicodeString firstWord(result, 0, stopPos);
firstWord.toTitle(NULL, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
result.replaceBetween(0, stopPos, firstWord);
} else {
// no stopPos, titlecase the whole text
result.toTitle(NULL, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
}
if ( result.length() > 0 && u_islower(result.char32At(0)) && capitalizationBrkIter!= NULL &&
( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE || fCapitalization[usage] ) ) {
// note fCapitalization[usage] won't be set unless capitalizationContext is UI_LIST_OR_MENU or STANDALONE
result.toTitle(capitalizationBrkIter, locale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
}
#endif
return result;

View file

@ -1519,6 +1519,10 @@ RuleBasedNumberFormat::setContext(UDisplayContext value, UErrorCode& status)
(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
}

View file

@ -17,6 +17,7 @@
#include "unicode/msgfmt.h"
#include "unicode/udisplaycontext.h"
#include "unicode/uchar.h"
#include "unicode/brkiter.h"
#include "gregoimp.h" // for CalendarData
#include "cmemory.h"
@ -45,7 +46,11 @@ RelativeDateFormat::RelativeDateFormat(const RelativeDateFormat& other) :
fDateStyle(other.fDateStyle), fLocale(other.fLocale),
fDayMin(other.fDayMin), fDayMax(other.fDayMax),
fDatesLen(other.fDatesLen), fDates(NULL),
fCombinedHasDateAtStart(other.fCombinedHasDateAtStart)
fCombinedHasDateAtStart(other.fCombinedHasDateAtStart),
fCapitalizationInfoSet(other.fCapitalizationInfoSet),
fCapitalizationOfRelativeUnitsForUIListMenu(other.fCapitalizationOfRelativeUnitsForUIListMenu),
fCapitalizationOfRelativeUnitsForStandAlone(other.fCapitalizationOfRelativeUnitsForStandAlone),
fCapitalizationBrkIter(NULL)
{
if(other.fDateTimeFormatter != NULL) {
fDateTimeFormatter = (SimpleDateFormat*)other.fDateTimeFormatter->clone();
@ -57,15 +62,18 @@ RelativeDateFormat::RelativeDateFormat(const RelativeDateFormat& other) :
fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*fDatesLen);
uprv_memcpy(fDates, other.fDates, sizeof(fDates[0])*fDatesLen);
}
fCapitalizationForRelativeUnits[0] = other.fCapitalizationForRelativeUnits[0];
fCapitalizationForRelativeUnits[1] = other.fCapitalizationForRelativeUnits[1];
if (other.fCapitalizationBrkIter != NULL) {
fCapitalizationBrkIter = (other.fCapitalizationBrkIter)->clone();
}
}
RelativeDateFormat::RelativeDateFormat( UDateFormatStyle timeStyle, UDateFormatStyle dateStyle,
const Locale& locale, UErrorCode& status) :
DateFormat(), fDateTimeFormatter(NULL), fDatePattern(), fTimePattern(), fCombinedFormat(NULL),
fDateStyle(dateStyle), fLocale(locale), fDayMin(0), fDayMax(0), fDatesLen(0), fDates(NULL),
fCombinedHasDateAtStart(FALSE)
fCombinedHasDateAtStart(FALSE), fCapitalizationInfoSet(FALSE),
fCapitalizationOfRelativeUnitsForUIListMenu(FALSE), fCapitalizationOfRelativeUnitsForStandAlone(FALSE),
fCapitalizationBrkIter(NULL)
{
if(U_FAILURE(status) ) {
return;
@ -116,6 +124,7 @@ RelativeDateFormat::~RelativeDateFormat() {
delete fDateTimeFormatter;
delete fCombinedFormat;
uprv_free(fDates);
delete fCapitalizationBrkIter;
}
@ -125,6 +134,8 @@ Format* RelativeDateFormat::clone(void) const {
UBool RelativeDateFormat::operator==(const Format& other) const {
if(DateFormat::operator==(other)) {
// The DateFormat::operator== check for fCapitalizationContext equality above
// is sufficient to check equality of all derived context-related data.
// DateFormat::operator== guarantees following cast is safe
RelativeDateFormat* that = (RelativeDateFormat*)&other;
return (fDateStyle==that->fDateStyle &&
@ -158,34 +169,16 @@ UnicodeString& RelativeDateFormat::format( Calendar& cal,
if ( relativeDayString.length() > 0 && !fDatePattern.isEmpty() &&
(fTimePattern.isEmpty() || fCombinedFormat == NULL || fCombinedHasDateAtStart)) {
#if !UCONFIG_NO_BREAK_ITERATION
// capitalize relativeDayString according to context for relative, set formatter no context
if ( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
(capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationForRelativeUnits[0]) ||
(capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationForRelativeUnits[1]) ) {
// titlecase first word of relativeDayString, do like LocaleDisplayNamesImpl::adjustForUsageAndContext
int32_t stopPos, stopPosLimit = 8;
if ( stopPosLimit > len ) {
stopPosLimit = len;
}
for ( stopPos = 0; stopPos < stopPosLimit; stopPos++ ) {
UChar32 ch = relativeDayString.char32At(stopPos);
int32_t wb = u_getIntPropertyValue(ch, UCHAR_WORD_BREAK);
if (!(u_islower(ch) || wb==U_WB_EXTEND || wb==U_WB_SINGLE_QUOTE || wb==U_WB_MIDNUMLET || wb==U_WB_MIDLETTER)) {
break;
}
if (ch >= 0x10000) {
stopPos++;
}
}
if ( stopPos > 0 && stopPos < len ) {
UnicodeString firstWord(relativeDayString, 0, stopPos);
firstWord.toTitle(NULL, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
relativeDayString.replaceBetween(0, stopPos, firstWord);
} else {
// no stopPos, titlecase the whole text
relativeDayString.toTitle(NULL, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
}
if ( u_islower(relativeDayString.char32At(0)) && fCapitalizationBrkIter!= NULL &&
( capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
(capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationOfRelativeUnitsForUIListMenu) ||
(capitalizationContext==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationOfRelativeUnitsForStandAlone) ) ) {
// titlecase first word of relativeDayString
relativeDayString.toTitle(fCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
}
#endif
fDateTimeFormatter->setContext(UDISPCTX_CAPITALIZATION_NONE, status);
} else {
// set our context for the formatter
@ -427,6 +420,54 @@ RelativeDateFormat::getDateFormatSymbols() const
return fDateTimeFormatter->getDateFormatSymbols();
}
// override the DateFormat implementation in order to
// lazily initialize relevant items
void
RelativeDateFormat::setContext(UDisplayContext value, UErrorCode& status)
{
DateFormat::setContext(value, status);
if (U_SUCCESS(status)) {
if (!fCapitalizationInfoSet &&
(value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE)) {
initCapitalizationContextInfo(fLocale);
fCapitalizationInfoSet = TRUE;
}
#if !UCONFIG_NO_BREAK_ITERATION
if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
(value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU && fCapitalizationOfRelativeUnitsForUIListMenu) ||
(value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE && fCapitalizationOfRelativeUnitsForStandAlone)) ) {
UErrorCode status = U_ZERO_ERROR;
fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
if (U_FAILURE(status)) {
delete fCapitalizationBrkIter;
fCapitalizationBrkIter = NULL;
}
}
#endif
}
}
void
RelativeDateFormat::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, "relative", 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) {
fCapitalizationOfRelativeUnitsForUIListMenu = intVector[0];
fCapitalizationOfRelativeUnitsForStandAlone = intVector[1];
}
}
ures_close(rb);
#endif
}
static const UChar patItem1[] = {0x7B,0x31,0x7D}; // "{1}"
static const int32_t patItem1Len = 3;
@ -473,35 +514,21 @@ void RelativeDateFormat::loadDates(UErrorCode &status) {
}
}
fCapitalizationForRelativeUnits[0] = fCapitalizationForRelativeUnits[1] = FALSE;
UResourceBundle *lb = ures_open(NULL, fLocale.getBaseName(), &status);
tempStatus = status;
UResourceBundle *rb = ures_getByKeyWithFallback(lb, "contextTransforms", NULL, &tempStatus);
UResourceBundle *sb = ures_getByKeyWithFallback(rb, "relative", NULL, &tempStatus);
if (U_SUCCESS(tempStatus) && sb != NULL) {
int32_t len = 0;
const int32_t * intVector = ures_getIntVector(sb, &len, &tempStatus);
if (U_SUCCESS(tempStatus) && intVector != NULL && len >= 2) {
fCapitalizationForRelativeUnits[0] = intVector[0];
fCapitalizationForRelativeUnits[1] = intVector[1];
}
}
sb = ures_getByKeyWithFallback(lb, "fields", sb, &status);
rb = ures_getByKeyWithFallback(sb, "day", rb, &status);
sb = ures_getByKeyWithFallback(rb, "relative", sb, &status);
ures_close(rb);
ures_close(lb);
UResourceBundle *rb = ures_open(NULL, fLocale.getBaseName(), &status);
rb = ures_getByKeyWithFallback(rb, "fields", rb, &status);
rb = ures_getByKeyWithFallback(rb, "day", rb, &status);
rb = ures_getByKeyWithFallback(rb, "relative", rb, &status);
// set up min/max
fDayMin=-1;
fDayMax=1;
if(U_FAILURE(status)) {
fDatesLen=0;
ures_close(sb);
ures_close(rb);
return;
}
fDatesLen = ures_getSize(sb);
fDatesLen = ures_getSize(rb);
fDates = (URelativeString*) uprv_malloc(sizeof(fDates[0])*fDatesLen);
// Load in each item into the array...
@ -509,8 +536,8 @@ void RelativeDateFormat::loadDates(UErrorCode &status) {
UResourceBundle *subString = NULL;
while(ures_hasNext(sb) && U_SUCCESS(status)) { // iterate over items
subString = ures_getNextResource(sb, subString, &status);
while(ures_hasNext(rb) && U_SUCCESS(status)) { // iterate over items
subString = ures_getNextResource(rb, subString, &status);
if(U_FAILURE(status) || (subString==NULL)) break;
@ -542,7 +569,7 @@ void RelativeDateFormat::loadDates(UErrorCode &status) {
n++;
}
ures_close(subString);
ures_close(sb);
ures_close(rb);
// the fDates[] array could be sorted here, for direct access.
}

View file

@ -19,6 +19,7 @@
#include "unicode/datefmt.h"
#include "unicode/smpdtfmt.h"
#include "unicode/brkiter.h"
U_NAMESPACE_BEGIN
@ -232,6 +233,19 @@ public:
*/
virtual const DateFormatSymbols* getDateFormatSymbols(void) const;
/* Cannot use #ifndef U_HIDE_DRAFT_API for the following draft method since it is virtual */
/**
* Set a particular UDisplayContext value in the formatter, such as
* UDISPCTX_CAPITALIZATION_FOR_STANDALONE. Note: For getContext, see
* DateFormat.
* @param value The UDisplayContext value to set.
* @param status Input/output status. If at entry this indicates a failure
* status, the function will do nothing; otherwise this will be
* updated with any new status from the function.
* @internal ICU 53
*/
virtual void setContext(UDisplayContext value, UErrorCode& status);
private:
SimpleDateFormat *fDateTimeFormatter;
UnicodeString fDatePattern;
@ -246,8 +260,11 @@ private:
int32_t fDatesLen; // Length of array
URelativeString *fDates; // array of strings
UBool fCapitalizationForRelativeUnits[2];
UBool fCombinedHasDateAtStart;
UBool fCapitalizationInfoSet;
UBool fCapitalizationOfRelativeUnitsForUIListMenu;
UBool fCapitalizationOfRelativeUnitsForStandAlone;
BreakIterator* fCapitalizationBrkIter;
/**
* Get the string at a specific offset.
@ -262,6 +279,11 @@ private:
*/
void loadDates(UErrorCode &status);
/**
* Set fCapitalizationOfRelativeUnitsForUIListMenu, fCapitalizationOfRelativeUnitsForStandAlone
*/
void initCapitalizationContextInfo(const Locale& thelocale);
/**
* @return the number of days in "until-now"
*/

View file

@ -49,6 +49,7 @@
#include "unicode/utf16.h"
#include "unicode/vtzone.h"
#include "unicode/udisplaycontext.h"
#include "unicode/brkiter.h"
#include "olsontz.h"
#include "patternprops.h"
#include "fphdlimp.h"
@ -236,6 +237,8 @@ SimpleDateFormat::~SimpleDateFormat()
delete cur->nf;
uprv_free(cur);
}
delete fCapitalizationBrkIter;
}
//----------------------------------------------------------------------
@ -245,7 +248,8 @@ SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
fSymbols(NULL),
fTimeZoneFormat(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
fOverrideList(NULL),
fCapitalizationBrkIter(NULL)
{
initializeBooleanAttributes();
construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
@ -261,7 +265,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fSymbols(NULL),
fTimeZoneFormat(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
fOverrideList(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setToBogus();
fTimeOverride.setToBogus();
@ -281,7 +286,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fSymbols(NULL),
fTimeZoneFormat(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
fOverrideList(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setTo(override);
fTimeOverride.setToBogus();
@ -303,7 +309,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fLocale(locale),
fTimeZoneFormat(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
fOverrideList(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setToBogus();
@ -325,7 +332,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fLocale(locale),
fTimeZoneFormat(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
fOverrideList(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setTo(override);
@ -350,7 +358,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fSymbols(symbolsToAdopt),
fTimeZoneFormat(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
fOverrideList(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setToBogus();
@ -372,7 +381,8 @@ SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
fSymbols(new DateFormatSymbols(symbols)),
fTimeZoneFormat(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
fOverrideList(NULL),
fCapitalizationBrkIter(NULL)
{
fDateOverride.setToBogus();
@ -395,7 +405,8 @@ SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
fSymbols(NULL),
fTimeZoneFormat(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
fOverrideList(NULL),
fCapitalizationBrkIter(NULL)
{
initializeBooleanAttributes();
construct(timeStyle, dateStyle, fLocale, status);
@ -418,7 +429,8 @@ SimpleDateFormat::SimpleDateFormat(const Locale& locale,
fSymbols(NULL),
fTimeZoneFormat(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
fOverrideList(NULL),
fCapitalizationBrkIter(NULL)
{
if (U_FAILURE(status)) return;
initializeBooleanAttributes();
@ -453,7 +465,8 @@ SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
fSymbols(NULL),
fTimeZoneFormat(NULL),
fNumberFormatters(NULL),
fOverrideList(NULL)
fOverrideList(NULL),
fCapitalizationBrkIter(NULL)
{
initializeBooleanAttributes();
*this = other;
@ -486,6 +499,10 @@ SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
fTimeZoneFormat = NULL; // forces lazy instantiation with the other locale
fLocale = other.fLocale;
}
if (other.fCapitalizationBrkIter != NULL) {
fCapitalizationBrkIter = (other.fCapitalizationBrkIter)->clone();
}
return *this;
}
@ -504,6 +521,8 @@ UBool
SimpleDateFormat::operator==(const Format& other) const
{
if (DateFormat::operator==(other)) {
// The DateFormat::operator== check for fCapitalizationContext equality above
// is sufficient to check equality of all derived context-related data.
// DateFormat::operator== guarantees following cast is safe
SimpleDateFormat* that = (SimpleDateFormat*)&other;
return (fPattern == that->fPattern &&
@ -1591,8 +1610,8 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
break;
}
#if !UCONFIG_NO_BREAK_ITERATION
if (fieldNum == 0) {
// first field, check to see whether we need to titlecase it
// if first field, check to see whether we need to and are able to titlecase it
if (fieldNum == 0 && u_islower(appendTo.char32At(beginOffset)) && fCapitalizationBrkIter != NULL) {
UBool titlecase = FALSE;
switch (capitalizationContext) {
case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
@ -1610,7 +1629,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
}
if (titlecase) {
UnicodeString firstField(appendTo, beginOffset);
firstField.toTitle(NULL, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
firstField.toTitle(fCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
appendTo.replaceBetween(beginOffset, appendTo.length(), firstField);
}
}
@ -3275,6 +3294,31 @@ void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
//----------------------------------------------------------------------
// override the DateFormat implementation in order to
// lazily initialize fCapitalizationBrkIter
void
SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status)
{
DateFormat::setContext(value, status);
#if !UCONFIG_NO_BREAK_ITERATION
if (U_SUCCESS(status)) {
if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) {
UErrorCode status = U_ZERO_ERROR;
fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
if (U_FAILURE(status)) {
delete fCapitalizationBrkIter;
fCapitalizationBrkIter = NULL;
}
}
}
#endif
}
//----------------------------------------------------------------------
UBool
SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
return isFieldUnitIgnored(fPattern, field);

View file

@ -981,11 +981,7 @@ private:
UBool capitalizationInfoSet;
UBool capitalizationForUIListMenu;
UBool capitalizationForStandAlone;
#if !UCONFIG_NO_BREAK_ITERATION
BreakIterator* capitalizationBrkIter;
#else
void* capitalizationBrkIter;
#endif
};
// ---------------

View file

@ -36,6 +36,7 @@
#include "unicode/datefmt.h"
#include "unicode/udisplaycontext.h"
#include "unicode/tzfmt.h" /* for UTimeZoneFormatTimeType */
#include "unicode/brkiter.h"
U_NAMESPACE_BEGIN
@ -1108,6 +1109,19 @@ public:
*/
virtual const TimeZoneFormat* getTimeZoneFormat(void) const;
/* Cannot use #ifndef U_HIDE_DRAFT_API for the following draft method since it is virtual */
/**
* Set a particular UDisplayContext value in the formatter, such as
* UDISPCTX_CAPITALIZATION_FOR_STANDALONE. Note: For getContext, see
* DateFormat.
* @param value The UDisplayContext value to set.
* @param status Input/output status. If at entry this indicates a failure
* status, the function will do nothing; otherwise this will be
* updated with any new status from the function.
* @draft ICU 53
*/
virtual void setContext(UDisplayContext value, UErrorCode& status);
#ifndef U_HIDE_INTERNAL_API
/**
* This is for ICU internal use only. Please do not use.
@ -1516,6 +1530,8 @@ private:
NSOverride *fOverrideList;
UBool fHaveDefaultCentury;
BreakIterator* fCapitalizationBrkIter;
};
inline UDate

View file

@ -1,6 +1,6 @@
/*********************************************************************
* COPYRIGHT:
* Copyright (c) 2010-2013, International Business Machines Corporation and
* Copyright (c) 2010-2014, International Business Machines Corporation and
* others. All Rights Reserved.
*********************************************************************/
@ -294,14 +294,21 @@ static const LocNameDispContextItem ctxtItems[] = {
{ "da", UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, en_US, daFor_en_US_DT },
{ "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, en, esFor_en_T },
{ "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, en_US, esFor_en_US_T },
{ "es", UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, en_US, esFor_en_US_DT },
{ "es", UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, en_US, esFor_en_US_DT },
{ "da", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, en, daFor_en_T },
{ "da", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, en_US, daFor_en_US_T },
{ "da", UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, en_US, daFor_en_US_DT },
{ "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, en, esFor_en_T },
{ "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, en_US, esFor_en_US_T },
{ "es", UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE, en_US, esFor_en_US_DT },
{ "es", UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU, en_US, esFor_en_US_DT },
{ "da", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, en, daFor_en },
{ "da", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, en_US, daFor_en_US },
{ "da", UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, en_US, daFor_en_US_D },
{ "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, en, esFor_en_T },
{ "es", UDISPCTX_STANDARD_NAMES, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, en_US, esFor_en_US_T },
{ "es", UDISPCTX_DIALECT_NAMES, UDISPCTX_CAPITALIZATION_FOR_STANDALONE, en_US, esFor_en_US_DT },
#endif /* #if !UCONFIG_NO_BREAK_ITERATION */
{ NULL, (UDisplayContext)0, (UDisplayContext)0, NULL, NULL }
};