Skip to content

Commit 1abcef0

Browse files
committed
Function context and u:options
1 parent a51dc3e commit 1abcef0

11 files changed

+379
-105
lines changed

icu4c/source/i18n/messageformat2.cpp

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "unicode/messageformat2_data_model.h"
1212
#include "unicode/messageformat2_formattable.h"
1313
#include "unicode/messageformat2.h"
14+
#include "unicode/ubidi.h"
1415
#include "unicode/unistr.h"
1516
#include "messageformat2_allocation.h"
1617
#include "messageformat2_evaluation.h"
@@ -153,6 +154,48 @@ FunctionOptions MessageFormatter::resolveOptions(const Environment& env,
153154
return FunctionOptions(std::move(*optionsVector), status);
154155
}
155156

157+
static UBiDiDirection getBiDiDirection(const Locale& locale,
158+
const UnicodeString& s) {
159+
if (s.isEmpty()) {
160+
return locale.isRightToLeft() ? UBIDI_RTL : UBIDI_LTR;
161+
}
162+
if (s == u"ltr") {
163+
return UBIDI_LTR;
164+
}
165+
if (s == u"rtl") {
166+
return UBIDI_RTL;
167+
}
168+
if (s == u"auto") {
169+
return UBIDI_MIXED;
170+
}
171+
return UBIDI_NEUTRAL;
172+
}
173+
174+
FunctionContext MessageFormatter::makeFunctionContext(const FunctionOptions& options) const {
175+
// Look up "u:locale", "u:dir", and "u:id" in the options
176+
UnicodeString localeStr = options.getStringFunctionOption(UnicodeString("u:locale"));
177+
178+
// Use default locale from context, unless "u:locale" is provided
179+
Locale localeToUse;
180+
if (localeStr.isEmpty()) {
181+
localeToUse = locale;
182+
} else {
183+
UErrorCode localStatus = U_ZERO_ERROR;
184+
std::string u8;
185+
Locale l = Locale::forLanguageTag(localeStr.toUTF8String(u8), localStatus);
186+
if (U_SUCCESS(localStatus)) {
187+
localeToUse = l;
188+
} else {
189+
localeToUse = locale;
190+
}
191+
}
192+
UBiDiDirection dir = getBiDiDirection(localeToUse,
193+
options.getStringFunctionOption(UnicodeString("u:dir")));
194+
UnicodeString id = options.getStringFunctionOption(UnicodeString("u:id"));
195+
196+
return FunctionContext(localeToUse, dir, id);
197+
}
198+
156199
// Looks up `functionName` and applies it to an operand and options,
157200
// handling errors if the function is unbound
158201
[[nodiscard]] InternalValue MessageFormatter::apply(const FunctionName& functionName,
@@ -180,13 +223,16 @@ FunctionOptions MessageFormatter::resolveOptions(const Environment& env,
180223
context.getErrors().setUnknownFunction(functionName, status);
181224
return InternalValue::fallback(fallbackStr);
182225
}
183-
LocalPointer<Function> function(functionFactory->createFunction(locale, status));
226+
LocalPointer<Function> function(functionFactory->createFunction(status));
184227
// Value is not a fallback, so we can safely call takeValue()
185228
LocalPointer<FunctionValue> functionArg(rand.takeValue(status));
186229
U_ASSERT(U_SUCCESS(status));
187230
// Call the function
188231
LocalPointer<FunctionValue>
189-
functionResult(function->call(*functionArg, std::move(options), status));
232+
functionResult(function->call(makeFunctionContext(options),
233+
*functionArg,
234+
std::move(options),
235+
status));
190236
// Handle any errors signaled by the function
191237
// (and use the fallback value)
192238
if (status == U_MF_OPERAND_MISMATCH_ERROR) {

icu4c/source/i18n/messageformat2_evaluation.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#if !UCONFIG_NO_MF2
99

10+
#include "unicode/ubidi.h"
1011
#include "messageformat2_allocation.h"
1112
#include "messageformat2_evaluation.h"
1213
#include "messageformat2_macros.h"
@@ -34,10 +35,13 @@ BaseValue::BaseValue(const Locale& loc, const Formattable& source)
3435
return message2::create<BaseValue>(BaseValue(locale, source), errorCode);
3536
}
3637

37-
extern UnicodeString formattableToString(const Locale&, const Formattable&, UErrorCode&);
38+
extern UnicodeString formattableToString(const Locale&, const UBiDiDirection, const Formattable&, UErrorCode&);
3839

3940
UnicodeString BaseValue::formatToString(UErrorCode& errorCode) const {
40-
return formattableToString(locale, operand, errorCode);
41+
return formattableToString(locale,
42+
UBIDI_NEUTRAL,
43+
operand,
44+
errorCode);
4145
}
4246

4347
BaseValue& BaseValue::operator=(BaseValue&& other) noexcept {

icu4c/source/i18n/messageformat2_formattable.cpp

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99

1010
#include "unicode/messageformat2_formattable.h"
1111
#include "unicode/smpdtfmt.h"
12+
#include "unicode/ubidi.h"
1213
#include "messageformat2_allocation.h"
1314
#include "messageformat2_macros.h"
15+
#include "ubidiimp.h"
1416

1517
#include "limits.h"
1618

@@ -184,9 +186,37 @@ namespace message2 {
184186
df->format(date, result, 0, errorCode);
185187
}
186188

189+
static UnicodeString& handleBiDi(const Locale& locale,
190+
UBiDiDirection dir,
191+
UnicodeString& result) {
192+
switch (dir) {
193+
case UBIDI_LTR:
194+
if (locale.isRightToLeft()) {
195+
result.insert(0, LRI_CHAR);
196+
result.insert(result.length(), PDI_CHAR);
197+
}
198+
break;
199+
case UBIDI_RTL:
200+
result.insert(0, RLI_CHAR);
201+
result.insert(result.length(), PDI_CHAR);
202+
break;
203+
case UBIDI_NEUTRAL:
204+
// Do nothing
205+
break;
206+
case UBIDI_MIXED:
207+
// mixed = auto
208+
result.insert(0, FSI_CHAR);
209+
result.insert(result.length(), PDI_CHAR);
210+
break;
211+
}
212+
213+
return result;
214+
}
215+
187216
UnicodeString formattableToString(const Locale& locale,
188-
const Formattable& toFormat,
189-
UErrorCode& status) {
217+
UBiDiDirection dir,
218+
const Formattable& toFormat,
219+
UErrorCode& status) {
190220
EMPTY_ON_ERROR(status);
191221

192222
// Try as decimal number first
@@ -205,33 +235,37 @@ namespace message2 {
205235
}
206236

207237
UFormattableType type = toFormat.getType();
238+
UnicodeString result;
239+
208240
switch (type) {
209241
case UFMT_DATE: {
210-
UnicodeString result;
211242
UDate d = toFormat.getDate(status);
212243
U_ASSERT(U_SUCCESS(status));
213244
formatDateWithDefaults(locale, d, result, status);
214-
return result;
245+
break;
215246
}
216247
case UFMT_DOUBLE: {
217248
double d = toFormat.getDouble(status);
218249
U_ASSERT(U_SUCCESS(status));
219-
return formatNumberWithDefaults(locale, d, status).toString(status);
250+
result = formatNumberWithDefaults(locale, d, status).toString(status);
251+
break;
220252
}
221253
case UFMT_LONG: {
222254
int32_t l = toFormat.getLong(status);
223255
U_ASSERT(U_SUCCESS(status));
224-
return formatNumberWithDefaults(locale, l, status).toString(status);
256+
result = formatNumberWithDefaults(locale, l, status).toString(status);
257+
break;
225258
}
226259
case UFMT_INT64: {
227260
int64_t i = toFormat.getInt64Value(status);
228261
U_ASSERT(U_SUCCESS(status));
229-
return formatNumberWithDefaults(locale, i, status).toString(status);
262+
result = formatNumberWithDefaults(locale, i, status).toString(status);
263+
break;
230264
}
231265
case UFMT_STRING: {
232-
const UnicodeString& s = toFormat.getString(status);
266+
result = toFormat.getString(status);
233267
U_ASSERT(U_SUCCESS(status));
234-
return s;
268+
break;
235269
}
236270
default: {
237271
// No default formatters for other types; use fallback
@@ -242,6 +276,8 @@ namespace message2 {
242276
return {};
243277
}
244278
}
279+
280+
return handleBiDi(locale, dir, result);
245281
}
246282

247283
} // namespace message2

0 commit comments

Comments
 (0)