LEFT | RIGHT |
(no file at all) | |
1 // © 2017 and later: Unicode, Inc. and others. | 1 // © 2017 and later: Unicode, Inc. and others. |
2 // License & terms of use: http://www.unicode.org/copyright.html | 2 // License & terms of use: http://www.unicode.org/copyright.html |
3 | 3 |
4 #include "unicode/utypes.h" | 4 #include "unicode/utypes.h" |
5 | 5 |
6 #if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT | 6 #if !UCONFIG_NO_FORMATTING && !UPRV_INCOMPLETE_CPP11_SUPPORT |
7 | 7 |
| 8 #include "unicode/simpleformatter.h" |
8 #include "unicode/ures.h" | 9 #include "unicode/ures.h" |
9 #include "ureslocs.h" | 10 #include "ureslocs.h" |
10 #include "charstr.h" | 11 #include "charstr.h" |
11 #include "uresimp.h" | 12 #include "uresimp.h" |
12 #include "number_longnames.h" | 13 #include "number_longnames.h" |
13 #include <algorithm> | 14 #include <algorithm> |
14 #include "cstring.h" | 15 #include "cstring.h" |
15 | 16 |
16 using namespace icu; | 17 using namespace icu; |
17 using namespace icu::number; | 18 using namespace icu::number; |
18 using namespace icu::number::impl; | 19 using namespace icu::number::impl; |
19 | 20 |
20 namespace { | 21 namespace { |
21 | 22 |
| 23 constexpr int32_t DNAM_INDEX = StandardPlural::Form::COUNT; |
| 24 constexpr int32_t PER_INDEX = StandardPlural::Form::COUNT + 1; |
| 25 constexpr int32_t ARRAY_LENGTH = StandardPlural::Form::COUNT + 2; |
| 26 |
| 27 static int32_t getIndex(const char* pluralKeyword, UErrorCode& status) { |
| 28 // pluralKeyword can also be "dnam" or "per" |
| 29 if (uprv_strcmp(pluralKeyword, "dnam") == 0) { |
| 30 return DNAM_INDEX; |
| 31 } else if (uprv_strcmp(pluralKeyword, "per") == 0) { |
| 32 return PER_INDEX; |
| 33 } else { |
| 34 StandardPlural::Form plural = StandardPlural::fromString(pluralKeyword,
status); |
| 35 return plural; |
| 36 } |
| 37 } |
| 38 |
| 39 static UnicodeString getWithPlural( |
| 40 const UnicodeString* strings, |
| 41 int32_t plural, |
| 42 UErrorCode& status) { |
| 43 UnicodeString result = strings[plural]; |
| 44 if (result.isBogus()) { |
| 45 result = strings[StandardPlural::Form::OTHER]; |
| 46 } |
| 47 if (result.isBogus()) { |
| 48 // There should always be data in the "other" plural variant. |
| 49 status = U_INTERNAL_PROGRAM_ERROR; |
| 50 } |
| 51 return result; |
| 52 } |
| 53 |
22 | 54 |
23 ////////////////////////// | 55 ////////////////////////// |
24 /// BEGIN DATA LOADING /// | 56 /// BEGIN DATA LOADING /// |
25 ////////////////////////// | 57 ////////////////////////// |
26 | 58 |
27 class PluralTableSink : public ResourceSink { | 59 class PluralTableSink : public ResourceSink { |
28 public: | 60 public: |
29 explicit PluralTableSink(UnicodeString *outArray) : outArray(outArray) { | 61 explicit PluralTableSink(UnicodeString *outArray) : outArray(outArray) { |
30 // Initialize the array to bogus strings. | 62 // Initialize the array to bogus strings. |
31 for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) { | 63 for (int32_t i = 0; i < ARRAY_LENGTH; i++) { |
32 outArray[i].setToBogus(); | 64 outArray[i].setToBogus(); |
33 } | 65 } |
34 } | 66 } |
35 | 67 |
36 void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UError
Code &status) U_OVERRIDE { | 68 void put(const char *key, ResourceValue &value, UBool /*noFallback*/, UError
Code &status) U_OVERRIDE { |
37 ResourceTable pluralsTable = value.getTable(status); | 69 ResourceTable pluralsTable = value.getTable(status); |
38 if (U_FAILURE(status)) { return; } | 70 if (U_FAILURE(status)) { return; } |
39 for (int i = 0; pluralsTable.getKeyAndValue(i, key, value); ++i) { | 71 for (int32_t i = 0; pluralsTable.getKeyAndValue(i, key, value); ++i) { |
40 // In MeasureUnit data, ignore dnam and per units for now. | 72 int32_t index = getIndex(key, status); |
41 if (uprv_strcmp(key, "dnam") == 0 || uprv_strcmp(key, "per") == 0) { | 73 if (U_FAILURE(status)) { return; } |
| 74 if (!outArray[index].isBogus()) { |
42 continue; | 75 continue; |
43 } | 76 } |
44 StandardPlural::Form plural = StandardPlural::fromString(key, status
); | 77 outArray[index] = value.getUnicodeString(status); |
45 if (U_FAILURE(status)) { return; } | |
46 if (!outArray[plural].isBogus()) { | |
47 continue; | |
48 } | |
49 outArray[plural] = value.getUnicodeString(status); | |
50 if (U_FAILURE(status)) { return; } | 78 if (U_FAILURE(status)) { return; } |
51 } | 79 } |
52 } | 80 } |
53 | 81 |
54 private: | 82 private: |
55 UnicodeString *outArray; | 83 UnicodeString *outArray; |
56 }; | 84 }; |
57 | 85 |
58 // NOTE: outArray MUST have room for all StandardPlural values. No bounds check
ing is performed. | 86 // NOTE: outArray MUST have room for all StandardPlural values. No bounds check
ing is performed. |
59 | 87 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
98 &isChoiceFormat, | 126 &isChoiceFormat, |
99 StandardPlural::getKeyword(static_cast<StandardPlural::Form>(i))
, | 127 StandardPlural::getKeyword(static_cast<StandardPlural::Form>(i))
, |
100 &longNameLen, | 128 &longNameLen, |
101 &status); | 129 &status); |
102 // Example pattern from data: "{0} {1}" | 130 // Example pattern from data: "{0} {1}" |
103 // Example output after find-and-replace: "{0} US dollars" | 131 // Example output after find-and-replace: "{0} US dollars" |
104 pattern.findAndReplace(UnicodeString(u"{1}"), UnicodeString(longName, lo
ngNameLen)); | 132 pattern.findAndReplace(UnicodeString(u"{1}"), UnicodeString(longName, lo
ngNameLen)); |
105 } | 133 } |
106 } | 134 } |
107 | 135 |
| 136 UnicodeString getPerUnitFormat(const Locale& locale, const UNumberUnitWidth &wid
th, UErrorCode& status) { |
| 137 LocalUResourceBundlePointer unitsBundle(ures_open(U_ICUDATA_UNIT, locale.get
Name(), &status)); |
| 138 if (U_FAILURE(status)) { return {}; } |
| 139 CharString key; |
| 140 key.append("units", status); |
| 141 if (width == UNUM_UNIT_WIDTH_NARROW) { |
| 142 key.append("Narrow", status); |
| 143 } else if (width == UNUM_UNIT_WIDTH_SHORT) { |
| 144 key.append("Short", status); |
| 145 } |
| 146 key.append("/compound/per", status); |
| 147 int32_t len = 0; |
| 148 const UChar* ptr = ures_getStringByKeyWithFallback(unitsBundle.getAlias(), k
ey.data(), &len, &status); |
| 149 return UnicodeString(ptr, len); |
| 150 } |
| 151 |
108 //////////////////////// | 152 //////////////////////// |
109 /// END DATA LOADING /// | 153 /// END DATA LOADING /// |
110 //////////////////////// | 154 //////////////////////// |
111 | 155 |
112 } // namespace | 156 } // namespace |
113 | 157 |
114 LongNameHandler | 158 LongNameHandler |
115 LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unit, cons
t UNumberUnitWidth &width, | 159 LongNameHandler::forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, c
onst MeasureUnit &perUnit, |
116 const PluralRules *rules, const MicroPropsGenera
tor *parent, | 160 const UNumberUnitWidth &width, const PluralRules
*rules, |
117 UErrorCode &status) { | 161 const MicroPropsGenerator *parent, UErrorCode &s
tatus) { |
| 162 MeasureUnit unit = unitRef; |
| 163 if (uprv_strcmp(perUnit.getType(), "none") != 0) { |
| 164 // Compound unit: first try to simplify (e.g., meters per second is its
own unit). |
| 165 bool isResolved = false; |
| 166 MeasureUnit resolved = MeasureUnit::resolveUnitPerUnit(unit, perUnit, &i
sResolved); |
| 167 if (isResolved) { |
| 168 unit = resolved; |
| 169 } else { |
| 170 // No simplified form is available. |
| 171 return forCompoundUnit(loc, unit, perUnit, width, rules, parent, sta
tus); |
| 172 } |
| 173 } |
| 174 |
118 LongNameHandler result(rules, parent); | 175 LongNameHandler result(rules, parent); |
119 UnicodeString simpleFormats[StandardPlural::Form::COUNT]; | 176 UnicodeString simpleFormats[ARRAY_LENGTH]; |
120 getMeasureData(loc, unit, width, simpleFormats, status); | 177 getMeasureData(loc, unit, width, simpleFormats, status); |
121 if (U_FAILURE(status)) { return result; } | 178 if (U_FAILURE(status)) { return result; } |
122 // TODO: What field to use for units? | 179 // TODO: What field to use for units? |
123 simpleFormatsToModifiers(simpleFormats, UNUM_FIELD_COUNT, result.fModifiers,
status); | 180 simpleFormatsToModifiers(simpleFormats, UNUM_FIELD_COUNT, result.fModifiers,
status); |
| 181 return result; |
| 182 } |
| 183 |
| 184 LongNameHandler |
| 185 LongNameHandler::forCompoundUnit(const Locale &loc, const MeasureUnit &unit, con
st MeasureUnit &perUnit, |
| 186 const UNumberUnitWidth &width, const PluralRule
s *rules, |
| 187 const MicroPropsGenerator *parent, UErrorCode &
status) { |
| 188 LongNameHandler result(rules, parent); |
| 189 UnicodeString primaryData[ARRAY_LENGTH]; |
| 190 getMeasureData(loc, unit, width, primaryData, status); |
| 191 if (U_FAILURE(status)) { return result; } |
| 192 UnicodeString secondaryData[ARRAY_LENGTH]; |
| 193 getMeasureData(loc, perUnit, width, secondaryData, status); |
| 194 if (U_FAILURE(status)) { return result; } |
| 195 |
| 196 UnicodeString perUnitFormat; |
| 197 if (!secondaryData[PER_INDEX].isBogus()) { |
| 198 perUnitFormat = secondaryData[PER_INDEX]; |
| 199 } else { |
| 200 UnicodeString rawPerUnitFormat = getPerUnitFormat(loc, width, status); |
| 201 if (U_FAILURE(status)) { return result; } |
| 202 // rawPerUnitFormat is something like "{0}/{1}"; we need to substitute i
n the secondary unit. |
| 203 SimpleFormatter compiled(rawPerUnitFormat, 2, 2, status); |
| 204 if (U_FAILURE(status)) { return result; } |
| 205 UnicodeString secondaryFormat = getWithPlural(secondaryData, StandardPlu
ral::Form::ONE, status); |
| 206 if (U_FAILURE(status)) { return result; } |
| 207 SimpleFormatter secondaryCompiled(secondaryFormat, 1, 1, status); |
| 208 if (U_FAILURE(status)) { return result; } |
| 209 UnicodeString secondaryString = secondaryCompiled.getTextWithNoArguments
().trim(); |
| 210 // TODO: Why does UnicodeString need to be explicit in the following lin
e? |
| 211 compiled.format(UnicodeString(u"{0}"), secondaryString, perUnitFormat, s
tatus); |
| 212 if (U_FAILURE(status)) { return result; } |
| 213 } |
| 214 // TODO: What field to use for units? |
| 215 multiSimpleFormatsToModifiers(primaryData, perUnitFormat, UNUM_FIELD_COUNT,
result.fModifiers, status); |
124 return result; | 216 return result; |
125 } | 217 } |
126 | 218 |
127 LongNameHandler LongNameHandler::forCurrencyLongNames(const Locale &loc, const C
urrencyUnit ¤cy, | 219 LongNameHandler LongNameHandler::forCurrencyLongNames(const Locale &loc, const C
urrencyUnit ¤cy, |
128 const PluralRules *rules, | 220 const PluralRules *rules, |
129 const MicroPropsGenerator
*parent, | 221 const MicroPropsGenerator
*parent, |
130 UErrorCode &status) { | 222 UErrorCode &status) { |
131 LongNameHandler result(rules, parent); | 223 LongNameHandler result(rules, parent); |
132 UnicodeString simpleFormats[StandardPlural::Form::COUNT]; | 224 UnicodeString simpleFormats[ARRAY_LENGTH]; |
133 getCurrencyLongNameData(loc, currency, simpleFormats, status); | 225 getCurrencyLongNameData(loc, currency, simpleFormats, status); |
134 if (U_FAILURE(status)) { return result; } | 226 if (U_FAILURE(status)) { return result; } |
135 simpleFormatsToModifiers(simpleFormats, UNUM_CURRENCY_FIELD, result.fModifie
rs, status); | 227 simpleFormatsToModifiers(simpleFormats, UNUM_CURRENCY_FIELD, result.fModifie
rs, status); |
136 return result; | 228 return result; |
137 } | 229 } |
138 | 230 |
139 void LongNameHandler::simpleFormatsToModifiers(const UnicodeString *simpleFormat
s, Field field, | 231 void LongNameHandler::simpleFormatsToModifiers(const UnicodeString *simpleFormat
s, Field field, |
140 SimpleModifier *output, UErrorCod
e &status) { | 232 SimpleModifier *output, UErrorCod
e &status) { |
141 for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) { | 233 for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) { |
142 UnicodeString simpleFormat = simpleFormats[i]; | 234 UnicodeString simpleFormat = getWithPlural(simpleFormats, i, status); |
143 if (simpleFormat.isBogus()) { | 235 if (U_FAILURE(status)) { return; } |
144 simpleFormat = simpleFormats[StandardPlural::Form::OTHER]; | |
145 } | |
146 if (simpleFormat.isBogus()) { | |
147 // There should always be data in the "other" plural variant. | |
148 status = U_INTERNAL_PROGRAM_ERROR; | |
149 return; | |
150 } | |
151 SimpleFormatter compiledFormatter(simpleFormat, 1, 1, status); | 236 SimpleFormatter compiledFormatter(simpleFormat, 1, 1, status); |
| 237 if (U_FAILURE(status)) { return; } |
152 output[i] = SimpleModifier(compiledFormatter, field, false); | 238 output[i] = SimpleModifier(compiledFormatter, field, false); |
| 239 } |
| 240 } |
| 241 |
| 242 void LongNameHandler::multiSimpleFormatsToModifiers(const UnicodeString *leadFor
mats, UnicodeString trailFormat, |
| 243 Field field, SimpleModifier
*output, UErrorCode &status) { |
| 244 SimpleFormatter trailCompiled(trailFormat, 1, 1, status); |
| 245 if (U_FAILURE(status)) { return; } |
| 246 for (int32_t i = 0; i < StandardPlural::Form::COUNT; i++) { |
| 247 UnicodeString leadFormat = getWithPlural(leadFormats, i, status); |
| 248 if (U_FAILURE(status)) { return; } |
| 249 UnicodeString compoundFormat; |
| 250 trailCompiled.format(leadFormat, compoundFormat, status); |
| 251 if (U_FAILURE(status)) { return; } |
| 252 SimpleFormatter compoundCompiled(compoundFormat, 1, 1, status); |
| 253 if (U_FAILURE(status)) { return; } |
| 254 output[i] = SimpleModifier(compoundCompiled, field, false); |
153 } | 255 } |
154 } | 256 } |
155 | 257 |
156 void LongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps &mic
ros, | 258 void LongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps &mic
ros, |
157 UErrorCode &status) const { | 259 UErrorCode &status) const { |
158 parent->processQuantity(quantity, micros, status); | 260 parent->processQuantity(quantity, micros, status); |
159 // TODO: Avoid the copy here? | 261 // TODO: Avoid the copy here? |
160 DecimalQuantity copy(quantity); | 262 DecimalQuantity copy(quantity); |
161 micros.rounding.apply(copy, status); | 263 micros.rounding.apply(copy, status); |
162 micros.modOuter = &fModifiers[copy.getStandardPlural(rules)]; | 264 micros.modOuter = &fModifiers[copy.getStandardPlural(rules)]; |
163 } | 265 } |
164 | 266 |
165 #endif /* #if !UCONFIG_NO_FORMATTING */ | 267 #endif /* #if !UCONFIG_NO_FORMATTING */ |
LEFT | RIGHT |