Using MF2 with JavaScript

The following guide explains how to use the mf2-messageformat package to format MF2 messages. For full API documentation, see the API documentation site for the package. This guide shows the simplest use cases for the API. More advanced uses are possible, which are documented in the API documentation.

Installation and setup Jump to heading

Install/add the package to your project. If you're using Node.js with npm, you can do this by running

npm install --save-exact messageformat@next

or use the corresponding operation for your preferred package manager. For instance, for Deno projects, you can run

deno add npm:messageformat@next

once that's done, you can import the contructor in your code like

import { MessageFormat } from 'messageformat';

The MessageFormat class Jump to heading

The main class for formatting messages is MessageFormat. The class has two methods you are likely to call: format() and formatToParts().

The MessageFormat constructor Jump to heading

The constructor takes a message string and one or more locales. Example:

const mf = new MessageFormat("Hello {$user}", ["en", "fr"]);

mf is now a message formatter object that can be re-used to format the same message with different arguments.

The constructor has an optional third argument, which can be used to specify custom functions (not covered in this document). The full documentation covers custom functions.

The format() method Jump to heading

The format() method formats the message formatter's message as a string. Example:

const mf = new MessageFormat("Hello {$user}", "en");
const result = mf.format({"user": "Bob"});
// result === "Hello Bob"

The first argument to format() is an object that specifies values for any external variables mentioned in the message.

format() has an optional second argument, which is used for reporting errors.

const mf = new MessageFormat("Hello {$user}", "en");
const result = mf.format({"us3r": "Bob"}, (error) => console.log(error.type));
// result === "Hello {$user}"
// Logs the string "unresolved-var" to the console

Messages can contain errors. In this case, format() returns a best-effort result: in this case, "Hello {$user}", because no value was given for "user". Passing in a callback gives the caller a way to check for errors. In this case, the error is an "unresolved variable" error. In this example, the error handling callback just logs the type of the error, for brevity. The full error could also be logged. The MessageError class defines the structure of errors: see the API documentation.

The formatToParts() method Jump to heading

The formatToParts() method is useful when different pieces of the formatted message need to be extracted and processed separately. It avoids the need to re-parse the formatted string, which is useful for frameworks like React where you might want to preprocess the formatted result before rendering it.

Example:

const mf = new MessageFormat("{#b}Hello {$user}{/b}", "en");
const result = mf.formatToParts({"user": "Bob"});
}

Unlike with format(), result is an array of MessageParts. In this case, it looks like:

[
  { type: 'markup', kind: 'open', source: '#b', name: 'b' },
  { type: 'literal', value: 'Hello ' },
  { type: 'string', source: '$user', locale: 'en', value: 'Bob' },
  { type: 'markup', kind: 'close', source: '/b', name: 'b' }
]

Each part is the formatted representation of one of the parts of the source message.

In this case, there are four parts, representing:

  1. The opening b markup placeholder.
  2. The literal part "Hello ", which appeared literally in the source message.
  3. The expression part, representing an expression in the source message ($user) along with its formatted value, "Bob".
  4. The closing b markup placeholder.

As with format(), formatToParts() can take an optional error callback as its second argument.

The MessagePart type Jump to heading

MessagePart is defined as follows (full documentation):

export type MessagePart = MessageExpressionPart | MessageLiteralPart | MessageMarkupClosePart | MessageMarkupPart;

In the formatToParts() example, part 1 is a MessageMarkupPart; part 2 is a MessageLiteralPart; part 3 is a MessageExpressionPart; and part 4 is a MessageMarkupClosePart.

The MessageMarkupPart interface Jump to heading

A MessageMarkupPart has 'markup' as its type property. Its other properties are:

  • kind: Either "open" (like {#b}) or "standalone" (like {#b/}).
  • name: The name of the markup placeholder ("b" in the example).
  • source: A string representation of the source markup placeholder.
  • options: The formatted options of this markup placeholder (an advanced feature).

The MessageMarkupClosePart interface Jump to heading

Same as MessageMarkupPart, but kind is always "close".

The MessageLiteralPart interface Jump to heading

The type property is 'literal'. It has one other property, value. For literal parts, the source representation and the formatted value are identical to each other.

The MessageExpressionPart interface Jump to heading

The type property is a string representation of the type of this expression. In the above example, it's 'string', because the runtime value of {$user} is a string (a string value was provided for the value of the external variable $user.)

The other properties are source (as with MessageMarkupPart) and value (as with MessageLiteralPart). Since an expression's contents vary depending on input, source and value are usually different from each other.

See the full MessageExpressionPart documentation for more.