mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-06 05:55:35 +00:00
ICU-20949 Fix compound unit in "ar", "ne" locales
Do not assume the "one" pattern always contains "{0}"
This commit is contained in:
parent
b5973eee64
commit
f0ada59042
6 changed files with 229 additions and 3 deletions
|
@ -246,7 +246,8 @@ LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit, con
|
|||
if (U_FAILURE(status)) { return result; }
|
||||
UnicodeString secondaryFormat = getWithPlural(secondaryData, StandardPlural::Form::ONE, status);
|
||||
if (U_FAILURE(status)) { return result; }
|
||||
SimpleFormatter secondaryCompiled(secondaryFormat, 1, 1, status);
|
||||
// Some "one" pattern may not contain "{0}". For example in "ar" or "ne" locale.
|
||||
SimpleFormatter secondaryCompiled(secondaryFormat, 0, 1, status);
|
||||
if (U_FAILURE(status)) { return result; }
|
||||
UnicodeString secondaryString = secondaryCompiled.getTextWithNoArguments().trim();
|
||||
// TODO: Why does UnicodeString need to be explicit in the following line?
|
||||
|
|
|
@ -9,9 +9,11 @@
|
|||
// Helpful in toString methods and elsewhere.
|
||||
#define UNISTR_FROM_STRING_EXPLICIT
|
||||
|
||||
#include <stdio.h>
|
||||
#include "unicode/unumberformatter.h"
|
||||
#include "unicode/umisc.h"
|
||||
#include "unicode/unum.h"
|
||||
#include "unicode/ustring.h"
|
||||
#include "cformtst.h"
|
||||
#include "cintltst.h"
|
||||
#include "cmemory.h"
|
||||
|
@ -26,6 +28,8 @@ static void TestFormattedValue(void);
|
|||
|
||||
static void TestSkeletonParseError(void);
|
||||
|
||||
static void TestPerUnitInArabic(void);
|
||||
|
||||
void addUNumberFormatterTest(TestNode** root);
|
||||
|
||||
#define TESTCASE(x) addTest(root, &x, "tsformat/unumberformatter/" #x)
|
||||
|
@ -36,6 +40,7 @@ void addUNumberFormatterTest(TestNode** root) {
|
|||
TESTCASE(TestExampleCode);
|
||||
TESTCASE(TestFormattedValue);
|
||||
TESTCASE(TestSkeletonParseError);
|
||||
TESTCASE(TestPerUnitInArabic);
|
||||
}
|
||||
|
||||
|
||||
|
@ -254,5 +259,88 @@ static void TestSkeletonParseError() {
|
|||
unumf_close(uformatter);
|
||||
}
|
||||
|
||||
|
||||
static void TestPerUnitInArabic() {
|
||||
const char* simpleMeasureUnits[] = {
|
||||
"area-acre",
|
||||
"digital-bit",
|
||||
"digital-byte",
|
||||
"temperature-celsius",
|
||||
"length-centimeter",
|
||||
"duration-day",
|
||||
"angle-degree",
|
||||
"temperature-fahrenheit",
|
||||
"volume-fluid-ounce",
|
||||
"length-foot",
|
||||
"volume-gallon",
|
||||
"digital-gigabit",
|
||||
"digital-gigabyte",
|
||||
"mass-gram",
|
||||
"area-hectare",
|
||||
"duration-hour",
|
||||
"length-inch",
|
||||
"digital-kilobit",
|
||||
"digital-kilobyte",
|
||||
"mass-kilogram",
|
||||
"length-kilometer",
|
||||
"volume-liter",
|
||||
"digital-megabit",
|
||||
"digital-megabyte",
|
||||
"length-meter",
|
||||
"length-mile",
|
||||
"length-mile-scandinavian",
|
||||
"volume-milliliter",
|
||||
"length-millimeter",
|
||||
"duration-millisecond",
|
||||
"duration-minute",
|
||||
"duration-month",
|
||||
"mass-ounce",
|
||||
"concentr-percent",
|
||||
"digital-petabyte",
|
||||
"mass-pound",
|
||||
"duration-second",
|
||||
"mass-stone",
|
||||
"digital-terabit",
|
||||
"digital-terabyte",
|
||||
"duration-week",
|
||||
"length-yard",
|
||||
"duration-year"
|
||||
};
|
||||
#define BUFFER_LEN 256
|
||||
char buffer[BUFFER_LEN];
|
||||
UChar ubuffer[BUFFER_LEN];
|
||||
const char* locale = "ar";
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UFormattedNumber* formatted = unumf_openResult(&status);
|
||||
if (U_FAILURE(status)) {
|
||||
log_err("FAIL: unumf_openResult failed");
|
||||
return;
|
||||
}
|
||||
for(int32_t i=0; i < UPRV_LENGTHOF(simpleMeasureUnits); ++i) {
|
||||
for(int32_t j=0; j < UPRV_LENGTHOF(simpleMeasureUnits); ++j) {
|
||||
status = U_ZERO_ERROR;
|
||||
sprintf(buffer, "measure-unit/%s per-measure-unit/%s",
|
||||
simpleMeasureUnits[i], simpleMeasureUnits[j]);
|
||||
int32_t outputlen = 0;
|
||||
u_strFromUTF8(ubuffer, BUFFER_LEN, &outputlen, buffer, strlen(buffer), &status);
|
||||
if (U_FAILURE(status)) {
|
||||
log_err("FAIL u_strFromUTF8: %s = %s ( %s )\n", locale, buffer,
|
||||
u_errorName(status));
|
||||
}
|
||||
UNumberFormatter* nf = unumf_openForSkeletonAndLocale(
|
||||
ubuffer, outputlen, locale, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
log_err("FAIL unumf_openForSkeletonAndLocale: %s = %s ( %s )\n",
|
||||
locale, buffer, u_errorName(status));
|
||||
} else {
|
||||
unumf_formatDouble(nf, 1, formatted, &status);
|
||||
if (U_FAILURE(status)) {
|
||||
log_err("FAIL unumf_formatDouble: %s = %s ( %s )\n",
|
||||
locale, buffer, u_errorName(status));
|
||||
}
|
||||
}
|
||||
unumf_close(nf);
|
||||
}
|
||||
}
|
||||
unumf_closeResult(formatted);
|
||||
}
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -258,6 +258,7 @@ class NumberSkeletonTest : public IntlTest {
|
|||
void defaultTokens();
|
||||
void flexibleSeparators();
|
||||
void wildcardCharacters();
|
||||
void perUnitInArabic();
|
||||
|
||||
void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ void NumberSkeletonTest::runIndexedTest(int32_t index, UBool exec, const char*&
|
|||
TESTCASE_AUTO(defaultTokens);
|
||||
TESTCASE_AUTO(flexibleSeparators);
|
||||
TESTCASE_AUTO(wildcardCharacters);
|
||||
TESTCASE_AUTO(perUnitInArabic);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
||||
|
@ -362,5 +363,77 @@ void NumberSkeletonTest::expectedErrorSkeleton(const char16_t** cases, int32_t c
|
|||
}
|
||||
}
|
||||
|
||||
void NumberSkeletonTest::perUnitInArabic() {
|
||||
IcuTestErrorCode status(*this, "perUnitInArabic");
|
||||
|
||||
struct TestCase {
|
||||
const char16_t* type;
|
||||
const char16_t* subtype;
|
||||
} cases[] = {
|
||||
{u"area", u"acre"},
|
||||
{u"digital", u"bit"},
|
||||
{u"digital", u"byte"},
|
||||
{u"temperature", u"celsius"},
|
||||
{u"length", u"centimeter"},
|
||||
{u"duration", u"day"},
|
||||
{u"angle", u"degree"},
|
||||
{u"temperature", u"fahrenheit"},
|
||||
{u"volume", u"fluid-ounce"},
|
||||
{u"length", u"foot"},
|
||||
{u"volume", u"gallon"},
|
||||
{u"digital", u"gigabit"},
|
||||
{u"digital", u"gigabyte"},
|
||||
{u"mass", u"gram"},
|
||||
{u"area", u"hectare"},
|
||||
{u"duration", u"hour"},
|
||||
{u"length", u"inch"},
|
||||
{u"digital", u"kilobit"},
|
||||
{u"digital", u"kilobyte"},
|
||||
{u"mass", u"kilogram"},
|
||||
{u"length", u"kilometer"},
|
||||
{u"volume", u"liter"},
|
||||
{u"digital", u"megabit"},
|
||||
{u"digital", u"megabyte"},
|
||||
{u"length", u"meter"},
|
||||
{u"length", u"mile"},
|
||||
{u"length", u"mile-scandinavian"},
|
||||
{u"volume", u"milliliter"},
|
||||
{u"length", u"millimeter"},
|
||||
{u"duration", u"millisecond"},
|
||||
{u"duration", u"minute"},
|
||||
{u"duration", u"month"},
|
||||
{u"mass", u"ounce"},
|
||||
{u"concentr", u"percent"},
|
||||
{u"digital", u"petabyte"},
|
||||
{u"mass", u"pound"},
|
||||
{u"duration", u"second"},
|
||||
{u"mass", u"stone"},
|
||||
{u"digital", u"terabit"},
|
||||
{u"digital", u"terabyte"},
|
||||
{u"duration", u"week"},
|
||||
{u"length", u"yard"},
|
||||
{u"duration", u"year"},
|
||||
};
|
||||
|
||||
for (const auto& cas1 : cases) {
|
||||
for (const auto& cas2 : cases) {
|
||||
UnicodeString skeleton(u"measure-unit/");
|
||||
skeleton += cas1.type;
|
||||
skeleton += u"-";
|
||||
skeleton += cas1.subtype;
|
||||
skeleton += u" ";
|
||||
skeleton += u"per-measure-unit/";
|
||||
skeleton += cas2.type;
|
||||
skeleton += u"-";
|
||||
skeleton += cas2.subtype;
|
||||
|
||||
status.setScope(skeleton);
|
||||
UnicodeString actual = NumberFormatter::forSkeleton(skeleton, status).locale("ar")
|
||||
.formatDouble(5142.3, status)
|
||||
.toString(status);
|
||||
status.errIfFailureAndReset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* #if !UCONFIG_NO_FORMATTING */
|
||||
|
|
|
@ -241,8 +241,10 @@ public class LongNameHandler implements MicroPropsGenerator, ModifierStore {
|
|||
String compiled = SimpleFormatterImpl
|
||||
.compileToStringMinMaxArguments(rawPerUnitFormat, sb, 2, 2);
|
||||
String secondaryFormat = getWithPlural(secondaryData, StandardPlural.ONE);
|
||||
|
||||
// Some "one" pattern may not contain "{0}". For example in "ar" or "ne" locale.
|
||||
String secondaryCompiled = SimpleFormatterImpl
|
||||
.compileToStringMinMaxArguments(secondaryFormat, sb, 1, 1);
|
||||
.compileToStringMinMaxArguments(secondaryFormat, sb, 0, 1);
|
||||
String secondaryString = SimpleFormatterImpl.getTextWithNoArguments(secondaryCompiled)
|
||||
.trim();
|
||||
perUnitFormat = SimpleFormatterImpl.formatCompiledPattern(compiled, "{0}", secondaryString);
|
||||
|
|
|
@ -349,4 +349,65 @@ public class NumberSkeletonTest {
|
|||
assertEquals(mode.toString(), modeString, skeleton.substring(14));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void perUnitInArabic() {
|
||||
String[][] cases = {
|
||||
{"area", "acre"},
|
||||
{"digital", "bit"},
|
||||
{"digital", "byte"},
|
||||
{"temperature", "celsius"},
|
||||
{"length", "centimeter"},
|
||||
{"duration", "day"},
|
||||
{"angle", "degree"},
|
||||
{"temperature", "fahrenheit"},
|
||||
{"volume", "fluid-ounce"},
|
||||
{"length", "foot"},
|
||||
{"volume", "gallon"},
|
||||
{"digital", "gigabit"},
|
||||
{"digital", "gigabyte"},
|
||||
{"mass", "gram"},
|
||||
{"area", "hectare"},
|
||||
{"duration", "hour"},
|
||||
{"length", "inch"},
|
||||
{"digital", "kilobit"},
|
||||
{"digital", "kilobyte"},
|
||||
{"mass", "kilogram"},
|
||||
{"length", "kilometer"},
|
||||
{"volume", "liter"},
|
||||
{"digital", "megabit"},
|
||||
{"digital", "megabyte"},
|
||||
{"length", "meter"},
|
||||
{"length", "mile"},
|
||||
{"length", "mile-scandinavian"},
|
||||
{"volume", "milliliter"},
|
||||
{"length", "millimeter"},
|
||||
{"duration", "millisecond"},
|
||||
{"duration", "minute"},
|
||||
{"duration", "month"},
|
||||
{"mass", "ounce"},
|
||||
{"concentr", "percent"},
|
||||
{"digital", "petabyte"},
|
||||
{"mass", "pound"},
|
||||
{"duration", "second"},
|
||||
{"mass", "stone"},
|
||||
{"digital", "terabit"},
|
||||
{"digital", "terabyte"},
|
||||
{"duration", "week"},
|
||||
{"length", "yard"},
|
||||
{"duration", "year"},
|
||||
};
|
||||
|
||||
ULocale arabic = new ULocale("ar");
|
||||
for (String[] cas1 : cases) {
|
||||
for (String[] cas2 : cases) {
|
||||
String skeleton = "measure-unit/";
|
||||
skeleton += cas1[0] + "-" + cas1[1] + " per-measure-unit/" + cas2[0] + "-" + cas2[1];
|
||||
|
||||
String actual = NumberFormatter.forSkeleton(skeleton).locale(arabic).format(5142.3)
|
||||
.toString();
|
||||
// Just make sure it won't throw exception
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue