🔒 Repository is read-only – file editing is disabled.

PaganDE/pagan-toolkit/src/i18n.rs main

134 linii Raw ← Powrót
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
//! Minimalna, zależnościowo „lekka" lokalizacja PL/EN.
//!
//! Świadomie NIE używamy `fluent`, `gettext` ani plików `.po`: dla toolkitu
//! wystarczy statyczna tablica napisów. Dzięki temu:
//!
//! * zero dodatkowych zależności i zero kodu generowanego w czasie budowy,
//! * `tr()` jest w pełni `const`-owalne (zwraca `&'static str`),
//! * rozbudowa to dopisanie jednego wariantu w [`MsgKey`] i trzech napisów w [`tr`].
//!
//! Język wybieramy ze zmiennej środowiskowej `PAGAN_LANG` (`pl` / `en`).

/// Obsługiwane języki interfejsu.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Locale {
    /// Polski.
    Pl,
    /// Angielski (domyślny, bezpieczny fallback).
    En,
}

impl Default for Locale {
    fn default() -> Self {
        Locale::En
    }
}

/// Klucze komunikatów UI. Dodawanie nowych napisów zaczyna się tutaj.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MsgKey {
    /// Tytuł okna demo.
    WindowTitle,
    /// Etykieta przycisku „Menu".
    Menu,
    /// Pozycja paska menu: plik.
    MenuFile,
    /// Pozycja paska menu: edycja.
    MenuEdit,
    /// Pozycja paska menu: widok.
    MenuView,
    /// Pozycja paska menu: pomoc.
    MenuHelp,
    /// Etykieta/tooltip przycisku zamykania.
    Close,
    /// Etykieta/tooltip przycisku minimalizacji.
    Minimize,
    /// Etykieta/tooltip przycisku maksymalizacji.
    Maximize,
    /// Etykieta/tooltip przywrócenia rozmiaru.
    Restore,
    /// Log: zamykanie okna.
    LogClosing,
    /// Log: rozpoczęto przeciąganie okna.
    LogDrag,
    /// Log: rozpoczęto zmianę rozmiaru za krawędź/róg.
    LogResize,
    /// Log: otwarto/zamknięto menu.
    LogMenu,
    /// Log: zakończono pętlę zdarzeń.
    LogExit,
    /// Log: zmieniono stan maksymalizacji.
    LogMaximize,
}

/// Zwraca przetłumaczony napis dla pary `(język, klucz)`.
///
/// Funkcja jest czysta (brak stanu, brak alokacji) i zwraca `&'static str`,
/// więc można ją wywoływać bez obaw w każdym miejscu, także w kodzie rysującym.
pub fn tr(locale: Locale, key: MsgKey) -> &'static str {
    match locale {
        Locale::Pl => match key {
            MsgKey::WindowTitle => "Pagan Toolkit — okno demo",
            MsgKey::Menu => "Menu",
            MsgKey::MenuFile => "Plik",
            MsgKey::MenuEdit => "Edycja",
            MsgKey::MenuView => "Widok",
            MsgKey::MenuHelp => "Pomoc",
            MsgKey::Close => "Zamknij",
            MsgKey::Minimize => "Minimalizuj",
            MsgKey::Maximize => "Maksymalizuj",
            MsgKey::Restore => "Przywróć",
            MsgKey::LogClosing => "Zamykanie okna na życzenie użytkownika.",
            MsgKey::LogDrag => "Rozpoczęto przeciąganie okna (xdg_toplevel.move).",
            MsgKey::LogResize => "Rozpoczęto zmianę rozmiaru okna (xdg_toplevel.resize).",
            MsgKey::LogMenu => "Naciśnięto przycisk menu.",
            MsgKey::LogExit => "Pętla zdarzeń zakończona. Do zobaczenia!",
            MsgKey::LogMaximize => "Zmieniono stan maksymalizacji okna.",
        },
        Locale::En => match key {
            MsgKey::WindowTitle => "Pagan Toolkit — demo window",
            MsgKey::Menu => "Menu",
            MsgKey::MenuFile => "File",
            MsgKey::MenuEdit => "Edit",
            MsgKey::MenuView => "View",
            MsgKey::MenuHelp => "Help",
            MsgKey::Close => "Close",
            MsgKey::Minimize => "Minimize",
            MsgKey::Maximize => "Maximize",
            MsgKey::Restore => "Restore",
            MsgKey::LogClosing => "Closing the window at user request.",
            MsgKey::LogDrag => "Started interactive move (xdg_toplevel.move).",
            MsgKey::LogResize => "Started interactive resize (xdg_toplevel.resize).",
            MsgKey::LogMenu => "Menu button pressed.",
            MsgKey::LogExit => "Event loop finished. Goodbye!",
            MsgKey::LogMaximize => "Toggled window maximize state.",
        },
    }
}

impl From<&str> for Locale {
    /// Mapuje dowolny string (np. z `PAGAN_LANG`) na język. Nieznane wartości →
    /// [`Locale::En`], żeby aplikacja nigdy nie wyświetlała pustych napisów.
    fn from(value: &str) -> Self {
        let normalized = value.trim().to_ascii_lowercase();
        match normalized.as_str() {
            "pl" | "pol" | "polski" | "pl_pl" | "pl-pl" => Locale::Pl,
            _ => Locale::En,
        }
    }
}

impl From<String> for Locale {
    fn from(value: String) -> Self {
        Locale::from(value.as_str())
    }
}

impl Locale {
    /// Odczytuje język ze zmiennej środowiskowej `PAGAN_LANG`.
    pub fn from_env() -> Self {
        std::env::var("PAGAN_LANG")
            .map(|value| Locale::from(value.as_str()))
            .unwrap_or_default()
    }
}