diff --git a/icu4c/source/data/build.xml b/icu4c/source/data/build.xml index 5fd1a993a12..a6eb039ea0b 100644 --- a/icu4c/source/data/build.xml +++ b/icu4c/source/data/build.xml @@ -27,7 +27,7 @@ - + @@ -47,8 +47,11 @@ + + + - + diff --git a/icu4c/source/data/cldr-icu-readme.txt b/icu4c/source/data/cldr-icu-readme.txt index b6f8ebe7bfc..d4ce2fd08e7 100644 --- a/icu4c/source/data/cldr-icu-readme.txt +++ b/icu4c/source/data/cldr-icu-readme.txt @@ -69,9 +69,8 @@ # # CLDR_DIR: Path to root of CLDR sources, below which are the common and # tools directories. -# CLDR_CLASSES: Defined relative to CLDR_DIR. It only needs to be set if you -# are not running ant jar for CLDR and have a non-default output -# folder for cldr-tools classes. +# CLDR_CLASSES: Path to the CLDR Tools classes directory. If not set, defaults +# to $CLDR_DIR/tools/java/classes # # c) ICU-related variables # These variables only need to be set if you're directly reusing the @@ -140,7 +139,6 @@ export ANT_OPTS="-Xmx3072m -DCLDR_DTD_CACHE=/tmp" # CLDR_DIR=`cygpath -wp /build/cldr` export CLDR_DIR=$HOME/cldr/trunk -#export CLDR_CLASSES=$CLDR_DIR/tools/java/classes # 1c. ICU variables @@ -148,9 +146,11 @@ export ICU4C_DIR=$HOME/icu/trunk/icu4c export ICU4J_ROOT=$HOME/icu/trunk/icu4j # 2. Build the CLDR Java tools +# Optionally build the jar, but ant will look inside the classes directory anyway cd $CLDR_DIR/tools/java -ant jar +ant all +#ant jar # 3. Configure ICU4C, build and test without new data first, to verify that # there are no pre-existing errors (configure shown here for MacOSX, adjust @@ -169,12 +169,16 @@ make check 2>&1 | tee /tmp/icu4c-oldData-makeCheck.txt # This process will take several minutes. # Keep a log so you can investigate anything that looks suspicious. # +# Running "ant setup" is not required, but it will print useful errors to +# debug issues with your path when it fails. +# # If you see timeout errors when building the rbnf data, for example, then the # system you are building on likely does not have its IP address whitelisted with # Unicode for access to the CLDR repository, see note on "IP address whitelisting" # near the top of this file. cd $ICU4C_DIR/source/data +ant setup ant clean ant all 2>&1 | tee /tmp/cldr-newData-buildLog.txt diff --git a/icu4c/source/data/unit/root.txt b/icu4c/source/data/unit/root.txt index 5ce0bf9b566..9410db52d08 100644 --- a/icu4c/source/data/unit/root.txt +++ b/icu4c/source/data/unit/root.txt @@ -198,6 +198,7 @@ root{ other{"{0} d"} per{"{0}/d"} } + day-person:alias{"/LOCALE/unitsShort/duration/day"} hour{ dnam{"hr"} other{"{0} h"} @@ -221,6 +222,7 @@ root{ other{"{0} m"} per{"{0}/m"} } + month-person:alias{"/LOCALE/unitsShort/duration/month"} nanosecond{ dnam{"ns"} other{"{0} ns"} @@ -235,11 +237,13 @@ root{ other{"{0} w"} per{"{0}/w"} } + week-person:alias{"/LOCALE/unitsShort/duration/week"} year{ dnam{"yr"} other{"{0} y"} per{"{0}/y"} } + year-person:alias{"/LOCALE/unitsShort/duration/year"} } electric{ ampere{ diff --git a/icu4c/source/i18n/measfmt.cpp b/icu4c/source/i18n/measfmt.cpp index 9830dc889e1..477341b4469 100644 --- a/icu4c/source/i18n/measfmt.cpp +++ b/icu4c/source/i18n/measfmt.cpp @@ -47,7 +47,7 @@ U_NAMESPACE_BEGIN static constexpr int32_t PER_UNIT_INDEX = StandardPlural::COUNT; static constexpr int32_t PATTERN_COUNT = PER_UNIT_INDEX + 1; -static constexpr int32_t MEAS_UNIT_COUNT = 142; // see assertion in MeasureFormatCacheData constructor +static constexpr int32_t MEAS_UNIT_COUNT = 146; // see assertion in MeasureFormatCacheData constructor static constexpr int32_t WIDTH_INDEX_COUNT = UMEASFMT_WIDTH_NARROW + 1; UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MeasureFormat) diff --git a/icu4c/source/i18n/measunit.cpp b/icu4c/source/i18n/measunit.cpp index a0c30b4ad30..e061cb458a2 100644 --- a/icu4c/source/i18n/measunit.cpp +++ b/icu4c/source/i18n/measunit.cpp @@ -43,19 +43,19 @@ static const int32_t gOffsets[] = { 26, 325, 336, - 347, 351, - 357, + 355, 361, - 381, - 382, - 393, - 396, - 402, - 408, + 365, + 385, + 386, + 397, + 400, + 406, 412, 416, - 441 + 420, + 445 }; static const int32_t gIndexes[] = { @@ -67,19 +67,19 @@ static const int32_t gIndexes[] = { 26, 26, 37, - 48, 52, - 58, + 56, 62, - 82, - 83, - 94, - 97, - 103, - 109, + 66, + 86, + 87, + 98, + 101, + 107, 113, 117, - 142 + 121, + 146 }; // Must be sorted alphabetically. @@ -446,15 +446,19 @@ static const char * const gSubTypes[] = { "terabyte", "century", "day", + "day-person", "hour", "microsecond", "millisecond", "minute", "month", + "month-person", "nanosecond", "second", "week", + "week-person", "year", + "year-person", "ampere", "milliampere", "ohm", @@ -553,14 +557,14 @@ static const char * const gSubTypes[] = { // Must be sorted by first value and then second value. static int32_t unitPerUnitToSingleUnit[][4] = { - {368, 338, 17, 0}, - {370, 344, 17, 2}, - {372, 338, 17, 3}, - {372, 430, 4, 2}, - {372, 431, 4, 3}, - {387, 428, 3, 1}, - {390, 11, 16, 5}, - {433, 368, 4, 1} + {372, 339, 17, 0}, + {374, 346, 17, 2}, + {376, 339, 17, 3}, + {376, 434, 4, 2}, + {376, 435, 4, 3}, + {391, 432, 3, 1}, + {394, 11, 16, 5}, + {437, 372, 4, 1} }; // Shortcuts to the base unit in order to make the default constructor fast @@ -879,78 +883,110 @@ MeasureUnit MeasureUnit::getDay() { return MeasureUnit(7, 1); } -MeasureUnit *MeasureUnit::createHour(UErrorCode &status) { +MeasureUnit *MeasureUnit::createDayPerson(UErrorCode &status) { return MeasureUnit::create(7, 2, status); } -MeasureUnit MeasureUnit::getHour() { +MeasureUnit MeasureUnit::getDayPerson() { return MeasureUnit(7, 2); } -MeasureUnit *MeasureUnit::createMicrosecond(UErrorCode &status) { +MeasureUnit *MeasureUnit::createHour(UErrorCode &status) { return MeasureUnit::create(7, 3, status); } -MeasureUnit MeasureUnit::getMicrosecond() { +MeasureUnit MeasureUnit::getHour() { return MeasureUnit(7, 3); } -MeasureUnit *MeasureUnit::createMillisecond(UErrorCode &status) { +MeasureUnit *MeasureUnit::createMicrosecond(UErrorCode &status) { return MeasureUnit::create(7, 4, status); } -MeasureUnit MeasureUnit::getMillisecond() { +MeasureUnit MeasureUnit::getMicrosecond() { return MeasureUnit(7, 4); } -MeasureUnit *MeasureUnit::createMinute(UErrorCode &status) { +MeasureUnit *MeasureUnit::createMillisecond(UErrorCode &status) { return MeasureUnit::create(7, 5, status); } -MeasureUnit MeasureUnit::getMinute() { +MeasureUnit MeasureUnit::getMillisecond() { return MeasureUnit(7, 5); } -MeasureUnit *MeasureUnit::createMonth(UErrorCode &status) { +MeasureUnit *MeasureUnit::createMinute(UErrorCode &status) { return MeasureUnit::create(7, 6, status); } -MeasureUnit MeasureUnit::getMonth() { +MeasureUnit MeasureUnit::getMinute() { return MeasureUnit(7, 6); } -MeasureUnit *MeasureUnit::createNanosecond(UErrorCode &status) { +MeasureUnit *MeasureUnit::createMonth(UErrorCode &status) { return MeasureUnit::create(7, 7, status); } -MeasureUnit MeasureUnit::getNanosecond() { +MeasureUnit MeasureUnit::getMonth() { return MeasureUnit(7, 7); } -MeasureUnit *MeasureUnit::createSecond(UErrorCode &status) { +MeasureUnit *MeasureUnit::createMonthPerson(UErrorCode &status) { return MeasureUnit::create(7, 8, status); } -MeasureUnit MeasureUnit::getSecond() { +MeasureUnit MeasureUnit::getMonthPerson() { return MeasureUnit(7, 8); } -MeasureUnit *MeasureUnit::createWeek(UErrorCode &status) { +MeasureUnit *MeasureUnit::createNanosecond(UErrorCode &status) { return MeasureUnit::create(7, 9, status); } -MeasureUnit MeasureUnit::getWeek() { +MeasureUnit MeasureUnit::getNanosecond() { return MeasureUnit(7, 9); } -MeasureUnit *MeasureUnit::createYear(UErrorCode &status) { +MeasureUnit *MeasureUnit::createSecond(UErrorCode &status) { return MeasureUnit::create(7, 10, status); } -MeasureUnit MeasureUnit::getYear() { +MeasureUnit MeasureUnit::getSecond() { return MeasureUnit(7, 10); } +MeasureUnit *MeasureUnit::createWeek(UErrorCode &status) { + return MeasureUnit::create(7, 11, status); +} + +MeasureUnit MeasureUnit::getWeek() { + return MeasureUnit(7, 11); +} + +MeasureUnit *MeasureUnit::createWeekPerson(UErrorCode &status) { + return MeasureUnit::create(7, 12, status); +} + +MeasureUnit MeasureUnit::getWeekPerson() { + return MeasureUnit(7, 12); +} + +MeasureUnit *MeasureUnit::createYear(UErrorCode &status) { + return MeasureUnit::create(7, 13, status); +} + +MeasureUnit MeasureUnit::getYear() { + return MeasureUnit(7, 13); +} + +MeasureUnit *MeasureUnit::createYearPerson(UErrorCode &status) { + return MeasureUnit::create(7, 14, status); +} + +MeasureUnit MeasureUnit::getYearPerson() { + return MeasureUnit(7, 14); +} + MeasureUnit *MeasureUnit::createAmpere(UErrorCode &status) { return MeasureUnit::create(8, 0, status); } diff --git a/icu4c/source/i18n/number_longnames.cpp b/icu4c/source/i18n/number_longnames.cpp index 0d12e56a91f..fc4517916ba 100644 --- a/icu4c/source/i18n/number_longnames.cpp +++ b/icu4c/source/i18n/number_longnames.cpp @@ -101,7 +101,16 @@ void getMeasureData(const Locale &locale, const MeasureUnit &unit, const UNumber key.append("/", status); key.append(unit.getType(), status); key.append("/", status); - key.append(unit.getSubtype(), status); + + // Map duration-year-person, duration-week-person, etc. to duration-year, duration-week, ... + // TODO(ICU-20400): Get duration-*-person data properly with aliases. + int32_t subtypeLen = static_cast(uprv_strlen(unit.getSubtype())); + if (subtypeLen > 7 && uprv_strcmp(unit.getSubtype() + subtypeLen - 7, "-person") == 0) { + key.append({unit.getSubtype(), subtypeLen - 7}, status); + } else { + key.append(unit.getSubtype(), status); + } + ures_getAllItemsWithFallback(unitsBundle.getAlias(), key.data(), sink, status); } diff --git a/icu4c/source/i18n/unicode/measunit.h b/icu4c/source/i18n/unicode/measunit.h index c0406e11c06..54390305157 100644 --- a/icu4c/source/i18n/unicode/measunit.h +++ b/icu4c/source/i18n/unicode/measunit.h @@ -838,6 +838,24 @@ class U_I18N_API MeasureUnit: public UObject { */ static MeasureUnit getDay(); +#ifndef U_HIDE_DRAFT_API + /** + * Returns by pointer, unit of duration: day-person. + * Caller owns returned value and must free it. + * Also see {@link #getDayPerson()}. + * @param status ICU error code. + * @draft ICU 63 + */ + static MeasureUnit *createDayPerson(UErrorCode &status); + + /** + * Returns by value, unit of duration: day-person. + * Also see {@link #createDayPerson()}. + * @draft ICU 64 + */ + static MeasureUnit getDayPerson(); +#endif /* U_HIDE_DRAFT_API */ + /** * Returns by pointer, unit of duration: hour. * Caller owns returned value and must free it. @@ -918,6 +936,24 @@ class U_I18N_API MeasureUnit: public UObject { */ static MeasureUnit getMonth(); +#ifndef U_HIDE_DRAFT_API + /** + * Returns by pointer, unit of duration: month-person. + * Caller owns returned value and must free it. + * Also see {@link #getMonthPerson()}. + * @param status ICU error code. + * @draft ICU 63 + */ + static MeasureUnit *createMonthPerson(UErrorCode &status); + + /** + * Returns by value, unit of duration: month-person. + * Also see {@link #createMonthPerson()}. + * @draft ICU 64 + */ + static MeasureUnit getMonthPerson(); +#endif /* U_HIDE_DRAFT_API */ + /** * Returns by pointer, unit of duration: nanosecond. * Caller owns returned value and must free it. @@ -966,6 +1002,24 @@ class U_I18N_API MeasureUnit: public UObject { */ static MeasureUnit getWeek(); +#ifndef U_HIDE_DRAFT_API + /** + * Returns by pointer, unit of duration: week-person. + * Caller owns returned value and must free it. + * Also see {@link #getWeekPerson()}. + * @param status ICU error code. + * @draft ICU 63 + */ + static MeasureUnit *createWeekPerson(UErrorCode &status); + + /** + * Returns by value, unit of duration: week-person. + * Also see {@link #createWeekPerson()}. + * @draft ICU 64 + */ + static MeasureUnit getWeekPerson(); +#endif /* U_HIDE_DRAFT_API */ + /** * Returns by pointer, unit of duration: year. * Caller owns returned value and must free it. @@ -982,6 +1036,24 @@ class U_I18N_API MeasureUnit: public UObject { */ static MeasureUnit getYear(); +#ifndef U_HIDE_DRAFT_API + /** + * Returns by pointer, unit of duration: year-person. + * Caller owns returned value and must free it. + * Also see {@link #getYearPerson()}. + * @param status ICU error code. + * @draft ICU 63 + */ + static MeasureUnit *createYearPerson(UErrorCode &status); + + /** + * Returns by value, unit of duration: year-person. + * Also see {@link #createYearPerson()}. + * @draft ICU 64 + */ + static MeasureUnit getYearPerson(); +#endif /* U_HIDE_DRAFT_API */ + /** * Returns by pointer, unit of electric: ampere. * Caller owns returned value and must free it. diff --git a/icu4c/source/test/intltest/measfmttest.cpp b/icu4c/source/test/intltest/measfmttest.cpp index 4fb9ee8320e..c8ec4dce4ed 100644 --- a/icu4c/source/test/intltest/measfmttest.cpp +++ b/icu4c/source/test/intltest/measfmttest.cpp @@ -74,6 +74,7 @@ private: void TestDoubleZero(); void TestUnitPerUnitResolution(); void TestIndividualPluralFallback(); + void Test20332_PersonUnits(); void verifyFormat( const char *description, const MeasureFormat &fmt, @@ -173,6 +174,7 @@ void MeasureFormatTest::runIndexedTest( TESTCASE_AUTO(TestDoubleZero); TESTCASE_AUTO(TestUnitPerUnitResolution); TESTCASE_AUTO(TestIndividualPluralFallback); + TESTCASE_AUTO(Test20332_PersonUnits); TESTCASE_AUTO_END; } @@ -2615,6 +2617,38 @@ void MeasureFormatTest::TestIndividualPluralFallback() { assertEquals("2 deg temp in fr_CA", expected, mf.format(twoDeg.orphan(), actual, errorCode), TRUE); } +void MeasureFormatTest::Test20332_PersonUnits() { + if (logKnownIssue("ICU-20400")) { + return; + } + IcuTestErrorCode status(*this, "Test20332_PersonUnits"); + const struct TestCase { + const char* locale; + MeasureUnit* unitToAdopt; + UMeasureFormatWidth width; + const char* expected; + } cases[] = { + {"en-us", MeasureUnit::createYearPerson(status), UMEASFMT_WIDTH_NARROW, "25y"}, + {"en-us", MeasureUnit::createYearPerson(status), UMEASFMT_WIDTH_SHORT, "25 yrs"}, + {"en-us", MeasureUnit::createYearPerson(status), UMEASFMT_WIDTH_WIDE, "25 years"}, + {"en-us", MeasureUnit::createMonthPerson(status), UMEASFMT_WIDTH_NARROW, "25m"}, + {"en-us", MeasureUnit::createMonthPerson(status), UMEASFMT_WIDTH_SHORT, "25 mths"}, + {"en-us", MeasureUnit::createMonthPerson(status), UMEASFMT_WIDTH_WIDE, "25 months"}, + {"en-us", MeasureUnit::createWeekPerson(status), UMEASFMT_WIDTH_NARROW, "25w"}, + {"en-us", MeasureUnit::createWeekPerson(status), UMEASFMT_WIDTH_SHORT, "25 wks"}, + {"en-us", MeasureUnit::createWeekPerson(status), UMEASFMT_WIDTH_WIDE, "25 weeks"}, + {"en-us", MeasureUnit::createDayPerson(status), UMEASFMT_WIDTH_NARROW, "25d"}, + {"en-us", MeasureUnit::createDayPerson(status), UMEASFMT_WIDTH_SHORT, "25 Days"}, + {"en-us", MeasureUnit::createDayPerson(status), UMEASFMT_WIDTH_WIDE, "25 days"} + }; + for (const auto& cas : cases) { + MeasureFormat mf(cas.locale, cas.width, status); + Measure measure(25, cas.unitToAdopt, status); + verifyFormat(cas.locale, mf, &measure, 1, cas.expected); + } +} + + void MeasureFormatTest::verifyFieldPosition( const char *description, const MeasureFormat &fmt, diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp index 910818ec5d8..b95807e6228 100644 --- a/icu4c/source/test/intltest/numbertest_api.cpp +++ b/icu4c/source/test/intltest/numbertest_api.cpp @@ -562,6 +562,15 @@ void NumberFormatterApiTest::unitMeasure() { Locale("es-MX"), 1, u"kelvin"); + + assertFormatSingle( + u"Person unit not in short form", + u"measure-unit/duration-year-person unit-width-full-name", + NumberFormatter::with().unit(MeasureUnit::getYearPerson()) + .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME), + Locale("es-MX"), + 5, + u"5 a\u00F1os"); } void NumberFormatterApiTest::unitCompoundMeasure() { diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/LongNameHandler.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/LongNameHandler.java index dbdc550c576..e31ea8b18a8 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/LongNameHandler.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/LongNameHandler.java @@ -97,7 +97,15 @@ public class LongNameHandler implements MicroPropsGenerator, ModifierStore { key.append("/"); key.append(unit.getType()); key.append("/"); - key.append(unit.getSubtype()); + + // Map duration-year-person, duration-week-person, etc. to duration-year, duration-week, ... + // TODO(ICU-20400): Get duration-*-person data properly with aliases. + if (unit.getSubtype().endsWith("-person")) { + key.append(unit.getSubtype(), 0, unit.getSubtype().length() - 7); + } else { + key.append(unit.getSubtype()); + } + try { resource.getAllItemsWithFallback(key.toString(), sink); } catch (MissingResourceException e) { diff --git a/icu4j/main/classes/core/src/com/ibm/icu/util/MeasureUnit.java b/icu4j/main/classes/core/src/com/ibm/icu/util/MeasureUnit.java index c2e0c04e5db..3c46c06606d 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/util/MeasureUnit.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/util/MeasureUnit.java @@ -610,6 +610,13 @@ public class MeasureUnit implements Serializable { */ public static final TimeUnit DAY = (TimeUnit) MeasureUnit.internalGetInstance("duration", "day"); + /** + * Constant for unit of duration: day-person + * @draft ICU 64 + * @provisional This API might change or be removed in a future release. + */ + public static final MeasureUnit DAY_PERSON = MeasureUnit.internalGetInstance("duration", "day-person"); + /** * Constant for unit of duration: hour * @stable ICU 4.0 @@ -640,6 +647,13 @@ public class MeasureUnit implements Serializable { */ public static final TimeUnit MONTH = (TimeUnit) MeasureUnit.internalGetInstance("duration", "month"); + /** + * Constant for unit of duration: month-person + * @draft ICU 64 + * @provisional This API might change or be removed in a future release. + */ + public static final MeasureUnit MONTH_PERSON = MeasureUnit.internalGetInstance("duration", "month-person"); + /** * Constant for unit of duration: nanosecond * @stable ICU 54 @@ -658,12 +672,26 @@ public class MeasureUnit implements Serializable { */ public static final TimeUnit WEEK = (TimeUnit) MeasureUnit.internalGetInstance("duration", "week"); + /** + * Constant for unit of duration: week-person + * @draft ICU 64 + * @provisional This API might change or be removed in a future release. + */ + public static final MeasureUnit WEEK_PERSON = MeasureUnit.internalGetInstance("duration", "week-person"); + /** * Constant for unit of duration: year * @stable ICU 4.0 */ public static final TimeUnit YEAR = (TimeUnit) MeasureUnit.internalGetInstance("duration", "year"); + /** + * Constant for unit of duration: year-person + * @draft ICU 64 + * @provisional This API might change or be removed in a future release. + */ + public static final MeasureUnit YEAR_PERSON = MeasureUnit.internalGetInstance("duration", "year-person"); + /** * Constant for unit of electric: ampere * @stable ICU 54 diff --git a/icu4j/main/shared/data/icudata.jar b/icu4j/main/shared/data/icudata.jar index d2de6e8764d..f7f146e8d1f 100644 --- a/icu4j/main/shared/data/icudata.jar +++ b/icu4j/main/shared/data/icudata.jar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:22491b0308503cc3a472815b978444811c3ab5fcf7cae071832c39a7ba178465 -size 12694176 +oid sha256:bff554a5fd35fddf6a105bb560ec56d120cee51c4655e941f2306a90297ebe53 +size 12696138 diff --git a/icu4j/main/shared/data/icutzdata.jar b/icu4j/main/shared/data/icutzdata.jar index 26ce352ba30..aabfe5762cd 100644 --- a/icu4j/main/shared/data/icutzdata.jar +++ b/icu4j/main/shared/data/icutzdata.jar @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d72644d74c804bede2359aa1ae18164b45dbab98d997826c98e82dca5dd685e9 -size 94046 +oid sha256:9e8b58bfaaf6e5d236337ee6bc0a7aee7dcb32e5d7054a8bd584650416490d2f +size 94059 diff --git a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java index c843e9abd4e..76548071e1b 100644 --- a/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java +++ b/icu4j/main/tests/core/src/com/ibm/icu/dev/test/format/MeasureUnitTest.java @@ -2193,6 +2193,34 @@ public class MeasureUnitTest extends TestFmwk { // Should not throw an exception. } + @Test + public void test20332_PersonUnits() { + Object[][] cases = new Object[][] { + {ULocale.US, MeasureUnit.YEAR_PERSON, MeasureFormat.FormatWidth.NARROW, "25y"}, + {ULocale.US, MeasureUnit.YEAR_PERSON, MeasureFormat.FormatWidth.SHORT, "25 yrs"}, + {ULocale.US, MeasureUnit.YEAR_PERSON, MeasureFormat.FormatWidth.WIDE, "25 years"}, + {ULocale.US, MeasureUnit.MONTH_PERSON, MeasureFormat.FormatWidth.NARROW, "25m"}, + {ULocale.US, MeasureUnit.MONTH_PERSON, MeasureFormat.FormatWidth.SHORT, "25 mths"}, + {ULocale.US, MeasureUnit.MONTH_PERSON, MeasureFormat.FormatWidth.WIDE, "25 months"}, + {ULocale.US, MeasureUnit.WEEK_PERSON, MeasureFormat.FormatWidth.NARROW, "25w"}, + {ULocale.US, MeasureUnit.WEEK_PERSON, MeasureFormat.FormatWidth.SHORT, "25 wks"}, + {ULocale.US, MeasureUnit.WEEK_PERSON, MeasureFormat.FormatWidth.WIDE, "25 weeks"}, + {ULocale.US, MeasureUnit.DAY_PERSON, MeasureFormat.FormatWidth.NARROW, "25d"}, + {ULocale.US, MeasureUnit.DAY_PERSON, MeasureFormat.FormatWidth.SHORT, "25 days"}, + {ULocale.US, MeasureUnit.DAY_PERSON, MeasureFormat.FormatWidth.WIDE, "25 days"} + }; + for (Object[] cas : cases) { + ULocale locale = (ULocale) cas[0]; + MeasureUnit unit = (MeasureUnit) cas[1]; + MeasureFormat.FormatWidth width = (MeasureFormat.FormatWidth) cas[2]; + String expected = (String) cas[3]; + + MeasureFormat fmt = MeasureFormat.getInstance(locale, width); + String result = fmt.formatMeasures(new Measure(25, unit)); + assertEquals("" + locale + " " + unit + " " + width, expected, result); + } + } + // DO NOT DELETE THIS FUNCTION! It may appear as dead code, but we use this to generate code // for MeasureFormat during the release process. static Map> getUnitsToPerParts() {