Expand description
§es-fluent-manager-bevy
Seamless Bevy integration for es-fluent.
This plugin connects es-fluent’s type-safe localization with Bevy’s ECS and Asset system. It allows you to use standard #[derive(EsFluent)] types as components that automatically update when the app/game’s language changes.
es-fluent-manager-bevy | bevy |
|---|---|
| crates.io | |
0.18.x | 0.18.x |
0.17.x | 0.17.x |
§Features
- Asset Loading: Loads
.ftlfiles via Bevy’sAssetServer. - Hot Reloading: Supports hot-reloading of translations during development.
- Reactive UI: The
FluentTextcomponent automatically refreshes text when the locale changes. - Global Hook Ownership: Can either let Bevy own
es-fluent’s process-global localization bridge or fail fast when another integration already installed one.
§Quick Start
§1. Define the Module
In your crate root (lib.rs or main.rs), tell the manager to scan your assets:
// a i18n.toml file must exist in the root of the crate
es_fluent_manager_bevy::define_i18n_module!();§2. Initialize & Use
Add the plugin to your App and define your I18n module:
use bevy::prelude::*;
use es_fluent_manager_bevy::I18nPlugin;
use unic_langid::langid;
// a i18n.toml file must exist in the root of the crate
es_fluent_manager_bevy::define_i18n_module!();
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(I18nPlugin::with_language(langid!("en-US")))
.run();
}I18nPlugin still installs the bridge that makes #[derive(EsFluent)] work
inside Bevy, but it now defaults to
GlobalLocalizerMode::ErrorIfAlreadySet. That keeps startup fail-fast if
another integration already owns the process-global localization bridge.
If your Bevy app intentionally owns that hook and should override any previous registration, opt in explicitly:
use es_fluent_manager_bevy::{GlobalLocalizerMode, I18nPlugin};
App::new().add_plugins(
I18nPlugin::with_language(langid!("en-US"))
.with_global_localizer_mode(GlobalLocalizerMode::ReplaceExisting),
);Plugin startup always uses strict module discovery, so invalid or duplicate registrations fail the app boot instead of being normalized silently. Failed hot reloads or locale switches keep the last accepted locale active instead of publishing a broken update.
Use RequestedLanguageId to read the latest user intent and ActiveLanguageId
to read the currently published locale. LocaleChangedEvent refers to
ActiveLanguageId, not merely the latest request.
§3. Define Localizable Components (Recommended)
Prefer the BevyFluentText derive macro. It auto-registers your type with
I18nPlugin via inventory, so you don’t have to call any registration
functions manually.
If a field depends on the active locale (like the Languages enum from
es_fluent_lang), mark it with #[locale].
The macro will generate RefreshForLocale and register the locale-aware
systems for you. #[locale] is supported on named struct fields and named
enum variant fields, and you can mark more than one named field in the same
variant when they all need refresh behavior.
RefreshForLocale receives the originally requested locale, not the fallback
resource locale. For example, if en-GB falls back to en assets, locale-aware
fields still refresh with en-GB.
use bevy::prelude::Component;
use es_fluent::EsFluent;
use es_fluent_manager_bevy::BevyFluentText;
#[derive(BevyFluentText, Clone, Component, EsFluent)]
pub enum UiMessage {
StartGame,
Settings,
LanguageHint {
#[locale]
current_language: Languages,
},
}§4. Using in UI
Use the FluentText component wrapper for any type that implements ToFluentString
(which #[derive(EsFluent)] provides).
use es_fluent_manager_bevy::FluentText;
fn spawn_menu(mut commands: Commands) {
commands.spawn((
// This text will automatically update if language changes
FluentText::new(UiMessage::StartGame),
Text::new(""),
));
}§Manual Registration (Fallback)
If you cannot derive BevyFluentText (e.g., external types), you can still
register manually:
app.register_fluent_text::<UiMessage>();If the type needs locale refresh, implement RefreshForLocale and use the
locale-aware registration function:
use es_fluent_manager_bevy::RefreshForLocale;
#[derive(EsFluent, Clone, Component)]
pub enum UiMessage {
LanguageHint { current_language: Languages },
}
impl RefreshForLocale for UiMessage {
fn refresh_for_locale(&mut self, lang: &unic_langid::LanguageIdentifier) {
match self {
UiMessage::LanguageHint { current_language } => {
if let Ok(value) = Languages::try_from(lang) {
*current_language = value;
}
}
}
}
}
app.register_fluent_text_from_locale::<UiMessage>();§Do Nested Types Need BevyFluentText?
Only the component type wrapped by FluentText<T> needs registration.
If a nested field (like KbKeys) is only used inside a registered component,
it does not need BevyFluentText. When the parent component re-renders,
its EsFluent implementation formats all fields using the current locale.
You only need BevyFluentText for a nested type if you plan to use it directly
as FluentText<ThatType> or otherwise register it as its own component.
Re-exports§
pub use bevy;pub use inventory;pub use unic_langid;pub use components::*;pub use plugin::*;pub use systems::*;
Modules§
Macros§
- define_
i18n_ module - Defines a Bevy i18n module.
Structs§
- Active
Language Id - A Bevy resource that holds the currently published active
LanguageIdentifier. - EsFluent
Bevy Plugin - A plugin that initializes the
es-fluentBevy integration. - FtlAsset
- A Bevy asset representing a Fluent Translation List (
.ftl) file. - FtlAsset
Loader - An
AssetLoaderfor loading.ftlfiles asFtlAssets. - I18n
Assets - A Bevy resource that manages the loading of
FtlAssets. - I18n
Bundle - A Bevy resource containing per-locale Fluent bundles plus accepted resources used for locale fallback lookups.
- I18n
Resource - The main resource for handling localization.
- Locale
Change Event - A Bevy
Messagesent to request a change of the requested locale. - Locale
Changed Event - A Bevy
Messagesent after the active locale has been successfully published. - Requested
Language Id - A Bevy resource that holds the most recently requested
LanguageIdentifier.
Traits§
- Bevy
Fluent Text Registration - Trait for auto-registering FluentText systems with Bevy.
- Fluent
Display - This trait is similar to
std::fmt::Display, but it is used for formatting types that can be displayed in a Fluent message. - Fluent
Text Registration - An extension trait for
Appto simplify the registration ofFluentTextcomponents. - From
Locale - A trait for types that can be constructed from a
LanguageIdentifier. - Refresh
ForLocale - A trait for types that can be updated in place when the locale changes.
- ToFluent
String - This trait is automatically implemented for any type that implements
FluentDisplay.
Functions§
- primary_
language - Returns the primary language subtag from a
LanguageIdentifier. - update_
values_ on_ locale_ change - A Bevy system that listens for
LocaleChangedEvents and updates components that implementRefreshForLocale.
Derive Macros§
- Bevy
Fluent Text - Registers a type for use with
FluentText<T>in Bevy.