fluent.js

repository·main·Indexed 21 days ago

https://github.com/projectfluent/fluent.js

A JavaScript implementation of the Project Fluent localization framework for handling complex natural language requirements like plurals and gender. The project includes several packages: @fluent/bundle for formatting translations, @fluent/dom for DOM-based translation, @fluent/react for React integration, @fluent/langneg for language negotiation, @fluent/syntax for parsing FTL, @fluent/dedent for template literal dedenting, and @fluent/sequence for bundle sequences.

Tokens
20.7K
Snippets
82
Records
107
Agent score
75%

What's inside fluent.js

  1. Overview of Project Fluent

    main
    Fluent.js is a JavaScript implementation of Project Fluent, a localization framework. It is designed to handle both simple translations and complex natural language concepts such as gender, plurals, and conjugations using the FTL (Fluent Translation List) syntax.
  2. Understand likely subtags in @fluent/langneg

    main

    The module includes a minimal list of "likely subtags" data. This allows the negotiation algorithm to find more specific available locales even when a requested locale is too generic.

    For example, if a user requests the generic en locale, but your application only supports en-GB and en-US, the likely subtags data helps the negotiator bridge that gap to find a suitable match.

  3. How DOMLocalization works for DOM-based translation

    main

    The DOMLocalization class is designed for full-fallback ready message formatting within the DOM. It works by identifying localizable elements via the data-l10n-id attribute.

    Key workflow:

    1. Initialize DOMLocalization with a list of FTL resource paths and a generateBundles generator function.
    2. Call connectRoot(root) to specify the starting point in the DOM.
    3. Call translateRoots() to perform the initial translation of the DOM tree.
    4. Use setAttributes(element, id, args) to update specific elements. This method sets data-l10n-id and data-l10n-args on the element, which triggers an internal MutationObserver to automatically translate the element.
    import { DOMLocalization } from "@fluent/dom";
    
    const l10n = new DOMLocalization(
      ["/browser/main.ftl", "/toolkit/menu.ftl"],
      generateBundles
    );
    
    l10n.connectRoot(document.documentElement);
    l10n.translateRoots();
    
    const h1 = document.querySelector("h1");
    
    // Sets `data-l10n-id` and `data-l10n-args` which triggers
    // the `MutationObserver` from `DOMLocalization` and translates the
    // element.
    l10n.setAttributes(h1, "welcome", { user: "Anna" });
  4. Configure language negotiation strategies

    main

    The negotiateLanguages API supports three different strategies via the strategy option. Choose the one that best fits your application's requirements for how many locales should be returned:

    1. filtering (default): Tries to match as many available locales as possible for each requested locale.
      • Example: If requested ['de-DE', 'fr-FR'] and available ['de', 'fr'], it returns ['de', 'fr'].
    2. matching: Looks for the single best matching available locale for each requested locale.
      • Example: If requested ['de-DE', 'fr-FR'] and available ['de', 'fr'], it returns ['de', 'fr'] (but focuses on the best match per request).
    3. lookup: Tries to find the single best locale for the entire requested locale list among the available locales.
      • Example: If requested ['de-DE', 'fr-FR'] and available ['de-DE', 'fr'], it returns only the single best match, e.g., ['de-DE'].
    let supported = negotiateLanguages(requested, available, {
      strategy: "matching",
    });
  5. How to use fluent-gecko for mozilla-central vendoring

    main

    If you are working with mozilla-central, fluent-gecko can build the specific files required for integration. The distribution provides:

    • FluentSyntax.jsm: Located in intl/l10n/ within mozilla-central.
    • fluent-react.js: Located in devtools/client/shared/vendor/ within mozilla-central.
  6. Run performance tests with test.js

    main

    Use the test.js script to measure the performance impact of changes to the fluent.js codebase. The script measures the speed of parsing, compilation, and entity retrieval using a resource file containing approximately 500 entities (imitating a real-world scenario like Firefox OS's settings localization). Execution time is reported in milliseconds (ms).

    To ensure reliable measurements and avoid JIT (Just-In-Time) compilation bias, the script spawns the target command via child_process.exec for a large sample of runs. If no command is provided, it is automatically determined based on the selected --engine.

    # Run with default settings
    ./test.js
    
    # Run using a specific engine (node, jsshell, or d8)
    ./test.js --engine jsshell
    
    # Run with a large sample size and show progress
    ./test.js --sample 1000 --progress
    
    # Run a specific custom command
    ./test.js "~/src/jsshell/js benchmark.jsshell.js"
  7. Set up a local development environment for fluent.js

    main

    To contribute to or build fluent.js locally, follow these steps:

    1. Prerequisites: Ensure you have Node.js 20.19 or newer installed. Older versions are not supported.
    2. Clone the repository:
      git clone https://github.com/projectfluent/fluent.js.git
      cd fluent.js
    3. Install dependencies: Use npm workspaces to install dependencies for all packages:
      npm install
    4. Build and test all packages: Run the following command to clean, build, lint, test, and generate documentation for all workspaces:
      npm run dist

    Alternatively, you can build a specific package by navigating to its directory and running:

    npm run build
    git clone https://github.com/projectfluent/fluent.js.git
    cd fluent.js
    npm install
    npm run dist
  8. Use @fluent/bundle to format translations

    main

    To format translations, use the FluentBundle constructor to create a bundle for a specific locale, add a FluentResource containing FTL (Fluent Translation Language) content, and then use getMessage and formatPattern to resolve messages with provided arguments.

    import { FluentBundle, FluentResource } from "@fluent/bundle";
    
    // 1. Define your FTL resource
    let resource = new FluentResource(`
    -brand-name = Foo 3000
    welcome = Welcome, {$name}, to {-brand-name}!
    `);
    
    // 2. Create a bundle for a specific locale
    let bundle = new FluentBundle("en-US");
    
    // 3. Add the resource and check for syntax errors
    let errors = bundle.addResource(resource);
    if (errors.length) {
      // Handle syntax errors (errors are per-message)
    }
    
    // 4. Retrieve and format a message
    let welcome = bundle.getMessage("welcome");
    if (welcome.value) {
      let result = bundle.formatPattern(welcome.value, { name: "Anna" });
      // result → "Welcome, Anna, to Foo 3000!"
    }
  9. Install Fluent.js packages

    main

    Fluent.js is modular. You can install specific packages via npm depending on your use case. Common packages include:

    • @fluent/bundle: Core bundling functionality.
    • @fluent/dedent: String dedenting utility.
    • @fluent/dom: DOM-related utilities.
    • @fluent/langneg: Language negotiation.
    • @fluent/react: React integration.
    • @fluent/sequence: Sequence handling.
    • @fluent/syntax: Syntax parsing and handling.

    To install a package, use npm install <package-name>.

    npm install @fluent/react