Fluent Syntax 0.8

tl;dr: Fluent Syntax is now feature-frozen.

In the beginning of December I published version 0.8 of the Fluent Syntax spec. The updates to the our official implementations followed a week later: fluent 0.10 and fluent-syntax 0.10 in JavaScript and fluent 0.10 in Python were released on December 13.

We expect this to be the last important milestone before Fluent Syntax reaches 1.0. We don’t have any more changes to the syntax planned before 1.0. There might still be a 0.9 or a 1.0 RC along the way to give us the opportunity to fix something we discover in this cycle, to remove the deprecated grammar, and to clean up the AST. No new features, though. Fluent Syntax is now feature-frozen.

Syntax 0.8 represents what we think should become Fluent Syntax 1.0 in a couple of months. We’ll use this time to make sure it’s ready to go gold, to improve the learning resources, and to polish the tools which already exist in the Fluent ecosystem.

This is a really good time to give Fluent a try. There are a few new features in Syntax 0.8 and we’d love to gather feedback about them. I’ll summarize them below and highlight what’s interesting about them. The full changelog has all the details.

New: Preserve content-indent in multiline Patterns

This new behavior changes how indentation is removed from multiline text. In Syntax 0.7 only the common indent across all indented lines of the pattern is stripped. (As opposed to all indent in Syntax 0.7).

multiline1 =
    This message has two spaces of indent
      on the second line of its value.

multiline2 =
      This message has two spaces of indent
    on the first line of its value.

This feature has been added to make it possible to express more variations of multiline content in Fluent, and to preserve the formatting and the layout of text. For example, you can now localize Markdown content with Fluent; the values of messages will preserve the indent so that your code blocks are displayed correctly. You can also put more HTML markup into your messages and have your preferred formatting preserved across parsing and serializing.

We tried our best to devise simple and predictable rules for this behavior; hopefully it does exactly what you think it should do all of the time. There are some edge cases related to patterns which start on the same line as the message identifier. See the full changelog for details. Please test this new behavior in the Fluent Playground and in your projects.

New: Parameterized Terms and the deprecation of VariantLists

There’s now a new way to define and reference Term variants. Rather than use a VariantLists which looks like a SelectExpression without the selector, it’s now possible to use a regular SelectExpression and then call the term as if it was a function.

# BEFORE (Syntax 0.7) A Term with a VariantList as a value.
-thing = {
   *[definite] the thing
     [indefinite] a thing
}

this = This is { -term[indefinite] }.

# AFTER (Syntax 0.8) A parametrized Term with a Pattern as a value.
-thing = { $article ->
   *[definite] the thing
    [indefinite] a thing
}

this = This is { -thing(article: "indefinite") }.

This new design has a number of advantages: it’s easy to create nested variants and it’s easy to pass more than one selector to the term; selector names are also self-documenting. The same syntax can be used to parameterize term attributes.

Parameterization removes the need for the (underspecified) VariantLists. Consequently, we’ve deprecated VariantLists and VariantExpressions in Syntax 0.8. They are still supported to make the transition to parameterized terms easier for tools and existing deployments. If your project makes use of VariantLists, please migrate it to this new syntax.

This feature leverages the existing syntax known from calling number and date formatting functions, e.g. NUMBER($progress, style: "percent"). We haven’t seen much use of this syntax in the past; the defaults for formatting numbers and dates are usually good enough. With the addition of parameterized terms you may see this syntax more often now. We’re open to feedback about its readability and ergonomics.

Changed: Special characters in TextElements and StringLiterals

Syntax 0.8 simplifies character handling in TextElements. Both the opening and the closing curly braces are now considered special. The backslash is now a regular character and no escape sequences are supported (in TextElements).

Escape sequences are still supported in StringLiterals; they are particularly useful for including invisible characters in the translation ({"\u00A0"} stands for the non-breaking space) or characters with lookalikes (e.g. the hyphen and the minus, the en dash and the em dash).

A new six-digit long Unicode codepoint escape sequence {"\UHHHHHH"} has been added to StringLiterals in order to allow encoding characters from other planes than the BMP. {"\U01F602"} can be used to insert :joy: into the translation. Whenever possible, however, and if it doesn’t hurt the readability for other translators, the actual character should be preferred. Translations in Fluent can make use of all Unicode characters as of Syntax 0.8.

Thank you

Thanks to all of you who responded to the RFC for syntax features which I posted in the past. Thanks to the commenters, reviewers and patch authors on GitHub. Thanks to the PM team who helped plan the rollout of Syntax 0.8 across different Mozilla products. Thanks to the developers who gave Fluent a chance and installed it to develop and deploy their apps. And thanks to the localizers for using Fluent to create great translations!