limitdeck 0.1.6

A privacy-safe terminal dashboard for AI subscription limits
use std::env;

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

impl Language {
    pub fn detect() -> Self {
        ["LC_ALL", "LC_MESSAGES", "LANG"]
            .into_iter()
            .find_map(|key| env::var(key).ok().filter(|value| !value.is_empty()))
            .map_or(Self::English, |value| Self::from_locale_name(&value))
    }

    pub const fn next(self) -> Self {
        match self {
            Self::English => Self::Chinese,
            Self::Chinese => Self::English,
        }
    }

    pub const fn label(self) -> &'static str {
        match self {
            Self::English => "EN",
            Self::Chinese => "中文",
        }
    }

    pub const fn copy(self) -> UiCopy {
        match self {
            Self::English => UiCopy {
                list_footer_prefix: "  ↑↓/jk Select · Enter Details · r Refresh · t ",
                detail_footer_prefix: "  Esc Back · r Refresh · t ",
                footer_language_separator: " · l ",
                footer_quit: " · q Quit",
                no_plans: "No coding plans found",
                no_plans_hint: "Sign in to Codex, configure Claude, or install OMP",
                quota: "Quota",
                reason: "Reason",
                action: "Action",
                history_collecting: "Collecting history",
                history_one_sample: "Collecting history · 1 sample",
                loading: "Loading",
                stale: "Cached",
                unavailable: "Unavailable · Enter for details",
            },
            Self::Chinese => UiCopy {
                list_footer_prefix: "  ↑↓/jk 选择 · Enter 详情 · r 刷新 · t ",
                detail_footer_prefix: "  Esc 返回 · r 刷新 · t ",
                footer_language_separator: " · l ",
                footer_quit: " · q 退出",
                no_plans: "未发现 Coding Plan",
                no_plans_hint: "登录 Codex、配置 Claude 状态行或安装 OMP",
                quota: "配额",
                reason: "原因",
                action: "处理",
                history_collecting: "历史收集中",
                history_one_sample: "历史收集中 · 1 个样本",
                loading: "加载中",
                stale: "缓存",
                unavailable: "不可用 · Enter 查看原因",
            },
        }
    }

    fn from_locale_name(value: &str) -> Self {
        if value.trim().to_ascii_lowercase().starts_with("zh") {
            Self::Chinese
        } else {
            Self::English
        }
    }
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct UiCopy {
    pub list_footer_prefix: &'static str,
    pub detail_footer_prefix: &'static str,
    pub footer_language_separator: &'static str,
    pub footer_quit: &'static str,
    pub no_plans: &'static str,
    pub no_plans_hint: &'static str,
    pub quota: &'static str,
    pub reason: &'static str,
    pub action: &'static str,
    pub history_collecting: &'static str,
    pub history_one_sample: &'static str,
    pub loading: &'static str,
    pub stale: &'static str,
    pub unavailable: &'static str,
}

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

    #[test]
    fn locale_names_select_chinese_only_for_zh_locales() {
        assert_eq!(Language::from_locale_name("zh_CN.UTF-8"), Language::Chinese);
        assert_eq!(Language::from_locale_name("zh-TW"), Language::Chinese);
        assert_eq!(Language::from_locale_name("en_US.UTF-8"), Language::English);
        assert_eq!(Language::from_locale_name("C"), Language::English);
    }

    #[test]
    fn language_cycle_wraps() {
        assert_eq!(Language::English.next(), Language::Chinese);
        assert_eq!(Language::Chinese.next(), Language::English);
    }
}