Expand description
§cloudiful-bevy-localization
Reusable Bevy localization runtime for apps that generate their own static locale registry at build time.
§What it provides
LocalizationDefinition: static description of fallback locale, supported locales, locale sources, and declared keysLocaleSource: one TOML payload bound to a locale + namespaceLocale: runtime locale handle with serialization supportTextKey: runtime text key handle with serialization supportLocalization: Bevy resource for lookup, formatting, locale switching, and table accessLocalizationPlugin: registers a definition and inserts theLocalizationresourceLocalizationLoadError: structured load/validation failureregister_definition(...): definition registry hook used by the plugin and helper typeslocale_name_key_id(...): helper forcommon.locale_name.<locale>key generation
§What it does not provide
- scanning downstream
assets/i18n - generating app-specific key constants
- embedding downstream
OUT_DIRartifacts inside the crate - editor tooling, extraction, or translation workflows
This crate expects the downstream app to generate or hand-author a static registry and then pass that definition into the plugin.
§Usage
Generate a static registry in the downstream app and pass it into the plugin.
LocalizationPlugin::new(...) registers the definition first and then inserts
the Localization resource built from that definition.
use bevy::prelude::*;
use cloudiful_bevy_localization::{
Locale, LocaleSource, Localization, LocalizationDefinition,
LocalizationPlugin, TextKey,
};
const KEYS: &[TextKey] = &[TextKey::new("common.hello")];
const SOURCES: &[LocaleSource] = &[
LocaleSource {
locale: "en-US",
namespace: "common",
contents: r#"
hello = "Hello"
[locale_name]
en_us = "English"
zh_cn = "Chinese"
"#,
},
LocaleSource {
locale: "zh-CN",
namespace: "common",
contents: r#"
hello = "你好"
[locale_name]
en_us = "英语"
zh_cn = "中文"
"#,
},
];
static LOCALIZATION: LocalizationDefinition = LocalizationDefinition {
fallback_locale: "en-US",
locales: &["en-US", "zh-CN"],
sources: SOURCES,
keys: KEYS,
};
fn main() {
App::new()
.add_plugins(LocalizationPlugin::new(&LOCALIZATION))
.add_systems(Update, read_text);
}
fn read_text(localization: Res<Localization>) {
assert_eq!(localization.current_locale(), Locale::new("en-US"));
assert_eq!(localization.text(TextKey::new("common.hello")), "Hello");
}At runtime, use the resource for lookup, formatting, locale switching, and locale display text:
use bevy::prelude::*;
use cloudiful_bevy_localization::{Locale, Localization, TextKey};
fn ui_text(mut localization: ResMut<Localization>) {
let text = localization.text(TextKey::new("common.hello")).to_string();
let formatted = localization.format_text(TextKey::new("common.hello"), []);
localization.set_locale(Locale::new("zh-CN"));
let current = localization.current_locale();
let available = localization.available_locales();
let display = localization.locale_display_text(current);
println!("{text} / {formatted} / {display} / {available:?}");
}§Validation Rules
Definitions are validated at load time. A load fails when any of these rules are broken:
- the fallback locale table is missing
- a listed locale has no table
- a declared
TextKeyis missing from any locale - a
common.locale_name.<locale>entry is missing for any supported locale - a locale table contains keys that are not declared
- placeholder names differ from the fallback locale for the same key
- a locale source references a locale not listed in
LocalizationDefinition - a TOML value is not a string or nested table
- the same flattened key appears more than once
LocaleSource.contents TOML is flattened by namespace, so:
[nested]
label = "Nested"under namespace common becomes common.nested.label.
§Runtime Behavior
Localization::text(...)looks up the current locale first, then the fallback locale, and panics only if both are missingLocalization::format_text(...)performs simple{name}replacement on the selected textLocalization::lookup(...)andlookup_id(...)returnOption<&str>without panickingLocalization::table(...)returns the flattened table for one localeLocalization::locale_display_text(...)looks upcommon.locale_name.<locale>in the current locale, then fallback locale, and finally returns the raw locale id
§Locale and Key Helpers
Locale::new(...)andTextKey::new(...)create static handlesLocale::available()reads available locales from the active registered definitionLocale::from_serialized(...)normalizes case and punctuation when matching serialized locale idsTextKey::from_id(...)resolves an id against the active registered definition
Structs§
- Locale
- Runtime locale handle used by
Localization. - Locale
Source - Static locale sources and definitions supplied by the downstream app.
- Localization
- Main localization resource and plugin.
- Localization
Definition - Static locale sources and definitions supplied by the downstream app.
- Localization
Plugin - Main localization resource and plugin.
- TextKey
- Runtime text-key handle used by
Localization.
Enums§
- Localization
Load Error - Error returned when loading or validating a
LocalizationDefinition.
Functions§
- locale_
name_ key_ id - Returns the generated key id for a locale display name entry.
- register_
definition - Registers the active
LocalizationDefinitionfor helper lookups.