ICU-12029 Measure unit display names, C++ version.

X-SVN-Rev: 39243
This commit is contained in:
Shane Carr 2016-09-15 08:37:56 +00:00
parent f8620a567b
commit 5b9fc6fc70
3 changed files with 111 additions and 5 deletions

View File

@ -110,6 +110,7 @@ public:
UMeasureFormatWidth widthFallback[WIDTH_INDEX_COUNT];
/** Measure unit -> format width -> array of patterns ("{0} meters") (plurals + PER_UNIT_INDEX) */
SimpleFormatter *patterns[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT][PATTERN_COUNT];
const UChar* dnams[MEAS_UNIT_COUNT][WIDTH_INDEX_COUNT];
SimpleFormatter perFormatters[WIDTH_INDEX_COUNT];
MeasureFormatCacheData();
@ -159,6 +160,7 @@ MeasureFormatCacheData::MeasureFormatCacheData() {
currencyFormats[i] = NULL;
}
uprv_memset(patterns, 0, sizeof(patterns));
uprv_memset(dnams, 0, sizeof(dnams));
integerFormat = NULL;
numericDateFormatters = NULL;
}
@ -174,6 +176,7 @@ MeasureFormatCacheData::~MeasureFormatCacheData() {
}
}
}
// Note: the contents of 'dnams' are pointers into the resource bundle
delete integerFormat;
delete numericDateFormatters;
}
@ -232,17 +235,25 @@ struct UnitDataSink : public ResourceSink {
void setFormatterIfAbsent(int32_t index, const ResourceValue &value,
int32_t minPlaceholders, UErrorCode &errorCode) {
SimpleFormatter **patterns =
&cacheData.patterns[unitIndex][width][0];
SimpleFormatter **patterns = &cacheData.patterns[unitIndex][width][0];
if (U_SUCCESS(errorCode) && patterns[index] == NULL) {
patterns[index] = new SimpleFormatter(
value.getUnicodeString(errorCode), minPlaceholders, 1, errorCode);
if (minPlaceholders >= 0) {
patterns[index] = new SimpleFormatter(
value.getUnicodeString(errorCode), minPlaceholders, 1, errorCode);
}
if (U_SUCCESS(errorCode) && patterns[index] == NULL) {
errorCode = U_MEMORY_ALLOCATION_ERROR;
}
}
}
void setDnamIfAbsent(const ResourceValue &value, UErrorCode& errorCode) {
if (cacheData.dnams[unitIndex][width] == NULL) {
int32_t length;
cacheData.dnams[unitIndex][width] = value.getString(length, errorCode);
}
}
/**
* Consume a display pattern. For example,
* unitsShort/duration/hour contains other{"{0} hrs"}.
@ -250,7 +261,8 @@ struct UnitDataSink : public ResourceSink {
void consumePattern(const char *key, const ResourceValue &value, UErrorCode &errorCode) {
if (U_FAILURE(errorCode)) { return; }
if (uprv_strcmp(key, "dnam") == 0) {
// Skip the unit display name for now.
// The display name for the unit in the current width.
setDnamIfAbsent(value, errorCode);
} else if (uprv_strcmp(key, "per") == 0) {
// For example, "{0}/h".
setFormatterIfAbsent(MeasureFormatCacheData::PER_UNIT_INDEX, value, 1, errorCode);
@ -817,6 +829,24 @@ UnicodeString &MeasureFormat::formatMeasures(
return appendTo;
}
UnicodeString MeasureFormat::getUnitDisplayName(const MeasureUnit& unit, UErrorCode& /*status*/) const {
UMeasureFormatWidth width = getRegularWidth(this->width);
const UChar* const* styleToDnam = cache->dnams[unit.getIndex()];
const UChar* dnam = styleToDnam[width];
if (dnam == NULL) {
int32_t fallbackWidth = cache->widthFallback[width];
dnam = styleToDnam[fallbackWidth];
}
UnicodeString result;
if (dnam == NULL) {
result.setToBogus();
} else {
result.setTo(dnam, -1);
}
return result;
}
void MeasureFormat::initMeasureFormat(
const Locale &locale,
UMeasureFormatWidth w,

View File

@ -210,6 +210,19 @@ class U_I18N_API MeasureFormat : public Format {
FieldPosition &pos,
UErrorCode &status) const;
/**
* Gets the display name of the specified {@link MeasureUnit} corresponding to the current
* locale and format width.
* @param unit The unit for which to get a display name.
* @param status the error.
* @return The display name in the locale and width specified in
* {@link MeasureFormat#getInstance}, or null if there is no display name available
* for the specified unit.
*
* @draft ICU 58
*/
UnicodeString getUnitDisplayName(const MeasureUnit& unit, UErrorCode &status) const;
/**
* Return a formatter for CurrencyAmount objects in the given

View File

@ -24,6 +24,7 @@
#include "unicode/tmunit.h"
#include "unicode/plurrule.h"
#include "charstr.h"
#include "cstr.h"
#include "unicode/reldatefmt.h"
struct ExpectedResult {
@ -58,6 +59,7 @@ private:
void TestManyLocaleDurations();
void TestGram();
void TestCurrencies();
void TestDisplayNames();
void TestFieldPosition();
void TestFieldPositionMultiple();
void TestBadArg();
@ -111,6 +113,11 @@ private:
const Measure *measures,
int32_t measureCount,
const char *expected);
void helperTestDisplayName(
const MeasureUnit *unit,
const char *localeID,
UMeasureFormatWidth width,
const char *expected);
void verifyFieldPosition(
const char *description,
const MeasureFormat &fmt,
@ -147,6 +154,7 @@ void MeasureFormatTest::runIndexedTest(
TESTCASE_AUTO(TestManyLocaleDurations);
TESTCASE_AUTO(TestGram);
TESTCASE_AUTO(TestCurrencies);
TESTCASE_AUTO(TestDisplayNames);
TESTCASE_AUTO(TestFieldPosition);
TESTCASE_AUTO(TestFieldPositionMultiple);
TESTCASE_AUTO(TestBadArg);
@ -1592,6 +1600,61 @@ void MeasureFormatTest::TestCurrencies() {
verifyFormat("TestCurrenciesNumeric", fmt, &USD_2, 1, "$2.00");
}
void MeasureFormatTest::TestDisplayNames() {
UErrorCode status = U_ZERO_ERROR;
helperTestDisplayName( MeasureUnit::createYear(status), "en", UMEASFMT_WIDTH_WIDE, "years" );
helperTestDisplayName( MeasureUnit::createYear(status), "ja", UMEASFMT_WIDTH_WIDE, "\\u5E74" );
helperTestDisplayName( MeasureUnit::createYear(status), "es", UMEASFMT_WIDTH_WIDE, "a\\u00F1os" );
helperTestDisplayName( MeasureUnit::createYear(status), "pt", UMEASFMT_WIDTH_WIDE, "anos" );
helperTestDisplayName( MeasureUnit::createYear(status), "pt-PT", UMEASFMT_WIDTH_WIDE, "anos" );
helperTestDisplayName( MeasureUnit::createAmpere(status), "en", UMEASFMT_WIDTH_WIDE, "amperes" );
helperTestDisplayName( MeasureUnit::createAmpere(status), "ja", UMEASFMT_WIDTH_WIDE, "\\u30A2\\u30F3\\u30DA\\u30A2" );
helperTestDisplayName( MeasureUnit::createAmpere(status), "es", UMEASFMT_WIDTH_WIDE, "amperios" );
helperTestDisplayName( MeasureUnit::createAmpere(status), "pt", UMEASFMT_WIDTH_WIDE, "amperes" );
helperTestDisplayName( MeasureUnit::createAmpere(status), "pt-PT", UMEASFMT_WIDTH_WIDE, "amperes" );
helperTestDisplayName( MeasureUnit::createMeterPerSecondSquared(status), "pt", UMEASFMT_WIDTH_WIDE, "metros por segundo ao quadrado" );
helperTestDisplayName( MeasureUnit::createMeterPerSecondSquared(status), "pt-PT", UMEASFMT_WIDTH_WIDE, "metros por segundo quadrado" );
helperTestDisplayName( MeasureUnit::createSquareKilometer(status), "pt", UMEASFMT_WIDTH_NARROW, "km\\u00B2" );
helperTestDisplayName( MeasureUnit::createSquareKilometer(status), "pt", UMEASFMT_WIDTH_SHORT, "km\\u00B2" );
helperTestDisplayName( MeasureUnit::createSquareKilometer(status), "pt", UMEASFMT_WIDTH_WIDE, "quil\\u00F4metros quadrados" );
helperTestDisplayName( MeasureUnit::createSecond(status), "pt-PT", UMEASFMT_WIDTH_NARROW, "s" );
helperTestDisplayName( MeasureUnit::createSecond(status), "pt-PT", UMEASFMT_WIDTH_SHORT, "s" );
helperTestDisplayName( MeasureUnit::createSecond(status), "pt-PT", UMEASFMT_WIDTH_WIDE, "segundos" );
helperTestDisplayName( MeasureUnit::createSecond(status), "pt", UMEASFMT_WIDTH_NARROW, "seg" );
helperTestDisplayName( MeasureUnit::createSecond(status), "pt", UMEASFMT_WIDTH_SHORT, "segs" );
helperTestDisplayName( MeasureUnit::createSecond(status), "pt", UMEASFMT_WIDTH_WIDE, "segundos" );
assertSuccess("Error creating measure units", status);
}
void MeasureFormatTest::helperTestDisplayName(const MeasureUnit *unit,
const char *localeID,
UMeasureFormatWidth width,
const char *expected) {
UErrorCode status = U_ZERO_ERROR;
MeasureFormat fmt(Locale(localeID), width, status);
if (U_FAILURE(status)) {
errln("Could not create MeasureFormat for locale %s, width %d, status: %s",
localeID, (int)width, u_errorName(status));
return;
}
UnicodeString dnam = fmt.getUnitDisplayName(*unit, status);
if (U_FAILURE(status)) {
errln("MeasureFormat::getUnitDisplayName failed for unit %s-%s, locale %s, width %d, status: %s",
unit->getType(), unit->getSubtype(), localeID, (int)width, u_errorName(status));
return;
}
UnicodeString expStr(UnicodeString(expected).unescape());
if (dnam != expStr) {
errln("MeasureFormat::getUnitDisplayName for unit %s-%s, locale %s, width %d: expected \"%s\", got \"%s\"",
unit->getType(), unit->getSubtype(), localeID, (int)width, CStr(expStr)(), CStr(dnam)());
}
// Delete the measure unit
delete unit;
}
void MeasureFormatTest::TestFieldPosition() {
UErrorCode status = U_ZERO_ERROR;
MeasureFormat fmt("en", UMEASFMT_WIDTH_SHORT, status);