aurora-locale 0.1.0

Language detection and string localization
Documentation
use std::env;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Language {
    Russian,
    English,
}

impl Language {
    pub fn is_ru(self) -> bool { self == Language::Russian }
}

#[derive(Debug, Clone)]
pub struct Localizer {
    pub lang: Language,
}

impl Localizer {
    pub fn detect() -> Self {
        let lang = detect_locale();
        Self { lang }
    }

    pub fn from_override(s: &str) -> Self {
        let s = s.to_lowercase();
        let lang = if s == "ru" || s.starts_with("ru_") {
            Language::Russian
        } else {
            Language::English
        };
        Self { lang }
    }

    pub fn t<'a>(&self, ru: &'a str, en: &'a str) -> &'a str {
        match self.lang {
            Language::Russian => ru,
            Language::English => en,
        }
    }

    pub fn msg(&self, key: &str) -> String {
        messages(self.lang, key)
    }

    pub fn fmt(&self, ru: &str, en: &str, args: &[(&str, &str)]) -> String {
        let template = self.t(ru, en);
        let mut result = template.to_string();
        for (k, v) in args {
            result = result.replace(&format!("{{{k}}}"), v);
        }
        result
    }
}

fn detect_locale() -> Language {
    for var in &["LC_ALL", "LC_MESSAGES", "LANG"] {
        if let Ok(val) = env::var(var) {
            let val = val.to_lowercase();
            if val == "ru" || val.starts_with("ru_") {
                return Language::Russian;
            }
        }
    }
    Language::English
}

fn messages(lang: Language, key: &str) -> String {
    match lang {
        Language::Russian => ru_messages(key),
        Language::English => en_messages(key),
    }
}

fn ru_messages(key: &str) -> String {
    match key {
        "welcome" => "Добро пожаловать в Aurora!".to_string(),
        "goodbye" => "До свидания!".to_string(),
        "searching" => "Поиск...".to_string(),
        "found_files" => "Найдено файлов: {count}".to_string(),
        "indexing" => "Индексация...".to_string(),
        "index_updated" => "Индекс обновлён: {count} файлов".to_string(),
        "converting" => "Конвертация...".to_string(),
        "processing" => "Обработка...".to_string(),
        "error" => "Ошибка: {msg}".to_string(),
        "loading" => "Загрузка...".to_string(),
        "done" => "Готово!".to_string(),
        "elapsed" => "Прошло: {time}с".to_string(),
        "no_results" => "Ничего не найдено".to_string(),
        "joke_break" => "А пока — шутка:".to_string(),
        "thinking" => "Думаю...".to_string(),
        "cancel_hint" => "Нажми Ctrl+C для отмены".to_string(),
        "config_loaded" => "Конфиг загружен".to_string(),
        "session_resumed" => "Сессия восстановлена".to_string(),
        "debug_analyzing" => "Анализирую проблему...".to_string(),
        "debug_suggestion" => "Возможное решение: {suggestion}".to_string(),
        _ => key.to_string(),
    }
}

fn en_messages(key: &str) -> String {
    match key {
        "welcome" => "Welcome to Aurora!".to_string(),
        "goodbye" => "Goodbye!".to_string(),
        "searching" => "Searching...".to_string(),
        "found_files" => "Files found: {count}".to_string(),
        "indexing" => "Indexing...".to_string(),
        "index_updated" => "Index updated: {count} files".to_string(),
        "converting" => "Converting...".to_string(),
        "processing" => "Processing...".to_string(),
        "error" => "Error: {msg}".to_string(),
        "loading" => "Loading...".to_string(),
        "done" => "Done!".to_string(),
        "elapsed" => "Elapsed: {time}s".to_string(),
        "no_results" => "No results found".to_string(),
        "joke_break" => "Meanwhile, a joke:".to_string(),
        "thinking" => "Thinking...".to_string(),
        "cancel_hint" => "Press Ctrl+C to cancel".to_string(),
        "config_loaded" => "Config loaded".to_string(),
        "session_resumed" => "Session resumed".to_string(),
        "debug_analyzing" => "Analyzing the issue...".to_string(),
        "debug_suggestion" => "Possible fix: {suggestion}".to_string(),
        _ => key.to_string(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_detect_ru() {
        let loc = Localizer::from_override("ru_RU.UTF-8");
        assert_eq!(loc.lang, Language::Russian);
    }

    #[test]
    fn test_detect_en() {
        let loc = Localizer::from_override("en_US.UTF-8");
        assert_eq!(loc.lang, Language::English);
    }

    #[test]
    fn test_translate() {
        let ru = Localizer::from_override("ru_RU");
        let en = Localizer::from_override("en_US");
        assert_eq!(ru.t("Search", "Поиск"), "Поиск");
        assert_eq!(en.t("Search", "Поиск"), "Search");
    }
}