mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-10 15:42:14 +00:00
ICU-21123 Support FormattedNumber::getGender() for "short" and "narrow" formatting too
See #1617
This commit is contained in:
parent
b79c299f90
commit
119dfa4f24
4 changed files with 88 additions and 49 deletions
|
@ -228,6 +228,10 @@ const char *getGenderForBuiltin(const Locale &locale, MeasureUnit builtinUnit, U
|
|||
// case. It loads all plural forms, because selection between plural forms is
|
||||
// dependent upon the value being formatted.
|
||||
//
|
||||
// See data/unit/de.txt and data/unit/fr.txt for examples - take a look at
|
||||
// units/compound/power2: German has case, French has differences for gender,
|
||||
// but no case.
|
||||
//
|
||||
// TODO(icu-units#138): Conceptually similar to PluralTableSink, however the
|
||||
// tree structures are different. After homogenizing the structures, we may be
|
||||
// able to unify the two classes.
|
||||
|
@ -336,6 +340,11 @@ class InflectedPluralSink : public ResourceSink {
|
|||
UnicodeString *outArray;
|
||||
};
|
||||
|
||||
// Fetches localised formatting patterns for the given subKey. See documentation
|
||||
// for InflectedPluralSink for details.
|
||||
//
|
||||
// Data is loaded for the appropriate unit width, with missing data filled in
|
||||
// from unitsShort.
|
||||
void getInflectedMeasureData(StringPiece subKey,
|
||||
const Locale &locale,
|
||||
const UNumberUnitWidth &width,
|
||||
|
@ -429,28 +438,40 @@ void getMeasureData(const Locale &locale,
|
|||
LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, locale.getName(), &status));
|
||||
if (U_FAILURE(status)) { return; }
|
||||
|
||||
CharString subKey;
|
||||
subKey.append("/", status);
|
||||
subKey.append(unit.getType(), status);
|
||||
subKey.append("/", status);
|
||||
|
||||
// Map duration-year-person, duration-week-person, etc. to duration-year, duration-week, ...
|
||||
// TODO(ICU-20400): Get duration-*-person data properly with aliases.
|
||||
StringPiece subtypeForResource;
|
||||
int32_t subtypeLen = static_cast<int32_t>(uprv_strlen(unit.getSubtype()));
|
||||
if (subtypeLen > 7 && uprv_strcmp(unit.getSubtype() + subtypeLen - 7, "-person") == 0) {
|
||||
subtypeForResource = {unit.getSubtype(), subtypeLen - 7};
|
||||
subKey.append({unit.getSubtype(), subtypeLen - 7}, status);
|
||||
} else {
|
||||
subtypeForResource = unit.getSubtype();
|
||||
subKey.append({unit.getSubtype(), subtypeLen}, status);
|
||||
}
|
||||
|
||||
if (width != UNUM_UNIT_WIDTH_FULL_NAME) {
|
||||
UErrorCode localStatus = status;
|
||||
CharString genderKey;
|
||||
genderKey.append("units", localStatus);
|
||||
genderKey.append(subKey, localStatus);
|
||||
genderKey.append("/gender", localStatus);
|
||||
StackUResourceBundle fillIn;
|
||||
ures_getByKeyWithFallback(unitsBundle.getAlias(), genderKey.data(), fillIn.getAlias(),
|
||||
&localStatus);
|
||||
outArray[GENDER_INDEX] = ures_getUnicodeString(fillIn.getAlias(), &localStatus);
|
||||
}
|
||||
|
||||
CharString key;
|
||||
key.append("units", status);
|
||||
// TODO(icu-units#140): support gender for other unit widths.
|
||||
if (width == UNUM_UNIT_WIDTH_NARROW) {
|
||||
key.append("Narrow", status);
|
||||
} else if (width == UNUM_UNIT_WIDTH_SHORT) {
|
||||
key.append("Short", status);
|
||||
}
|
||||
key.append("/", status);
|
||||
key.append(unit.getType(), status);
|
||||
key.append("/", status);
|
||||
key.append(subtypeForResource, status);
|
||||
key.append(subKey, status);
|
||||
|
||||
// Grab desired case first, if available. Then grab no-case data to fill in
|
||||
// the gaps.
|
||||
|
@ -486,10 +507,8 @@ void getMeasureData(const Locale &locale,
|
|||
// TODO(ICU-13353): The fallback to short does not work in ICU4C.
|
||||
// Manually fall back to short (this is done automatically in Java).
|
||||
key.clear();
|
||||
key.append("unitsShort/", status);
|
||||
key.append(unit.getType(), status);
|
||||
key.append("/", status);
|
||||
key.append(subtypeForResource, status);
|
||||
key.append("unitsShort", status);
|
||||
key.append(subKey, status);
|
||||
ures_getAllItemsWithFallback(unitsBundle.getAlias(), key.data(), sink, status);
|
||||
}
|
||||
|
||||
|
|
|
@ -2287,15 +2287,14 @@ void NumberFormatterApiTest::unitGender() {
|
|||
LocalizedNumberFormatter formatter;
|
||||
FormattedNumber fn;
|
||||
for (const TestCase &t : cases) {
|
||||
// TODO(icu-units#140): make this work for more than just UNUM_UNIT_WIDTH_FULL_NAME
|
||||
// formatter = NumberFormatter::with()
|
||||
// .unit(MeasureUnit::forIdentifier(t.unitIdentifier, status))
|
||||
// .locale(Locale(t.locale));
|
||||
// fn = formatter.formatDouble(1.1, status);
|
||||
// assertEquals(UnicodeString("Testing gender with default width, unit: ") + t.unitIdentifier +
|
||||
// ", locale: " + t.locale,
|
||||
// t.expectedGender, fn.getGender(status));
|
||||
// status.assertSuccess();
|
||||
formatter = NumberFormatter::with()
|
||||
.unit(MeasureUnit::forIdentifier(t.unitIdentifier, status))
|
||||
.locale(Locale(t.locale));
|
||||
fn = formatter.formatDouble(1.1, status);
|
||||
assertEquals(UnicodeString("Testing gender with default width, unit: ") + t.unitIdentifier +
|
||||
", locale: " + t.locale,
|
||||
t.expectedGender, fn.getGender(status));
|
||||
status.assertSuccess();
|
||||
|
||||
formatter = NumberFormatter::with()
|
||||
.unit(MeasureUnit::forIdentifier(t.unitIdentifier, status))
|
||||
|
|
|
@ -141,10 +141,8 @@ public class LongNameHandler
|
|||
key.append("/gender");
|
||||
|
||||
try {
|
||||
ICUResourceBundle stackBundle =
|
||||
(ICUResourceBundle)unitsBundle.getWithFallback(key.toString());
|
||||
return stackBundle.getString();
|
||||
} catch (Exception e) {
|
||||
return unitsBundle.getWithFallback(key.toString()).getString();
|
||||
} catch (MissingResourceException e) {
|
||||
// TODO(icu-units#28): "$unitRes/gender" does not exist. Do we want to
|
||||
// check whether the parent "$unitRes" exists? Then we could return
|
||||
// U_MISSING_RESOURCE_ERROR for incorrect usage (e.g. builtinUnit not
|
||||
|
@ -161,6 +159,10 @@ public class LongNameHandler
|
|||
// case. It loads all plural forms, because selection between plural forms is
|
||||
// dependent upon the value being formatted.
|
||||
//
|
||||
// See data/unit/de.txt and data/unit/fr.txt for examples - take a look at
|
||||
// units/compound/power2: German has case, French has differences for
|
||||
// gender, but no case.
|
||||
//
|
||||
// TODO(icu-units#138): Conceptually similar to PluralTableSink, however the
|
||||
// tree structures are different. After homogenizing the structures, we may be
|
||||
// able to unify the two classes.
|
||||
|
@ -259,6 +261,11 @@ public class LongNameHandler
|
|||
String[] outArray;
|
||||
}
|
||||
|
||||
// Fetches localised formatting patterns for the given subKey. See
|
||||
// documentation for InflectedPluralSink for details.
|
||||
//
|
||||
// Data is loaded for the appropriate unit width, with missing data filled
|
||||
// in from unitsShort.
|
||||
static void getInflectedMeasureData(String subKey,
|
||||
ULocale locale,
|
||||
UnitWidth width,
|
||||
|
@ -284,7 +291,7 @@ public class LongNameHandler
|
|||
if (width == UnitWidth.SHORT) {
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (MissingResourceException e) {
|
||||
// Continue: fall back to short
|
||||
}
|
||||
|
||||
|
@ -338,25 +345,40 @@ public class LongNameHandler
|
|||
ICUResourceBundle resource;
|
||||
resource = (ICUResourceBundle) UResourceBundle.getBundleInstance(ICUData.ICU_UNIT_BASE_NAME,
|
||||
locale);
|
||||
|
||||
StringBuilder subKey = new StringBuilder();
|
||||
subKey.append("/");
|
||||
subKey.append(unit.getType());
|
||||
subKey.append("/");
|
||||
|
||||
// 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() != null && unit.getSubtype().endsWith("-person")) {
|
||||
subKey.append(unit.getSubtype(), 0, unit.getSubtype().length() - 7);
|
||||
} else {
|
||||
subKey.append(unit.getSubtype());
|
||||
}
|
||||
|
||||
if (width != UnitWidth.FULL_NAME) {
|
||||
StringBuilder genderKey = new StringBuilder();
|
||||
genderKey.append("units");
|
||||
genderKey.append(subKey);
|
||||
genderKey.append("/gender");
|
||||
try {
|
||||
outArray[GENDER_INDEX] = resource.getWithFallback(genderKey.toString()).getString();
|
||||
} catch (MissingResourceException e) {
|
||||
// continue
|
||||
}
|
||||
}
|
||||
|
||||
StringBuilder key = new StringBuilder();
|
||||
key.append("units");
|
||||
// TODO(icu-units#140): support gender for other unit widths.
|
||||
if (width == UnitWidth.NARROW) {
|
||||
key.append("Narrow");
|
||||
} else if (width == UnitWidth.SHORT) {
|
||||
key.append("Short");
|
||||
}
|
||||
key.append("/");
|
||||
key.append(unit.getType());
|
||||
key.append("/");
|
||||
|
||||
// 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() != null && unit.getSubtype().endsWith("-person")) {
|
||||
key.append(unit.getSubtype(), 0, unit.getSubtype().length() - 7);
|
||||
} else {
|
||||
key.append(unit.getSubtype());
|
||||
}
|
||||
key.append(subKey);
|
||||
|
||||
// Grab desired case first, if available. Then grab nominative case to fill
|
||||
// in the gaps.
|
||||
|
@ -427,7 +449,7 @@ public class LongNameHandler
|
|||
key.append(compoundKey);
|
||||
try {
|
||||
return resource.getStringWithFallback(key.toString());
|
||||
} catch (Exception e) {
|
||||
} catch (MissingResourceException e) {
|
||||
if (width == UnitWidth.SHORT) {
|
||||
return "";
|
||||
}
|
||||
|
@ -440,7 +462,7 @@ public class LongNameHandler
|
|||
key.append(compoundKey);
|
||||
try {
|
||||
return resource.getStringWithFallback(key.toString());
|
||||
} catch (Exception e) {
|
||||
} catch (MissingResourceException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
@ -502,7 +524,7 @@ public class LongNameHandler
|
|||
} else {
|
||||
this.value1 = value;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
} catch (MissingResourceException e) {
|
||||
// Fall back to uninflected.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2278,14 +2278,13 @@ public class NumberFormatterApiTest extends TestFmwk {
|
|||
LocalizedNumberFormatter formatter;
|
||||
FormattedNumber fn;
|
||||
for (TestCase t : cases) {
|
||||
// // TODO(icu-units#140): make this work for more than just UnitWidth.FULL_NAME
|
||||
// formatter = NumberFormatter.with()
|
||||
// .unit(MeasureUnit.forIdentifier(t.unitIdentifier))
|
||||
// .locale(new ULocale(t.locale));
|
||||
// fn = formatter.format(1.1);
|
||||
// assertEquals("Testing gender with default width, unit: " + t.unitIdentifier +
|
||||
// ", locale: " + t.locale,
|
||||
// t.expectedGender, fn.getGender());
|
||||
formatter = NumberFormatter.with()
|
||||
.unit(MeasureUnit.forIdentifier(t.unitIdentifier))
|
||||
.locale(new ULocale(t.locale));
|
||||
fn = formatter.format(1.1);
|
||||
assertEquals("Testing gender with default width, unit: " + t.unitIdentifier +
|
||||
", locale: " + t.locale,
|
||||
t.expectedGender, fn.getGender());
|
||||
|
||||
formatter = NumberFormatter.with()
|
||||
.unit(MeasureUnit.forIdentifier(t.unitIdentifier))
|
||||
|
|
Loading…
Add table
Reference in a new issue