Categories: Planet Pontoon Tools

Implementing Fluent in a localization tool

In order to produce natural sounding translations, Fluent syntax supports gender, plurals, conjugations, and virtually any other grammatical category. The syntax is designed to be simple to read, but translators without developer background might find more complex concepts harder to deal with.

That’s why we designed a Fluent-specific user interface in Pontoon, which unleashes Fluent powers to localizers who aren’t coders. Any other general purpose Translation Management System (TMS) with support for popular localization formats can follow the example. Let’s have a closer look at Fluent implementation in Pontoon.

Storing Fluent strings in the DB

We store Fluent translations in the Translation table differently compared to other file formats.

In the string column we usually only store the translatable content, which is sufficient for representing the translation across the application. For example, string hello = Hello, world! in the .properties file format is stored as Hello, world! in Translation.string. In Fluent, we store the entire string: hello = Hello, world!.

The main reason for storing full Fluent strings are attributes, which can be present in Fluent Messages and Terms in addition to their values. Having multiple localizable values stored together allows us to build advanced UIs like the ones we use for access keys (see below).

The alternative to storing the serialized string is to store its AST. At the time of implementing Fluent support in Pontoon, the AST wasn’t as stable as the syntax, but today you should be fine with using either of these approaches.

Different presentation formats

Due to their potential complexity, Fluent strings can be presented in 4 different ways in Pontoon:

  1. In simplified form: used in string list, History tab and various other places across Pontoon, it represents the string as it appears to the end-user in the application. We generate it using FluentSerializer.serializeExpression(). For example, hello = Hello, world! would appear simply as Hello, world!.
  2. In read-only form: used to represent the source string.
  3. In editable form: used to represent the translation in the editor.
  4. As source: used to represent the translation in the source editor.
Presentation formats

Where are different presentation formats used.
You can access the source view by clicking on the FTL button.

Example walk-through

The following is a list of various Fluent strings and their appearances in a Pontoon translation interface with source string panel on top and translation editor below. In the first batch are the strings using the existing Pontoon UI, shared with other file formats.

Simple strings
Simple strings

title = About Localization

Multiline strings
Multiline strings

feedbackUninstallCopy =
    Your participation in Firefox Test Pilot means
    a lot! Please check out our other experiments,
    and stay tuned for more to come!

Strings with a single attribute
Strings with a single attribute

emailOptInInput =
    .placeholder = email goes here :)

Next up are Fluent strings, which have attributes in addition to the value or multiple attributes. A separate text input is available for each of them.

Strings with a value and attributes
Strings with a value and an attribute

shotIndexNoExpirationSymbol = ∞
    .title = This shot does not expire

Since Fluent lets you combine labels and access keys within the same string, we designed a dedicated UI that lists all the allowed access keys as you translate the label. You can also type in a custom key if none of the candidates meets your criteria.

Access keys
Access keys

file-menu =
    .label = File
    .accesskey = F

Terms are similar to regular messages but they can only be used as references in other messages. Hence, they are best used to define vocabulary and glossary items which can be used consistently across the localization of the entire product. Terms can have multiple variants, and Pontoon makes it easy to add/remove them.

Terms
Terms

# Translated string
-brandShortName = { $case ->
    [nominative] Firefox Račun
   *[genitive] Firefox Računa
}

Selectors are a powerful feature of Fluent. They are used when there’s a need for multiple variants of the string based on an external variable. In the case case, PLATFORM().

Selectors
Selectors

platform = { PLATFORM() ->
    [win] Options
   *[other] Preferences
}

A common use case of selectors are plurals. When you translate a pluralized source string, Pontoon renders empty CLDR plural categories used in the target locale, each accompanied by an example number.

Plurals
Plurals

delete-all-message = { $num ->
    [one] Delete this download?
   *[other] Delete { $num } downloads?
}

Selectors can also be used in attributes. Pontoon hides most of the complexity.

Selectors in attributes
Selectors in attributes

download-choose-folder =
    .label = { PLATFORM() ->
        [macos] Choose…
       *[other] Browse…
    }
    .accesskey = { PLATFORM() ->
        [macos] e
       *[other] o
    }

If a value or an attribute contains multiple selectors, Pontoon indents them for better readability.

Strings with multiple selectors
Strings with multiple selectors

selector-multi = There { $num ->
    [one] is one email
   *[other] are many emails
} for { $gender ->
   *[masculine] him
    [feminine] her
}

Strings with nested selectors are not supported in Fluent editor, in which case Pontoon falls back to the source editor. The source editor is always available, and you can switch to it by clicking on the FTL button.

Unsupported strings
Unsupported strings

Next steps

The current state of the Fluent UI in Pontoon allows us to use Fluent to localize Firefox and various other projects. We don’t want to stop here, though. Instead, we’re looking to improve the Fluent experience further and make it the best among available localization formats. You can track the list of Fluent-related Pontoon bugs in Bugzilla. Some of the highlights include:

  • Ability to change default variant
  • Ability to add/remove variants
  • Ability to add selectors to simple messages
  • Making machinery usable with more complex strings
  • Prefilling complex message skeleton in source editor

No comments yet

Post a comment

Leave a Reply

Your email address will not be published. Required fields are marked *