Expand description
Generate typed Rust translation APIs from modular Fluent catalogs.
This reference documents the 0.2.0 runtime-loading API. See the setup guide for installation, and the migration guide when upgrading from 0.1.4.
Language directories are discovered automatically. FTL file paths become named Rust types, and message parameters become typed accessor arguments.
Built on fluent-typed, which generates the typed message accessors and provides Fluent formatting. This crate adds module discovery and a typed translation tree around that foundation. Applications choose their own resource loading, active language and presentation layer.
§Feature selection
build(default): discovery, schema validation, source generation and theExtensionAPI for custom integrations. Enable in build-dependencies.manifest: optional TOML parsing and file-manifest factory.- No default features:
translations!and std-only source contracts, with no dependencies. Use this configuration in normal dependencies. The generated code still requires the application’sfluent-typedandfluent-syntaxdependencies.
Cargo resolver 2/3 keeps the build and normal feature contexts separate. See the dependency setup for the build and runtime dependency declarations.
§Configure the consuming package
[package.metadata.localization]
asset-root = "assets"
catalog = "localizations/localization.toml"The asset root is relative to the Cargo package. The configuration path is relative to that root. Its filename is configurable; the TOML contains:
translations-directory = "translations"
source-language = "en"
default-language = "en"translations-directory is optional and relative to this TOML. Omit it to use
locale folders beside the file (default .). The legacy languages-directory
alias is accepted, but specifying both names is an error.
With the explicit path above, put matching FTL modules under
assets/localizations/translations/en/, es/
and any other locale directories. The source language defines message keys,
references and argument annotations. default-language is emitted as
DEFAULT_LANGUAGE metadata for application startup; Locale::default()
identifies the source language. Each language must provide the same contract.
§Generate and use the API
Return fluent_typed_codegen::build() from the consuming build.rs to run
validation and generation. Errors produce readable diagnostics and a failing
exit code. cargo check also regenerates for IDE indexing; no application
execution is needed. Source files are never rewritten.
For a file ui/menu.ftl containing title = Settings, the generated type is
texts::ui::Menu. A directory becomes a namespace/group, a file becomes a
leaf type, and each Fluent message has a typed accessor:
fluent_typed_codegen::translations!(pub mod texts);
let manifest = texts::embed_manifest!();
let translations = texts::Translations::from_manifest(texts::Locale::En, &manifest)?;
let ui: &texts::Ui = translations.ui();
let menu: &texts::ui::Menu = ui.menu();
println!("{}", menu.msg_title());This snippet needs consumer-owned FTL and build output; the runnable Rust example demonstrates the complete setup. There is no public module at a leaf path. Message keys in different files stay independent, including their argument types.
§Output and checked loading
Cargo entrypoints emit Rust, per-module FTL and source metadata into OUT_DIR.
Keep that output under target/ and out of source control. generate also
accepts an explicit tool-owned output directory for custom build frontends.
Failed generation can leave partial output; always propagate build errors.
Generated leaves expose checked new(locale, bytes), safe new_unchecked,
and standalone validate. Translations::from_modules validates and parses
caller-supplied FTL strings before
returning a snapshot. Compatible prose edits can be loaded without rebuilding;
changes to the schema or language/module inventory require regeneration.
These runtime methods perform no filesystem reads. File loading and replacing
snapshots are caller-controlled, not a filesystem watcher.
Sources can come from decoded archive entries or any application-owned buffers;
module keys remain paths below the locale directory, not storage URLs. The
returned snapshot retains no input borrows. Read a coherent revision before
parsing and replace application state only after validation succeeds. Archive
I/O and pack installation remain application choices; there is no implicit fallback.
Generated from_manifest constructors read files through a
LocalizationManifest contract, while
texts::embed_manifest!() explicitly includes a build-prepared raw source set.
Without that macro invocation, generated APIs contain no FTL payload.
The embedded macro is crate-local; module = texts::ui::Menu selects one leaf,
and module = texts::Ui includes the group’s descendants, in every language.
Use a generated type path or a use alias, not a type alias or generic parameter.
Unselected FTL is not included even in unoptimized builds without LTO or stripping.
See the complete loading recipes
for bytes, files, embedding, all languages and explicit module lifetimes.
§Numbers, plural selection and presentation
Native Fluent numeric selectors remain available; this generator does not
replace upstream argument types or select-expression behavior. For numbers,
percentages, currencies and dates, it’s recommended to use dedicated
ICU or
ICU4X formatters. Formatting policies and component
stability belong to the application.
For decimal text, use DecimalFormatter.
If grammar must follow visible precision, pass the same prepared Decimal to
PluralRules.
Annotate the displayed text and category keyword as (String) in source FTL.
The runnable example
uses ICU directly; no special generated numeric type, generator dependency or
feature is required. Respect ICU’s operand limits for arbitrary-precision input.
A compact ICU walkthrough
shows reusable formatters and a numeric input. Catalogs and formatters can be
kept in application state; the application decides when to recompute strings
and how to use the result.
String categories match literal Fluent keys such as [one]; unmatched strings
select the starred default. Numeric exact matches such as [1] still require
a numeric selector. Keep number formatting aligned with the snapshot’s locale.
Number formatting and Fluent interpolation isolation do not implement RTL
layout, glyph shaping or fonts; those belong to the application’s renderer.
§Custom integrations
With build, Extension adds an entrypoint decorated with typed Rust syntax,
while preserving the plain generated API. It can add attributes, imports or
application-specific registration code. See the
extension guide
for its syntax hooks and consumer-compilation requirements.
Repository links follow main; this API reference describes the viewed version.
Re-exports§
pub use syn;
Macros§
- translations
- Declare a module containing this package’s generated Fluent translations.
Structs§
- Catalog
Config - Contents of
localization.toml, separate from Cargo’s asset-path settings. - Localization
Manifest - A source contract for readable FTL; creating one never parses FTL.
- Scope
- A generated type and its path of accessor calls from the root snapshot.
- Settings
- Portable paths locating a consuming package’s assets and catalog configuration.
Enums§
- Manifest
Error - A manifest or requested module could not be obtained.
Traits§
- Extension
- Syntax-level extension for a consuming framework’s generated entrypoint.
Functions§
- build
- Generate catalogs from a Cargo build script with readable failure output.
- build_
with - As
build, with an opt-in framework source extension. - from_
cargo - Generate using the consuming package’s Cargo.toml metadata and Cargo OUT_DIR.
- from_
cargo_ with - As
from_cargo, also emitting the extension’s entrypoint. - generate
- Generate from explicit paths, for custom build frontends and tests.
- generate_
with - As
generate, with an additional framework entrypoint.