Project Fluent: Localization and Pluralization in Firefox

This article explores how Mozilla’s Project Fluent revolutionizes software localization in the Firefox Web Browser. It examines the limitations of traditional translation systems and details how Fluent utilizes asymmetric localization, selectors, and isolated grammar logic to handle complex natural language rules, including intricate pluralization and gender agreement, across dozens of global languages.

Asymmetric Localization

Traditional localization systems rely on a one-to-one mapping between the source language (usually English) and the target language. This forces developers to hardcode English grammar rules into the software, breaking translations for languages with more complex structures.

Project Fluent solves this in Firefox through "asymmetric localization." The complexity of one language does not restrict or complicate another. A developer can write a simple string in English, and a localizer can expand that single string into multiple complex variants in their native language without needing the developer to change the underlying Firefox source code.

Solving Complex Pluralization with Selectors

Pluralization is one of the hardest challenges in localization. While English only has two plural categories (singular and plural), other languages have many more. For example, Polish and Russian have four categories, and Arabic has six.

Fluent handles this natively by integrating Unicode CLDR (Common Locale Data Repository) plural rules and utilizing a syntax feature called "selectors." Selectors work like switch statements in programming.

In Firefox, an English .ftl (Fluent Translation List) file might handle closing tabs like this:

tabs-close-warning = { $tabCount ->
    [one] You are about to close { $tabCount } tab.
   *[other] You are about to close { $tabCount } tabs.
}

For the exact same interface element, the Polish localizer can add the necessary grammatical categories without altering Firefox’s code:

tabs-close-warning = { $tabCount ->
    [one] Zamkniesz { $tabCount } kartę.
    [few] Zamkniesz { $tabCount } karty.
    [many] Zamkniesz { $tabCount } kart.
   *[other] Zamkniesz { $tabCount } karty.
}

The asterisk (*) denotes the default fallback value if no other conditions are met. You can even match exact numbers (like [0] or [1]) to create more natural-sounding phrases, such as "You are about to close no tabs" instead of "0 tabs."

Terms, Attributes, and Grammatical Cases

Natural language complexity extends beyond plurals to include grammatical gender, animacy, and case declensions. In many languages, verbs and adjectives must change depending on the gender of the noun they reference, or a brand name must change its ending based on its role in a sentence.

Fluent addresses this using "Terms" (denoted with a hyphen, like -brand-name) and custom attributes. Localizers can attach metadata to a term and use that metadata in selectors.

-brand-name = Firefox
    .gender = masculine

update-successful = { -brand-name.gender ->
    [masculine] { -brand-name } a été mis à jour.
    [feminine] { -brand-name } a été mise à jour.
   *[other] { -brand-name } a été mis(e) à jour.
}

If Mozilla ever rebrands a product or uses a different term (like "Firefox Nightly" vs. "Aurora"), the localizer only needs to change the .gender attribute in one place. Every sentence referencing that term in the browser will automatically adjust its grammar to match.

Decoupling Code from Grammar

In the Firefox codebase, Project Fluent creates a strict separation of concerns between engineers and translators.

To display a localized message, a Firefox engineer only needs to reference the message ID (e.g., tabs-close-warning) and pass the raw data variables (e.g., { tabCount: 5 }). The Fluent engine inside Firefox evaluates the variables, applies the target language's specific logic from the .ftl file, and outputs the correct string to the browser's user interface. This ensures that Firefox reads naturally in every supported language while keeping the browser's source code clean and maintainable.