| /* GENERATED SOURCE. DO NOT MODIFY. */ |
| // © 2022 and later: Unicode, Inc. and others. |
| // License & terms of use: https://www.unicode.org/copyright.html |
| |
| package android.icu.message2; |
| |
| import java.util.Locale; |
| import java.util.Map; |
| |
| /** |
| * <h3>Overview of {@code MessageFormatter}</h3> |
| * |
| * <p>In ICU4J, the {@code MessageFormatter} class is the next iteration of {@link android.icu.text.MessageFormat}. |
| * This new version will build on the lessons learned from using MessageFormat for 25 years |
| * in various environments, when used directly or as a base for other public APIs.</p> |
| * |
| * |
| * <p>The effort to design a succesor to {@code MessageFormat} will result in a specification |
| * referred to as MessageFormat 2.0. |
| * The reasoning for this effort is shared in the |
| * <a target="github" href="https://github.com/unicode-org/message-format-wg/blob/main/docs/why_mf_next.md">“Why |
| * MessageFormat needs a successor”</a> document.</p> |
| * |
| * <p>MessageFormat 2.0 will be more modular and easier to port and backport. |
| * It will also provide extension points via interfaces to allow users to supply new formatters and selectors without having to modify the specification. |
| * ICU will eventually include support for new formatters, such as intervals, relative time, lists, measurement units, personal names, and more, |
| * as well as the ability for users to supply their own custom implementations. |
| * These will potentially support use cases like grammatical gender, inflection, markup regimes (such as those require for text-to-speech), |
| * and other complex message management needs.</p> |
| * |
| * <p>The MessageFormat Working Group, which develops the new data model, semantics, and syntax, |
| * is hosted on <a target="github" href="https://github.com/unicode-org/message-format-wg">GitHub</a>. |
| * The current specification for the syntax and data model can be found |
| * <a target="github" href="https://github.com/unicode-org/message-format-wg/blob/main/spec/syntax.md">here</a>.</p> |
| * |
| * <p>This technical preview implements enough functions for {@code MessageFormatter} to be useful in many situations, |
| * but the final set of functions and the parameters accepted by those functions is not yet finalized.</p> |
| * |
| * <h3>Examples</h3> |
| * |
| * <h4>Basic usage</h4> |
| * |
| * <blockquote><pre> |
| * import static org.junit.Assert.assertEquals; |
| * import java.util.Date; |
| * import java.util.HashMap; |
| * import java.util.Locale; |
| * import java.util.Map; |
| * |
| * import android.icu.message2.MessageFormatter; |
| * |
| * @Test |
| * public void test() { |
| * final Locale enGb = Locale.forLanguageTag("en-GB"); |
| * Map<String, Object> arguments = new HashMap<>(); |
| * arguments.put("name", "John"); |
| * arguments.put("exp", new Date(2023 - 1900, 2, 27, 19, 42, 51)); // March 27, 2023, 7:42:51 PM |
| * |
| * MessageFormatter mf2 = MessageFormatter.builder() |
| * .setPattern("Hello {$name}, your card expires on {$exp :datetime year=numeric month=short day=numeric weekday=short}!") |
| * .setLocale(enGb) |
| * .build(); |
| * |
| * assertEquals( |
| * "Hello John, your card expires on Mon, 27 Mar 2023!", |
| * mf2.formatToString(arguments)); |
| * } |
| * </pre></blockquote> |
| * |
| * <h4>Placeholder examples</h4> |
| * |
| * <table border="1"> |
| * <tr> |
| * <th>Code to set runtime value for placeholder</th> |
| * <th>Examples of placeholder in message pattern</th> |
| * </tr> |
| * <tr> |
| * <td><code>arguments.put("name", "John")</code></td> |
| * <td><code>{$name}</code></td> |
| * </tr> |
| * <tr> |
| * <td><code>arguments.put("exp", new Date(…))</code></td> |
| * <td><code>{$exp :datetime skeleton=year=numeric month=short day=numeric weekday=short}</code> <br> |
| * <code>{$exp :datetime dateStyle=full}</code></td> |
| * </tr> |
| * <tr> |
| * <td><code>arguments.put("val", 3.141592653)</code></td> |
| * <td><code>{$val}</code> <br> <code>{$val :number minimumFractionDigits=5}</code></td> |
| * </tr> |
| * <tr> |
| * <td>No argument for fixed values known at build time</td> |
| * <td><code>{|123456789.531| :number}</code></td> |
| * </tr> |
| * </table> |
| * |
| * <h4>Plural selection message</h4> |
| * |
| * <blockquote><pre> |
| * @Test |
| * public void testSelection() { |
| * final String message = ".match {$count :number}\n" |
| * + " 1 {{You have one notification.}}\n" |
| * + " * {{You have {$count} notifications.}}\n"; |
| * final Locale enGb = Locale.forLanguageTag("en-GB"); |
| * Map<String, Object> arguments = new HashMap<>(); |
| * |
| * MessageFormatter mf2 = MessageFormatter.builder() |
| * .setPattern(message) |
| * .setLocale(enGb) |
| * .build(); |
| * |
| * arguments.put("count", 1); |
| * assertEquals( |
| * "You have one notification.", |
| * mf2.formatToString(arguments)); |
| * |
| * arguments.put("count", 42); |
| * assertEquals( |
| * "You have 42 notifications.", |
| * mf2.formatToString(arguments)); |
| * } |
| * </pre></blockquote> |
| * |
| * <h4>Built-in formatter functions</h4> |
| * |
| * <p>The tech preview implementation comes with formatters for numbers ({@code :number}), |
| * date / time ({@code :datetime}, {@code :date}, {@code :time}), |
| * plural selectors ({@code :number} with options for {@code plural} and {@code ordinal} selection), |
| * and general selector ({@code :string}), |
| * very similar to what {@code MessageFormat} offers.</p> |
| * |
| * <p>The <a target="github" href="https://github.com/unicode-org/icu/tree/main/icu4j/main/core/src/test/java/com/ibm/icu/dev/test/message2">ICU test code</a> |
| * covers most features, and has examples of how to make custom placeholder formatters; |
| * you can look for classes that implement {@code android.icu.message2.FormatterFactory} |
| * (they are named {@code Custom*Test.java}).</p> |
| * |
| * <p>The complete list of valid options for each function, and how they infulence the results, can be found at |
| * <a target="github" href="https://github.com/unicode-org/message-format-wg/blob/main/spec/registry.md">here</a>.<p> |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide Only a subset of ICU is exposed in Android |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public class MessageFormatter { |
| private final Locale locale; |
| private final String pattern; |
| private final MFFunctionRegistry functionRegistry; |
| private final MFDataModel.Message dataModel; |
| private final MFDataModelFormatter modelFormatter; |
| |
| private MessageFormatter(Builder builder) { |
| this.locale = builder.locale; |
| this.functionRegistry = builder.functionRegistry; |
| if ((builder.pattern == null && builder.dataModel == null) |
| || (builder.pattern != null && builder.dataModel != null)) { |
| throw new IllegalArgumentException( |
| "You need to set either a pattern, or a dataModel, but not both."); |
| } |
| |
| if (builder.dataModel != null) { |
| this.dataModel = builder.dataModel; |
| // this.pattern = MFSerializer.dataModelToString(this.dataModel); |
| this.pattern = MFSerializer.dataModelToString(dataModel); |
| } else { |
| this.pattern = builder.pattern; |
| try { |
| this.dataModel = MFParser.parse(pattern); |
| } catch (MFParseException pe) { |
| throw new IllegalArgumentException("" |
| + "Parse error:\n" |
| + "Message: <<" + pattern + ">>\n" |
| + "Error: " + pe.getMessage() + "\n"); |
| } |
| } |
| modelFormatter = new MFDataModelFormatter(dataModel, locale, functionRegistry); |
| } |
| |
| /** |
| * Creates a builder. |
| * |
| * @return the Builder. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public static Builder builder() { |
| return new Builder(); |
| } |
| |
| /** |
| * Get the locale to use for all the formatting and selections in |
| * the current {@code MessageFormatter}. |
| * |
| * @return the locale. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public Locale getLocale() { |
| return locale; |
| } |
| |
| /** |
| * Get the pattern (the serialized message in MessageFormat 2 syntax) of |
| * the current {@code MessageFormatter}. |
| * |
| * <p>If the {@code MessageFormatter} was created from an {@link MFDataModel} |
| * the this string is generated from that model.</p> |
| * |
| * @return the pattern. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public String getPattern() { |
| return pattern; |
| } |
| |
| /** |
| * Give public access to the message data model. |
| * |
| * <p>This data model is similar to the functionality we have today |
| * in {@link android.icu.text.MessagePatternUtil} maybe even a bit more higher level.</p> |
| * |
| * <p>We can also imagine a model where one parses the string syntax, takes the data model, |
| * modifies it, and then uses that modified model to create a {@code MessageFormatter}.</p> |
| * |
| * @return the data model. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public MFDataModel.Message getDataModel() { |
| return dataModel; |
| } |
| |
| /** |
| * Formats a map of objects by iterating over the MessageFormat's pattern, |
| * with the plain text “as is” and the arguments replaced by the formatted objects. |
| * |
| * @param arguments a map of objects to be formatted and substituted. |
| * @return the string representing the message with parameters replaced. |
| * |
| * @throws IllegalArgumentException when something goes wrong |
| * (for example wrong argument type, or null arguments, etc.) |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public String formatToString(Map<String, Object> arguments) { |
| return modelFormatter.format(arguments); |
| } |
| |
| /** |
| * Not yet implemented: formats a map of objects by iterating over the MessageFormat's |
| * pattern, with the plain text “as is” and the arguments replaced by the formatted objects. |
| * |
| * @param arguments a map of objects to be formatted and substituted. |
| * @return the {@link FormattedMessage} class representing the message with parameters replaced. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| @SuppressWarnings("static-method") |
| public FormattedMessage format(Map<String, Object> arguments) { |
| throw new RuntimeException("Not yet implemented."); |
| } |
| |
| /** |
| * A {@code Builder} used to build instances of {@link MessageFormatter}. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide Only a subset of ICU is exposed in Android |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public static class Builder { |
| private Locale locale = Locale.getDefault(Locale.Category.FORMAT); |
| private String pattern = null; |
| private MFFunctionRegistry functionRegistry = MFFunctionRegistry.builder().build(); |
| private MFDataModel.Message dataModel = null; |
| |
| // Prevent direct creation |
| private Builder() {} |
| |
| /** |
| * Sets the locale to use for all formatting and selection operations. |
| * |
| * @param locale the locale to set. |
| * @return the builder, for fluent use. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public Builder setLocale(Locale locale) { |
| this.locale = locale; |
| return this; |
| } |
| |
| /** |
| * Sets the pattern (in MessageFormat 2 syntax) used to create the message.<br> |
| * It conflicts with the data model, so it will reset it (the last call on setter wins). |
| * |
| * @param pattern the pattern to set. |
| * @return the builder, for fluent use. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public Builder setPattern(String pattern) { |
| this.pattern = pattern; |
| this.dataModel = null; |
| return this; |
| } |
| |
| /** |
| * Sets an instance of {@link MFFunctionRegistry} that should register any |
| * custom functions used by the message. |
| * |
| * <p>There is no need to do this in order to use standard functions |
| * (for example date / time / number formatting, plural / ordinal / literal selection).<br> |
| * The exact set of standard functions, with the types they format and the options |
| * they accept is still TBD.</p> |
| * |
| * @param functionRegistry the function registry to set. |
| * @return the builder, for fluent use. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public Builder setFunctionRegistry(MFFunctionRegistry functionRegistry) { |
| this.functionRegistry = functionRegistry; |
| return this; |
| } |
| |
| /** |
| * Sets the data model used to create the message.<br> |
| * It conflicts with the pattern, so it will reset it (the last call on setter wins). |
| * |
| * @param dataModel the pattern to set. |
| * @return the builder, for fluent use. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public Builder setDataModel(MFDataModel.Message dataModel) { |
| this.dataModel = dataModel; |
| this.pattern = null; |
| return this; |
| } |
| |
| /** |
| * Builds an instance of {@link MessageFormatter}. |
| * |
| * @return the {@link MessageFormatter} created. |
| * |
| * @deprecated This API is for technology preview only. |
| * @hide draft / provisional / internal are hidden on Android |
| */ |
| @Deprecated |
| public MessageFormatter build() { |
| return new MessageFormatter(this); |
| } |
| } |
| } |