Namespaces and file splitting
Namespaces route selected types into separate .ftl files instead of the
default {crate}.ftl resource. EsFluent, EsFluentLabel, and
EsFluentVariants support the same namespace modes.
Use exactly one namespace source for each generated output. When multiple
derives are combined on one type, either inherit a shared namespace from
#[fluent(namespace = ...)] or set one on the specific
#[fluent_label(...)] / #[fluent_variants(...)] output, but do not combine
those namespace sources.
Output layout
| Declaration | File path |
|---|---|
| No namespace | assets_dir/{locale}/{crate}.ftl |
| With namespace | assets_dir/{locale}/{crate}/{namespace}.ftl |
When namespaces are enabled through the manager macros, the configured
namespace files are the canonical per-locale resources.
{crate}.ftl remains an optional mixed-mode resource for non-namespaced
messages when it exists.
Namespace modes
Explicit string
namespace = "name" sets an explicit string namespace. Literal namespaces
must be safe locale-relative paths: no empty segments, ./.., backslashes,
absolute paths, surrounding whitespace, or .ftl suffix.
use es_fluent::EsFluent;
#[derive(EsFluent)]
#[fluent(namespace = "ui")]
pub struct Button<'a>(pub &'a str);
This writes the key to assets_dir/{locale}/{crate}/ui.ftl.
File stem
namespace = file uses the source file’s stem as the namespace.
use es_fluent::EsFluent;
// In src/components/dialog.rs
#[derive(EsFluent)]
#[fluent(namespace = file)]
pub struct Dialog {
pub title: String,
}
A type in src/components/dialog.rs maps to namespace dialog.
File relative
namespace = file_relative uses the file path relative to the crate root, strips src/, and removes the extension.
use es_fluent::EsFluent;
// In src/ui/button.rs
#[derive(EsFluent)]
#[fluent(namespace = file_relative)]
pub enum Gender {
Male,
Female,
Other(String),
}
A type in src/ui/button.rs maps to namespace ui/button.
Folder
namespace = folder uses the source file’s parent folder.
use es_fluent::EsFluentLabel;
// In src/user/profile.rs
#[derive(EsFluentLabel)]
#[fluent(namespace = folder)]
pub enum FolderStatus {
Active,
Inactive,
}
A type in src/user/profile.rs maps to namespace user.
Folder relative
namespace = folder_relative uses the parent folder path relative to the crate root, stripping src/ when nested and keeping src for root module files.
use es_fluent::EsFluentLabel;
// In src/screens/user/profile.rs
#[derive(EsFluentLabel)]
#[fluent(namespace = folder_relative)]
pub struct FolderUserProfile;
A type in src/screens/user/profile.rs maps to namespace screens/user. With
namespace = folder, the same file would map only to user.
Quick reference
| Syntax | Example source file | Resulting namespace |
|---|---|---|
namespace = "name" | any | name |
namespace = file | src/ui/button.rs | button |
namespace = file_relative | src/ui/button.rs | ui/button |
namespace = folder | src/screens/ui/button.rs | ui |
namespace = folder_relative | src/screens/ui/button.rs | screens/ui |
Validation
Literal string namespaces are validated at compile time as safe relative namespace paths. If namespaces = [...] is set in your i18n.toml, both the compiler and the CLI validate that explicit string-based namespaces used by your code match the provided allowlist. File-based and folder-based namespaces bypass allowlist validation because they’re derived automatically from the source tree.