faststep 0.1.0

UIKit-inspired embedded UI framework built on embedded-graphics
Documentation
/// A localizable label with a stable lookup key and fallback text.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Localized<'a> {
    /// Stable localization key.
    pub key: &'a str,
    /// Fallback text used when no translation is available.
    pub fallback: &'a str,
}

impl<'a> Localized<'a> {
    /// Creates a new localized label.
    pub const fn new(key: &'a str, fallback: &'a str) -> Self {
        Self { key, fallback }
    }
}

/// One translated string in a locale table.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Translation<'a> {
    /// Stable localization key.
    pub key: &'a str,
    /// Resolved localized text.
    pub value: &'a str,
}

/// Translation table for one locale identifier.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct LocaleTable<'a> {
    /// Locale identifier, for example `"en"` or `"pl"`.
    pub id: &'a str,
    /// All translated entries for the locale.
    pub entries: &'a [Translation<'a>],
}

/// Small runtime localizer used by widgets and views.
#[derive(Clone, Copy, Debug)]
pub struct I18n<'a> {
    locale: &'a str,
    fallback_locale: &'a str,
    locales: &'a [LocaleTable<'a>],
}

impl<'a> I18n<'a> {
    /// Creates a new localization runtime.
    pub const fn new(
        locale: &'a str,
        fallback_locale: &'a str,
        locales: &'a [LocaleTable<'a>],
    ) -> Self {
        Self {
            locale,
            fallback_locale,
            locales,
        }
    }

    /// Returns the currently selected locale identifier.
    pub const fn locale(&self) -> &'a str {
        self.locale
    }

    /// Changes the active locale identifier.
    pub fn set_locale(&mut self, locale: &'a str) {
        self.locale = locale;
    }

    /// Resolves a [`Localized`] label into text.
    pub fn text(&self, label: Localized<'a>) -> &'a str {
        self.lookup(self.locale, label.key)
            .or_else(|| self.lookup(self.fallback_locale, label.key))
            .unwrap_or(label.fallback)
    }

    fn lookup(&self, locale: &str, key: &str) -> Option<&'a str> {
        let table = self.locales.iter().find(|table| table.id == locale)?;
        table
            .entries
            .iter()
            .find(|entry| entry.key == key)
            .map(|entry| entry.value)
    }
}