Overview of i18n-config
masteri18n-config library provides the core configuration structs and parsing functions used by the cargo-i18n tool and system. It serves as the shared configuration schema for the entire cargo-i18n ecosystem.repository·master·Indexed 40 days ago
https://github.com/kellpossible/cargo-i18nA Cargo sub-command and ecosystem of tools for extracting and building localization resources to embed in Rust applications and libraries. It includes i18n-build for build script integration, i18n-config for shared configuration schemas, and i18n-embed for runtime localization. The ecosystem supports the Fluent and gettext localization systems, providing features like compile-time checked localization via the fl! macro in i18n-embed-fl and platform-specific language detection for desktop and WASM contexts.
i18n-config library provides the core configuration structs and parsing functions used by the cargo-i18n tool and system. It serves as the shared configuration schema for the entire cargo-i18n ecosystem.i18n-build crate is a library designed for use within the cargo-i18n tool to facilitate crate localization. While primarily used by the cargo-i18n CLI, it is published independently so that developers can call its functionality directly within their own project build scripts (build.rs) if they need custom localization build logic.When using Fluent, your localization files must be organized by language and domain. The language identifiers must conform to the Unicode Language Identifier standard.
Example structure:
my_crate/
Cargo.toml
i18n.toml
src/
i18n/
{language}/
{domain}.ftlTo embed Fluent localization into your application, follow these steps:
i18n-embed with fluent-system and a requester feature (e.g., desktop-requester) to your Cargo.toml.i18n.toml file in your crate root.#[derive(RustEmbed)] pointing to your assets directory.fluent_language_loader!() macro to instantiate the loader.i18n_embed::select to resolve the requested languages against your embedded localizations.use i18n_embed::{DesktopLanguageRequester, fluent::{
FluentLanguageLoader, fluent_language_loader
}};
use rust_embed::RustEmbed;
#[derive(RustEmbed)]
#[folder = "i18n"] // path to the compiled localization resources
struct Localizations;
fn main() {
// Create the loader using the macro which pulls config from i18n.toml
let language_loader: FluentLanguageLoader = fluent_language_loader!();
// Resolve the system's requested languages
let requested_languages = DesktopLanguageRequester::requested_languages();
// Select the appropriate localizations
let _result = i18n_embed::select(
&language_loader, &Localizations, &requested_languages);
// continue on with your application
}To use i18n-embed-fl for compile-time checked Fluent localization, you must configure an i18n.toml file in your crate root and organize your Fluent files in a specific directory structure.
i18n.tomlCreate an i18n.toml file in your crate root with the following required keys:
fallback_language: The language identifier used as the primary fallback (e.g., "en-GB").[fluent] assets_dir: The path to your localization assets.Your assets directory must follow this structure:
assets_dir/{language}/{domain}.ftl
Note: The {domain} should be the Rust path of your crate, using underscores (_) instead of hyphens (-).
Use fluent_language_loader! to initialize the loader and the fl! macro from i18n-embed-fl to retrieve messages with compile-time validation of both the message ID and the arguments.
# i18n.toml
fallback_language = "en-GB"
[fluent]
assets_dir = "i18n"use i18n_embed::{
fluent::{fluent_language_loader, FluentLanguageLoader},
LanguageLoader,
};
use i18n_embed_fl::fl;
use rust_embed::RustEmbed;
#[derive(RustEmbed)]
#[folder = "i18n/"]
struct Localizations;
let loader: FluentLanguageLoader = fluent_language_loader!();
loader
.load_languages(&Localizations, &[loader.fallback_language().clone()])
.unwrap();
// The fl! macro performs compile-time checks for the ID and arguments
assert_eq!(
"Hello \u{2068}Bob 23\u{2069}!",
fl!(loader, "hello-arg", name = format!("Bob {}", 23))
)Hot-reloading is achieved through the subscribe_changed method on the I18nAssets trait.
std::sync::Arc) to subscribe_changed. This closure is executed whenever a change is detected.Box<dyn Watcher>. You must keep this object in scope. When the Watcher is dropped, the file system subscription is automatically cancelled.FileSystemAssets supports this if the autoreload feature is enabled and notify_changes_enabled(true) was called.RustEmbedNotifyAssets supports this if the autoreload feature is enabled.AssetsMultiplexor propagates the subscription to all its children.The i18n-embed crate provides optional features to support different localization systems and platform-specific language detection:
fluent-system: Enables support for the Fluent localization system via the FluentLanguageLoader.gettext-system: Enables support for the gettext localization system using the tr macro and the gettext crate via the GettextLanguageLoader.desktop-requester: Provides DesktopLanguageRequester for desktop platforms (Windows, macOS, Linux) using the sys-locale crate to resolve the system locale.web-sys-requester: Provides WebLanguageRequester for WASM contexts using the web-sys crate to resolve the browser's language.The LanguageRequester trait is used by I18nAssets to determine which languages are currently being requested by the system or environment. It allows you to register Localizer instances as listeners that will automatically update via their select() method whenever the requested languages change.
Key capabilities include:
add_listener (for Weak<dyn Localizer>, which are automatically removed when the underlying Arc is dropped) or add_listener_ref (for &'a dyn Localizer, which are permanent).poll() method checks the current system/environment language and notifies all registered listeners.set_language_override to force a specific unic_langid::LanguageIdentifier regardless of the system settings.requested_languages(), available_languages(), and current_languages() to see what the system wants, what is available, and what is currently loaded across different domains.By default, i18n-build is focused on the build process. If you need to enable runtime localization using the localize() function via the i18n-embed crate, you must enable the localize Cargo feature in your Cargo.toml.
[dependencies]
i18n-build = { version = "0.2.13", features = ["localize"] }To use the Fluent localization system, create an i18n.toml file in your crate root. This file is used by cargo-i18n and the fluent_language_loader!() macro to configure the localization environment at compile time.
Required keys:
fallback_language: The Unicode language identifier used as the primary fallback (all strings must be present in this language).[fluent].assets_dir: The path to your localization assets. The directory structure must follow the pattern: assets_dir/{language}/{domain}.ftl.# (Required) The primary fallback language
fallback_language = "en-GB"
[fluent]
# (Required) The path to the assets directory
assets_dir = "i18n"When configuring Gettext in i18n.toml, you can optionally specify custom directories for .pot, .po, and .mo files. If these are not explicitly provided, the following defaults are used relative to your output_dir:
[output_dir]/pot[output_dir]/po[output_dir]/moFor web-based applications, use WebLanguageRequester. It retrieves the requested languages from the browser's navigator.languages API.
Note: This requires the web-sys-requester crate feature to be enabled.
Similar to the desktop version, you register listeners and call poll() to update your localizers based on the browser's language settings.
use i18n_embed::LanguageRequester;
use i18n_embed::WebLanguageRequester;
use std::sync::Arc;
let mut requester = WebLanguageRequester::new();
requester.add_listener(Arc::downgrade(&localizer));
// Sync with browser locale
requester.poll().unwrap();