diff --git a/icu4c/source/i18n/tmutfmt.cpp b/icu4c/source/i18n/tmutfmt.cpp index dc355a0365e..e2394ed3ab9 100644 --- a/icu4c/source/i18n/tmutfmt.cpp +++ b/icu4c/source/i18n/tmutfmt.cpp @@ -1,6 +1,6 @@ /* ******************************************************************************* - * Copyright (C) 2008-2011, Google, International Business Machines Corporation + * Copyright (C) 2008-2012, Google, International Business Machines Corporation * and others. All Rights Reserved. ******************************************************************************* */ @@ -386,9 +386,19 @@ TimeUnitFormat::create(const Locale& locale, UTimeUnitFormatStyle style, UErrorC void TimeUnitFormat::setup(UErrorCode& err) { initDataMembers(err); - readFromCurrentLocale(UTMUTFMT_FULL_STYLE, gUnitsTag, err); + + UVector pluralCounts(0, uhash_compareUnicodeString, 6, err); + StringEnumeration* keywords = fPluralRules->getKeywords(err); + if (U_FAILURE(err)) { + return; + } + UnicodeString* pluralCount; + while ((pluralCount = const_cast(keywords->snext(err))) != NULL) { + pluralCounts.addElement(pluralCount, err); + } + readFromCurrentLocale(UTMUTFMT_FULL_STYLE, gUnitsTag, pluralCounts, err); checkConsistency(UTMUTFMT_FULL_STYLE, gUnitsTag, err); - readFromCurrentLocale(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, err); + readFromCurrentLocale(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, pluralCounts, err); checkConsistency(UTMUTFMT_ABBREVIATED_STYLE, gShortUnitsTag, err); } @@ -415,7 +425,8 @@ TimeUnitFormat::initDataMembers(UErrorCode& err){ void -TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, const char* key, UErrorCode& err) { +TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, const char* key, + const UVector& pluralCounts, UErrorCode& err) { if (U_FAILURE(err)) { return; } @@ -490,12 +501,15 @@ TimeUnitFormat::readFromCurrentLocale(UTimeUnitFormatStyle style, const char* ke if (U_FAILURE(status)) { continue; } + UnicodeString pluralCountUniStr(pluralCount, -1, US_INV); + if (!pluralCounts.contains(&pluralCountUniStr)) { + continue; + } MessageFormat* messageFormat = new MessageFormat(pattern, fLocale, err); if ( U_SUCCESS(err) ) { if (fNumberFormat != NULL) { messageFormat->setFormat(0, *fNumberFormat); } - UnicodeString pluralCountUniStr(pluralCount, -1, US_INV); MessageFormat** formatters = (MessageFormat**)countToPatterns->get(pluralCountUniStr); if (formatters == NULL) { formatters = (MessageFormat**)uprv_malloc(UTMUTFMT_FORMAT_STYLE_COUNT*sizeof(MessageFormat*)); @@ -763,6 +777,7 @@ TimeUnitFormat::setNumberFormat(const NumberFormat& format, UErrorCode& status){ while ((elem = fTimeUnitToCountToPatterns[i]->nextElement(pos)) != NULL){ const UHashTok keyTok = elem->value; MessageFormat** pattern = (MessageFormat**)keyTok.pointer; + pattern[UTMUTFMT_FULL_STYLE]->setFormat(0, format); pattern[UTMUTFMT_ABBREVIATED_STYLE]->setFormat(0, format); } diff --git a/icu4c/source/i18n/unicode/tmutfmt.h b/icu4c/source/i18n/unicode/tmutfmt.h index a2acc7a6bfa..dd9aa36f45f 100644 --- a/icu4c/source/i18n/unicode/tmutfmt.h +++ b/icu4c/source/i18n/unicode/tmutfmt.h @@ -24,6 +24,7 @@ #include "unicode/measfmt.h" #include "unicode/numfmt.h" #include "unicode/plurrule.h" +#include "uvector.h" /** * Constants for various styles. @@ -229,7 +230,8 @@ private: void initDataMembers(UErrorCode& status); // initialize fTimeUnitToCountToPatterns from current locale's resource. - void readFromCurrentLocale(UTimeUnitFormatStyle style, const char* key, UErrorCode& status); + void readFromCurrentLocale(UTimeUnitFormatStyle style, const char* key, const UVector& pluralCounts, + UErrorCode& status); // check completeness of fTimeUnitToCountToPatterns against all time units, // and all plural rules, fill in fallback as necessary. diff --git a/icu4c/source/test/intltest/tufmtts.cpp b/icu4c/source/test/intltest/tufmtts.cpp index 90efa96fcf2..e4268d04e16 100644 --- a/icu4c/source/test/intltest/tufmtts.cpp +++ b/icu4c/source/test/intltest/tufmtts.cpp @@ -1,5 +1,5 @@ /******************************************************************** - * Copyright (c) 2008-2011, International Business Machines Corporation and + * Copyright (c) 2008-2012, International Business Machines Corporation and * others. All Rights Reserved. ********************************************************************/ @@ -25,7 +25,8 @@ void TimeUnitTest::runIndexedTest( int32_t index, UBool exec, const char* &name, switch (index) { TESTCASE(0, testBasic); TESTCASE(1, testAPI); - TESTCASE(2, testGreek); + TESTCASE(2, testGreekWithFallback); + TESTCASE(3, testGreekWithSanitization); default: name = ""; break; } } @@ -208,7 +209,7 @@ void TimeUnitTest::testAPI() { * to long unit names for a locale where the locale data does not * provide short unit names. As of CLDR 1.9, Greek is one such language. */ -void TimeUnitTest::testGreek() { +void TimeUnitTest::testGreekWithFallback() { UErrorCode status = U_ZERO_ERROR; const char* locales[] = {"el-GR", "el"}; @@ -323,4 +324,23 @@ void TimeUnitTest::testGreek() { } } +// Test bug9042 +void TimeUnitTest::testGreekWithSanitization() { + + UErrorCode status = U_ZERO_ERROR; + Locale elLoc("el"); + NumberFormat* numberFmt = NumberFormat::createInstance(Locale("el"), status); + if (!assertSuccess("NumberFormat::createInstance for el locale", status)) return; + numberFmt->setMaximumFractionDigits(1); + + TimeUnitFormat* timeUnitFormat = new TimeUnitFormat(elLoc, status); + if (!assertSuccess("TimeUnitFormat::TimeUnitFormat for el locale", status)) return; + + timeUnitFormat->setNumberFormat(*numberFmt, status); + + delete numberFmt; + delete timeUnitFormat; +} + + #endif diff --git a/icu4c/source/test/intltest/tufmtts.h b/icu4c/source/test/intltest/tufmtts.h index 3910f4a2db8..45e841cb806 100644 --- a/icu4c/source/test/intltest/tufmtts.h +++ b/icu4c/source/test/intltest/tufmtts.h @@ -1,6 +1,6 @@ /******************************************************************** * COPYRIGHT: - * Copyright (c) 2008-2010, International Business Machines Corporation + * Copyright (c) 2008-2012, International Business Machines Corporation * and others. All Rights Reserved. ********************************************************************/ @@ -37,7 +37,18 @@ public: * to long unit names for a locale where the locale data does not * provide short unit names. As of CLDR 1.9, Greek is one such language. **/ - void testGreek(); + void testGreekWithFallback(); + + /** + * Performs tests for Greek + * This tests that if the plural count listed in time unit format does not + * match those in the plural rules for the locale, those plural count in + * time unit format will be ingored and subsequently, fall back will kick in + * which is tested above. + * Without data sanitization, setNumberFormat() would crash. + * As of CLDR shiped in ICU4.8, Greek is one such language. + */ + void testGreekWithSanitization(); }; #endif /* #if !UCONFIG_NO_FORMATTING */