Skip to content

Commit

Permalink
ICU-23044 MF2, ICU4J, bring the implementation close to the spec at L…
Browse files Browse the repository at this point in the history
…DML 47
  • Loading branch information
mihnita committed Feb 13, 2025
1 parent ecd22c1 commit acc69ce
Show file tree
Hide file tree
Showing 55 changed files with 2,442 additions and 805 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -328,7 +328,7 @@ public void testAllKindOfNumbers() {
public void testSpecialPluralWithDecimals() {
String message;
message = ".local $amount = {$count :number}\n"
+ ".match {$amount :number}\n"
+ ".match $amount\n"
+ " 1 {{I have {$amount} dollar.}}\n"
+ " * {{I have {$amount} dollars.}}";
TestUtils.runTestCase(new TestCase.Builder()
Expand All @@ -338,7 +338,7 @@ public void testSpecialPluralWithDecimals() {
.expected("I have 1 dollar.")
.build());
message = ".local $amount = {$count :number minimumFractionDigits=2}\n"
+ ".match {$amount :number minimumFractionDigits=2}\n"
+ ".match $amount\n"
+ " one {{I have {$amount} dollar.}}\n"
+ " * {{I have {$amount} dollars.}}";
TestUtils.runTestCase(new TestCase.Builder()
Expand Down Expand Up @@ -367,7 +367,8 @@ public void testDefaultFunctionAndOptions() {

@Test
public void testSimpleSelection() {
String message = ".match {$count :number}\n"
String message = ".input {$count :number}\n"
+ ".match $count\n"
+ " 1 {{You have one notification.}}\n"
+ " * {{You have {$count} notifications.}}";

Expand All @@ -386,7 +387,9 @@ public void testSimpleSelection() {
@Test
public void testComplexSelection() {
String message = ""
+ ".match {$photoCount :number} {$userGender :string}\n"
+ ".input {$photoCount :number}\n"
+ ".input {$userGender :string}\n"
+ ".match $photoCount $userGender\n"
+ " 1 masculine {{{$userName} added a new photo to his album.}}\n"
+ " 1 feminine {{{$userName} added a new photo to her album.}}\n"
+ " 1 * {{{$userName} added a new photo to their album.}}\n"
Expand Down Expand Up @@ -437,8 +440,9 @@ public void testSimpleLocaleVariable() {
@Test
public void testLocaleVariableWithSelect() {
String message = ""
+ ".input {$count :number}\n"
+ ".local $exp = {$expDate :date year=numeric month=short day=numeric weekday=short}\n"
+ ".match {$count :number}\n"
+ ".match $count\n"
+ " 1 {{Your ticket expires on {$exp}.}}\n"
+ " * {{Your {$count} tickets expire on {$exp}.}}";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ private static int stringToStyle(String option) {
*/
@Override
public Formatter createFormatter(Locale locale, Map<String, Object> fixedOptions) {
locale = OptUtils.getBestLocale(fixedOptions, locale);
Directionality dir = OptUtils.getBestDirectionality(fixedOptions, locale);

boolean reportErrors = OptUtils.reportErrors(fixedOptions);
int dateStyle = DateFormat.NONE;
int timeStyle = DateFormat.NONE;
switch (kind) {
Expand Down Expand Up @@ -98,7 +102,7 @@ public Formatter createFormatter(Locale locale, Map<String, Object> fixedOptions
}
if (!skeleton.isEmpty()) {
DateFormat df = DateFormat.getInstanceForSkeleton(skeleton, locale);
return new DateTimeFormatter(locale, df);
return new DateTimeFormatter(locale, df, reportErrors);
}

// No skeletons, custom or otherwise, match fallback to short / short as per spec.
Expand All @@ -119,7 +123,7 @@ public Formatter createFormatter(Locale locale, Map<String, Object> fixedOptions
}

DateFormat df = DateFormat.getDateTimeInstance(dateStyle, timeStyle, locale);
return new DateTimeFormatter(locale, df);
return new DateTimeFormatter(locale, df, reportErrors);
}

private static int getDateTimeStyle(Map<String, Object> options, String key) {
Expand Down Expand Up @@ -329,10 +333,12 @@ private static String getTimeFieldOptions(Map<String, Object> options) {
private static class DateTimeFormatter implements Formatter {
private final DateFormat icuFormatter;
private final Locale locale;
private final boolean reportErrors;

private DateTimeFormatter(Locale locale, DateFormat df) {
private DateTimeFormatter(Locale locale, DateFormat df, boolean reportErrors) {
this.locale = locale;
this.icuFormatter = df;
this.reportErrors = reportErrors;
}

/**
Expand All @@ -348,6 +354,9 @@ public FormattedPlaceholder format(Object toFormat, Map<String, Object> variable
toFormat = parseIso8601(toFormat.toString());
// We were unable to parse the input as iso date
if (toFormat instanceof CharSequence) {
if (reportErrors) {
throw new IllegalArgumentException("bad-operand: argument must be ISO 8601");
}
return new FormattedPlaceholder(
toFormat, new PlainStringFormattedValue("{|" + toFormat + "|}"));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// © 2025 and later: Unicode, Inc. and others.
// License & terms of use: https://www.unicode.org/copyright.html

package com.ibm.icu.message2;

import com.ibm.icu.util.ULocale;

/**
* Encodes info about the direction of the message.
*
* <p>It is used to implement the @code u:dir} functionality.</p>
*
* @internal ICU 77 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
public enum Directionality {
/**
* Not initialized or unknown.
*
* <p>No special processing will be used.
*
* @internal ICU 77 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
UNKNOWN,
/**
* Left-to-right directionality.
*
* @internal ICU 77 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
LTR,
/**
* Right-to-left directionality.
*
* @internal ICU 77 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
RTL,
/**
* Directionality determined from <i>expression</i> contents.
*
* @internal ICU 77 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
AUTO,
/**
* Directionality inherited from the <i>message</i> or from the <i>resolved value</i>
* of the <i>operand</i> without requiring isolation of the <i>expression</i> value.
*
* @internal ICU 77 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
INHERIT;

/**
* Determines the directionality appropriate for a given locale.
*
* @param ulocale the locale to determine the directionality from.
* @return the appropriate directionality for the locale given.
*
* @internal ICU 77 technology preview
* @deprecated This API is for technology preview only.
*/
@Deprecated
public static Directionality of(ULocale ulocale) {
if (ulocale == null ) {
return Directionality.INHERIT;
}
return ulocale.isRightToLeft() ? Directionality.RTL : Directionality.LTR;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,42 @@
public class FormattedPlaceholder {
private final FormattedValue formattedValue;
private final Object inputValue;
private final Directionality directionality;
private final boolean isolate;

/**
* Constructor creating the {@code FormattedPlaceholder}.
*
* @param inputValue the original value to be formatted.
* @param formattedValue the result of formatting the placeholder.
* @param directionality the directionality of the formatted placeholder.
*
* @internal ICU 72 technology preview
* @deprecated This API is for ICU internal use only.
*/
@Deprecated
public FormattedPlaceholder(Object inputValue, FormattedValue formattedValue) {
public FormattedPlaceholder(Object inputValue, FormattedValue formattedValue, Directionality directionality, boolean isolate) {
if (formattedValue == null) {
throw new IllegalAccessError("Should not try to wrap a null formatted value");
}
this.inputValue = inputValue;
this.formattedValue = formattedValue;
this.directionality = directionality;
this.isolate = isolate;
}

/**
* Constructor creating the {@code FormattedPlaceholder}.
*
* @param inputValue the original value to be formatted.
* @param formattedValue the result of formatting the placeholder.
*
* @internal ICU 72 technology preview
* @deprecated This API is for ICU internal use only.
*/
@Deprecated
public FormattedPlaceholder(Object inputValue, FormattedValue formattedValue) {
this(inputValue, formattedValue, Directionality.LTR, false);
}

/**
Expand Down Expand Up @@ -62,6 +81,32 @@ public FormattedValue getFormattedValue() {
return formattedValue;
}

/**
* Retrieve the directionality of the formatted the placeholder.
*
* @return the directionality.
*
* @internal ICU 77 technology preview
* @deprecated This API is for ICU internal use only.
*/
@Deprecated
public Directionality getDirectionality() {
return directionality;
}

/**
* Retrieve the BiDi isolate setting of the formatted the placeholder.
*
* @return the BiDi isolate setting.
*
* @internal ICU 77 technology preview
* @deprecated This API is for ICU internal use only.
*/
@Deprecated
public boolean getIsolate() {
return isolate;
}

/**
* Returns a string representation of the object.
* It can be null, which is unusual, and we plan to change that.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,24 @@ class IdentityFormatterFactory implements FormatterFactory {
*/
@Override
public Formatter createFormatter(Locale locale, Map<String, Object> fixedOptions) {
return new IdentityFormatterImpl();
return new IdentityFormatterImpl(OptUtils.getDirectionality(fixedOptions));
}

private static class IdentityFormatterImpl implements Formatter {
private final Directionality directionality;

public IdentityFormatterImpl(Directionality directionality) {
this.directionality = directionality == null ? Directionality.INHERIT : directionality;
}

/**
* {@inheritDoc}
*/
@Override
public FormattedPlaceholder format(Object toFormat, Map<String, Object> variableOptions) {
return new FormattedPlaceholder(
toFormat, new PlainStringFormattedValue(Objects.toString(toFormat)));
toFormat, new PlainStringFormattedValue(Objects.toString(toFormat)),
directionality, true);
}

/**
Expand Down
Loading

0 comments on commit acc69ce

Please sign in to comment.