Crate fluent_fallback

source ·
Expand description

Fluent is a modern localization system designed to improve how software is translated.

fluent-fallback is a high-level component of the Fluent Localization System.

The crate builds on top of the mid-level fluent-bundle package, and provides an ergonomic API for highly flexible localization.

The functionality of this level is complete, but the API itself is in the early stages and the goal of being ergonomic is yet to be achieved.

If the user is willing to work through the challenge of setting up the boiler-plate that will eventually go away, fluent-fallback provides a powerful abstraction around FluentBundle coupled with a localization resource management system.

The main struct, Localization, is a long-lived, reactive, multi-lingual struct which allows for strong error recovery and locale fallbacking, exposing synchronous and asynchronous ergonomic methods for L10nMessage retrieval.

Localization is also an API that is to be used when designing bindings to user interface systems, such as DOM, React, and others.

Example

use fluent_fallback::{Localization, types::{ResourceType, ToResourceId}};
use fluent_resmgr::ResourceManager;
use unic_langid::langid;

let res_mgr = ResourceManager::new("./tests/resources/{locale}/".to_string());

let loc = Localization::with_env(
    vec![
        "test.ftl".into(),
        "test2.ftl".to_resource_id(ResourceType::Optional),
    ],
    true,
    vec![langid!("en-US")],
    res_mgr,
);
let bundles = loc.bundles();

let mut errors = vec![];
let value = bundles.format_value_sync("hello-world", None, &mut errors)
    .expect("Failed to format a value");

assert_eq!(value, Some("Hello World [en]".into()));

The above example is far from the ergonomical API style the Fluent project is aiming for, but it represents the full scope of functionality intended for the model.

Resource Management

Resource management is one of the most complicated parts of a localization system. In particular, modern software may have needs for both synchronous and asynchronous I/O. That, in turn has a large impact on what can happen in case of missing resources, or errors.

Resource identifiers can refer to resources that are either required or optional. In the above example, "test.ftl" is a required resource (the default using .into()), and "test2.ftl" is an optional resource, which you can create via the [ToResourceId`](fluent_fallback::types::ToResourceId) trait.

A required resource must be present in order for the a bundle to be considered valid. If a required resource is missing for a given locale, a bundle will not be generated for that locale.

A bundle is still considered valid if an optional resource is missing. A bundle will still be generated and the entries for the missing optional resource will simply be missing from the bundle. This should be used sparingly in exceptional cases where you do not want Localization to fall back to the next locale if there is a missing resource. Marking all resources as optional will increase the state space that the solver has to search through, and will have a negative impact on performance.

Currently, Localization can be specialized over an implementation of generator::BundleGenerator trait which provides a method to generate an Iterator and Stream.

This is not very elegant and will likely be improved in the future, but for the time being, if the customer doesn’t need one of the modes, the unnecessary method should use the unimplemented!() macro as its body.

fluent-resmgr provides a simple resource manager which handles synchronous I/O and uses local file system to store resources in a directory structure.

That model is often sufficient and the user can either use fluent-resmgr or write a similar API to provide the generator for Localization.

Alternatively, a much more sophisticated resource manager can be used. Mozilla for its needs in Firefox uses L10nRegistry library which implements BundleGenerator.

Locale Management

As a long lived structure, the Localization is intended to handle runtime locale management.

In the example above, Vec<LagnuageIdentifier> provides a static list of locales that the Localization handles, but that’s just the simplest implementation of the env::LocalesProvider, and one can implement a much more sophisticated one that reacts to user or environment driven changes, and called Localization::on_change to trigger a new locales to be used for the next translation request.

See env::LocalesProvider trait for an example of a reactive system implementation.

Modules

Traits required to provide environment driven data for Localization.

Structs

Enums