fluent_fallback/lib.rs
1//! Fluent is a modern localization system designed to improve how software is translated.
2//!
3//! `fluent-fallback` is a high-level component of the [Fluent Localization
4//! System](https://www.projectfluent.org).
5//!
6//! The crate builds on top of the mid-level [`fluent-bundle`](../fluent-bundle) package, and provides an ergonomic API for highly flexible localization.
7//!
8//! The functionality of this level is complete, but the API itself is in the
9//! early stages and the goal of being ergonomic is yet to be achieved.
10//!
11//! If the user is willing to work through the challenge of setting up the
12//! boiler-plate that will eventually go away, `fluent-fallback` provides
13//! a powerful abstraction around [`FluentBundle`](fluent_bundle::FluentBundle) coupled
14//! with a localization resource management system.
15//!
16//! The main struct, [`Localization`], is a long-lived, reactive, multi-lingual
17//! struct which allows for strong error recovery and locale
18//! fallbacking, exposing synchronous and asynchronous ergonomic methods
19//! for [`L10nMessage`](types::L10nMessage) retrieval.
20//!
21//! [`Localization`] is also an API that is to be used when designing bindings
22//! to user interface systems, such as DOM, React, and others.
23//!
24//! # Example
25//!
26//! ```
27//! use fluent_fallback::{Localization, types::{ResourceType, ToResourceId}};
28//! use fluent_resmgr::ResourceManager;
29//! use unic_langid::langid;
30//!
31//! let res_mgr = ResourceManager::new("./tests/resources/{locale}/".to_string());
32//!
33//! let loc = Localization::with_env(
34//! vec![
35//! "test.ftl".into(),
36//! "test2.ftl".to_resource_id(ResourceType::Optional),
37//! ],
38//! true,
39//! vec![langid!("en-US")],
40//! res_mgr,
41//! );
42//! let bundles = loc.bundles();
43//!
44//! let mut errors = vec![];
45//! let value = bundles.format_value_sync("hello-world", None, &mut errors)
46//! .expect("Failed to format a value");
47//!
48//! assert_eq!(value, Some("Hello World [en]".into()));
49//! ```
50//!
51//! The above example is far from the ergonomic API style the Fluent project
52//! is aiming for, but it represents the full scope of functionality intended
53//! for the model.
54//!
55//! # Resource Management
56//!
57//! Resource management is one of the most complicated parts of a localization system.
58//! In particular, modern software may have needs for both synchronous
59//! and asynchronous I/O. That, in turn has a large impact on what can happen
60//! in case of missing resources, or errors.
61//!
62//! Resource identifiers can refer to resources that are either required or optional.
63//! In the above example, `"test.ftl"` is a required resource (the default using `.into()`),
64//! and `"test2.ftl"` is an optional resource, which you can create via the
65//! [`ToResourceId`](types::ToResourceId) trait.
66//!
67//! A required resource must be present in order for the a bundle to be considered valid.
68//! If a required resource is missing for a given locale, a bundle will not be generated for that locale.
69//!
70//! A bundle is still considered valid if an optional resource is missing. A bundle will still be generated
71//! and the entries for the missing optional resource will simply be missing from the bundle. This should be
72//! used sparingly in exceptional cases where you do not want `Localization` to fall back to the next
73//! locale if there is a missing resource. Marking all resources as optional will increase the state space
74//! that the solver has to search through, and will have a negative impact on performance.
75//!
76//! Currently, [`Localization`] can be specialized over an implementation of
77//! [`generator::BundleGenerator`] trait which provides a method to generate an
78//! [`Iterator`] and [`Stream`](futures::stream::Stream).
79//!
80//! This is not very elegant and will likely be improved in the future, but for the time being, if
81//! the customer doesn't need one of the modes, the unnecessary method should use the
82//! `unimplemented!()` macro as its body.
83//!
84//! `fluent-resmgr` provides a simple resource manager which handles synchronous I/O
85//! and uses local file system to store resources in a directory structure.
86//!
87//! That model is often sufficient and the user can either use `fluent-resmgr` or write
88//! a similar API to provide the generator for [`Localization`].
89//!
90//! Alternatively, a much more sophisticated resource manager can be used. Mozilla
91//! for its needs in Firefox uses [`L10nRegistry`](https://github.com/zbraniecki/l10nregistry-rs)
92//! library which implements [`BundleGenerator`](generator::BundleGenerator).
93//!
94//! # Locale Management
95//!
96//! As a long lived structure, the [`Localization`] is intended to handle runtime locale
97//! management.
98//!
99//! In the example above, [`Vec<LanguageIdentifier>`](unic_langid::LanguageIdentifier)
100//! provides a static list of locales that the [`Localization`] handles, but that's just the
101//! simplest implementation of the [`env::LocalesProvider`], and one can implement
102//! a much more sophisticated one that reacts to user or environment driven changes, and
103//! called [`Localization::on_change`] to trigger a new locales to be used for the
104//! next translation request.
105//!
106//! See [`env::LocalesProvider`] trait for an example of a reactive system implementation.
107mod bundles;
108mod cache;
109pub mod env;
110mod errors;
111pub mod generator;
112mod localization;
113pub mod types;
114
115pub use bundles::Bundles;
116pub use errors::LocalizationError;
117pub use localization::Localization;