Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Namespaces & File Splitting

By default, all your FTL keys land in a single {crate}.ftl file per locale. As a project grows, this gets unwieldy. Namespaces let you route specific types into separate .ftl files. Every derive macro (EsFluent, EsFluentLabel, EsFluentVariants) supports the same namespace attribute.

Output Layout

DeclarationFile path
No namespaceassets_dir/{locale}/{crate}.ftl
With namespaceassets_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.

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_label(origin)]
#[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/user/profile.rs
#[derive(EsFluentLabel)]
#[fluent_label(origin)]
#[fluent(namespace(folder(relative)))]
pub struct FolderUserProfile;

A type in src/user/profile.rs maps to namespace user.

Quick Reference

SyntaxExample source fileResulting namespace
namespace = "name"anyname
namespace = filesrc/ui/button.rsbutton
namespace(file(relative))src/ui/button.rsui/button
namespace = foldersrc/ui/button.rsui
namespace(folder(relative))src/ui/button.rsui

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.