Skip to main content

Crate cloudiful_bevy_localization

Crate cloudiful_bevy_localization 

Source
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 keys
  • LocaleSource: one TOML payload bound to a locale + namespace
  • Locale: runtime locale handle with serialization support
  • TextKey: runtime text key handle with serialization support
  • Localization: Bevy resource for lookup, formatting, locale switching, and table access
  • LocalizationPlugin: registers a definition and inserts the Localization resource
  • LocalizationLoadError: structured load/validation failure
  • register_definition(...): definition registry hook used by the plugin and helper types
  • locale_name_key_id(...): helper for common.locale_name.<locale> key generation

§What it does not provide

  • scanning downstream assets/i18n
  • generating app-specific key constants
  • embedding downstream OUT_DIR artifacts 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 TextKey is 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 missing
  • Localization::format_text(...) performs simple {name} replacement on the selected text
  • Localization::lookup(...) and lookup_id(...) return Option<&str> without panicking
  • Localization::table(...) returns the flattened table for one locale
  • Localization::locale_display_text(...) looks up common.locale_name.<locale> in the current locale, then fallback locale, and finally returns the raw locale id

§Locale and Key Helpers

  • Locale::new(...) and TextKey::new(...) create static handles
  • Locale::available() reads available locales from the active registered definition
  • Locale::from_serialized(...) normalizes case and punctuation when matching serialized locale ids
  • TextKey::from_id(...) resolves an id against the active registered definition

Structs§

Locale
Runtime locale handle used by Localization.
LocaleSource
Static locale sources and definitions supplied by the downstream app.
Localization
Main localization resource and plugin.
LocalizationDefinition
Static locale sources and definitions supplied by the downstream app.
LocalizationPlugin
Main localization resource and plugin.
TextKey
Runtime text-key handle used by Localization.

Enums§

LocalizationLoadError
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 LocalizationDefinition for helper lookups.