cuqueclicker 1.2.0

A TUI idle clicker where you finger an ASCII ass instead of clicking a cookie.
Documentation
use std::env;
use std::sync::OnceLock;

pub struct Lang {
    pub hud_cuques: &'static str,
    pub hud_fps: &'static str,
    /// Short form of the FPS/DPS acronym (no trademark, no expansion).
    /// Used in inline strings like "+5% FPS" / "+5% DPS" where the long
    /// form would be too noisy.
    pub fps_unit: &'static str,
    pub help_game: &'static str,
    pub help_stats: &'static str,
    pub help_ach: &'static str,
    pub fingerers_title: &'static str,
    pub owned: &'static str,
    pub cost: &'static str,
    pub fps_each: &'static str,
    pub fingerer_names: &'static [&'static str],
    pub stats_title: &'static str,
    pub stat_session_time: &'static str,
    pub stat_total_time: &'static str,
    pub stat_total_clicks: &'static str,
    pub stat_lifetime_cuques: &'static str,
    pub stat_best_fps: &'static str,
    pub stat_achievements: &'static str,
    pub stat_fingerers_owned: &'static str,
    pub stat_golden_caught: &'static str,
    pub stat_lucky_caught: &'static str,
    pub stat_frenzy_caught: &'static str,
    pub stat_buff_caught: &'static str,
    pub stat_green_coin_caught: &'static str,
    pub achievements_title: &'static str,
    pub ach_unlocked: &'static str,
    pub ach_locked: &'static str,
    pub ach_summary: &'static str,
    pub achievement_names: &'static [&'static str],
    pub achievement_descs: &'static [&'static str],
    pub tree_title: &'static str,
    /// Help line shown at the bottom of the screen while the upgrade-tree
    /// modal is open.
    pub help_tree: &'static str,
    /// Localized rarity tags shown in the info pane next to the focused
    /// node's title (e.g. `[Small]` / `[Pequeno]`).
    pub tree_rarity_small: &'static str,
    pub tree_rarity_notable: &'static str,
    pub tree_rarity_keystone: &'static str,
    /// Connector words used by `primitive_blurb` to assemble effect
    /// descriptions. The math symbols + magnitude numbers are
    /// locale-neutral; only the connector ("to", "cost on", ...) and
    /// the target label flip per locale.
    pub tree_blurb_to: &'static str,
    pub tree_blurb_flat_to: &'static str,
    pub tree_blurb_cost_on: &'static str,
    pub tree_blurb_spawn_rate_for: &'static str,
    pub tree_blurb_effect_on: &'static str,
    /// Localized target labels.
    pub tree_target_all_fingerers: &'static str,
    pub tree_target_click: &'static str,
    pub tree_target_prestige: &'static str,
    pub tree_target_green_coin_strength: &'static str,
    /// Localized suffixes for powerup-targeted primitives. Format slot:
    /// `{}` → powerup name. Examples: "Lucky spawn" / "spawn de Lucky".
    pub tree_target_powerup_spawn_fmt: &'static str,
    pub tree_target_powerup_reward_fmt: &'static str,
    pub tree_target_powerup_duration_fmt: &'static str,
    /// Used by the info pane when a lot has no node ("empty lot at (x, y)").
    pub tree_empty_lot_fmt: &'static str,
    pub tree_empty_lot_hint: &'static str,
    /// Owned / unreachable / cost states in the info pane.
    pub tree_owned_tag: &'static str,
    pub tree_unreachable_hint: &'static str,
    pub tree_cost_label: &'static str,
    pub tree_cost_need_more_fmt: &'static str,
    pub tree_buy_button: &'static str,
    pub tree_refund_button: &'static str,
    pub tree_refund_returns_fmt: &'static str,
    /// Anchor (cuque-at-origin) info-pane copy.
    pub tree_anchor_tag: &'static str,
    pub tree_anchor_blurb: &'static str,
    pub tree_anchor_footer: &'static str,
    /// Refund-rejection reasons (origin / orphan).
    pub tree_refund_reason_origin: &'static str,
    pub tree_refund_reason_orphan: &'static str,
    /// Prefix label for the refund-rejected info-pane line. Format slot:
    /// `{}` → the reason text. e.g. "(no refund: {reason})".
    pub tree_no_refund_fmt: &'static str,
    pub prestige_title: &'static str,
    pub prestige_currency: &'static str,
    pub prestige_owned_label: &'static str,
    pub prestige_bonus_label: &'static str,
    pub prestige_available_label: &'static str,
    pub prestige_lifetime_needed: &'static str,
    pub prestige_confirm_hint: &'static str,
    pub prestige_confirm_question: &'static str,
    pub prestige_confirm_warning: &'static str,
    pub prestige_confirm_yes: &'static str,
    pub prestige_confirm_no: &'static str,
    pub prestige_not_enough: &'static str,
    pub help_prestige: &'static str,
}

pub const EN: Lang = Lang {
    hud_cuques: "Cuques",
    hud_fps: "FPS (Fingers per Second®)",
    fps_unit: "FPS",
    help_game: "[Space/Click] finger  [Click/1-0] buy  [Shift] x10  [Alt/RClick] max  [-/+/Wheel] zoom\n[t] tree  [p] prestige  [s] stats  [a] achievements  [g] grab golden/powerup  [q] quit",
    help_stats: "[s/Esc] back to game  [q] quit",
    help_ach: "[a/Esc] back to game  [q] quit",
    fingerers_title: " Fingerers ",
    owned: "owned",
    cost: "cost",
    fps_each: "FPS each",
    fingerer_names: &[
        "Index Finger",
        "Whole Hand",
        "Latex Glove",
        "Greek Kiss",
        "Robotic Finger",
        "Tentacle",
        "Finger Vortex",
        "Dimensional Hole",
        "Cosmic Finger",
        "Hand of God",
    ],
    stats_title: " Stats ",
    stat_session_time: "Session time",
    stat_total_time: "Total play time",
    stat_total_clicks: "Total fingerings",
    stat_lifetime_cuques: "Lifetime cuques",
    stat_best_fps: "Best FPS",
    stat_achievements: "Achievements",
    stat_fingerers_owned: "Fingerers owned",
    stat_golden_caught: "Powerups caught",
    stat_lucky_caught: "  ↳ Golden",
    stat_frenzy_caught: "  ↳ Frenzy",
    stat_buff_caught: "  ↳ Buff",
    stat_green_coin_caught: "  ↳ Green Coin",
    achievements_title: " Achievements ",
    ach_unlocked: "[X]",
    ach_locked: "[ ]",
    ach_summary: "unlocked",
    achievement_names: &[
        "First Finger",
        "Warming Up",
        "Seasoned Fingerer",
        "Cuque Mogul",
        "Automation",
        "Factory of Fingers",
        "Latex Enjoyer",
        "Golden Touch",
        "Golden Hoarder",
        "Rise of the Machines",
    ],
    achievement_descs: &[
        "Finger the cuque for the first time",
        "Accumulate 100 cuques",
        "Accumulate 10,000 cuques",
        "Accumulate 1,000,000 cuques",
        "Buy your first fingerer",
        "Own 10 Whole Hands",
        "Own 10 Latex Gloves",
        "Catch your first Golden Cuque",
        "Catch 10 Golden Cuques",
        "Own a Robotic Finger",
    ],
    tree_title: " Upgrade Tree ",
    help_tree: "[hjkl/arrows] pan  [LClick/drag] navigate  [Enter/RClick] buy  [r/RClick] refund  [0] root node  [1] last bought  [t/Esc] close  [q] quit",
    tree_rarity_small: "Small",
    tree_rarity_notable: "Notable",
    tree_rarity_keystone: "KEYSTONE",
    tree_blurb_to: "to",
    tree_blurb_flat_to: "flat to",
    tree_blurb_cost_on: "cost on",
    tree_blurb_spawn_rate_for: "spawn rate for",
    tree_blurb_effect_on: "effect on",
    tree_target_all_fingerers: "all fingerers",
    tree_target_click: "click power",
    tree_target_prestige: "prestige multiplier",
    tree_target_green_coin_strength: "Green Coin strength",
    tree_target_powerup_spawn_fmt: "{} spawn",
    tree_target_powerup_reward_fmt: "{} reward",
    tree_target_powerup_duration_fmt: "{} duration",
    tree_empty_lot_fmt: "(empty lot at {:+}, {:+})",
    tree_empty_lot_hint: "Pan with arrows / hjkl to find populated lots.",
    tree_owned_tag: "[owned]",
    tree_unreachable_hint: "unreachable — buy a connected neighbor first",
    tree_cost_label: "Cost: ",
    tree_cost_need_more_fmt: "(need {} more)",
    tree_buy_button: "[Click/Enter] to buy",
    tree_refund_button: "[Click/R] refund",
    tree_refund_returns_fmt: "(returns {}, loses {})",
    tree_anchor_tag: "[Root Node]",
    tree_anchor_blurb: "  - the twitching ass itself",
    tree_anchor_footer: "  every path of the tree branches outward from here.",
    tree_refund_reason_origin: "anchor — origin cannot be refunded",
    tree_refund_reason_orphan: "would orphan another owned node — refund a leaf first",
    tree_no_refund_fmt: "(no refund: {})",
    prestige_title: " Prestige ",
    prestige_currency: "Tissue Paper",
    prestige_owned_label: "Currently owned",
    prestige_bonus_label: "FPS bonus",
    prestige_available_label: "Available to claim",
    prestige_lifetime_needed: "Next papel at",
    prestige_confirm_hint: "Press [r] to reset and claim",
    prestige_confirm_question: "Are you SURE you want to reset?",
    // \n-split into chunks that EACH fit inside the bordered prestige
    // panel's inner width (~34 chars usable after the 2-space indent).
    // Pre-split is load-bearing: any chunk that's too wide would
    // soft-wrap into 2 visual rows, breaking the Vec-index ==
    // visual-row mapping the Y/N click rects depend on.
    prestige_confirm_warning: "Wipes ALL fingerers, tree, buffs.\nCannot be undone.",
    prestige_confirm_yes: "[Y/Enter] Yes, reset",
    prestige_confirm_no: "[N/Esc] No, cancel",
    prestige_not_enough: "Earn more lifetime cuques.\nFormula: sqrt(lifetime / 1M)",
    help_prestige: "[p/Esc] back  [q] quit",
};

pub const PT_BR: Lang = Lang {
    hud_cuques: "Cuques",
    hud_fps: "DPS (Dedadas por Segundo®)",
    fps_unit: "DPS",
    help_game: "[Espaço/Clique] dedar  [Clique/1-0] comprar  [Shift] x10  [Alt/Bot.Dir.] max  [-/+/Roda] zoom\n[t] árvore  [p] prestígio  [s] stats  [a] conquistas  [g] pegar dourado/bônus  [q] sair",
    help_stats: "[s/Esc] voltar ao jogo  [q] sair",
    help_ach: "[a/Esc] voltar ao jogo  [q] sair",
    fingerers_title: " Dedadores ",
    owned: "possui",
    cost: "custo",
    fps_each: "DPS cada",
    fingerer_names: &[
        "Dedo Indicador",
        "Mão Inteira",
        "Luva de Látex",
        "Beijo Grego",
        "Dedo Robótico",
        "Tentáculo",
        "Vórtice de Dedos",
        "Buraco Dimensional",
        "Dedo Cósmico",
        "Mão de Deus",
    ],
    stats_title: " Estatísticas ",
    stat_session_time: "Tempo de sessão",
    stat_total_time: "Tempo total de jogo",
    stat_total_clicks: "Total de dedadas",
    stat_lifetime_cuques: "Cuques na vida",
    stat_best_fps: "Melhor DPS",
    stat_achievements: "Conquistas",
    stat_fingerers_owned: "Dedadores possuídos",
    stat_golden_caught: "Powerups pegos",
    stat_lucky_caught: "  ↳ Dourado",
    stat_frenzy_caught: "  ↳ Frenzy",
    stat_buff_caught: "  ↳ Buff",
    stat_green_coin_caught: "  ↳ Moeda Verde",
    achievements_title: " Conquistas ",
    ach_unlocked: "[X]",
    ach_locked: "[ ]",
    ach_summary: "desbloqueadas",
    achievement_names: &[
        "Primeiro Dedo",
        "Esquentando",
        "Dedador Experiente",
        "Magnata do Cuque",
        "Automação",
        "Fábrica de Dedos",
        "Amante de Látex",
        "Toque Dourado",
        "Acumulador Dourado",
        "Ascensão das Máquinas",
    ],
    achievement_descs: &[
        "Dedar o cuque pela primeira vez",
        "Acumular 100 cuques",
        "Acumular 10.000 cuques",
        "Acumular 1.000.000 de cuques",
        "Comprar o primeiro dedador",
        "Possuir 10 Mãos Inteiras",
        "Possuir 10 Luvas de Látex",
        "Pegar o primeiro Cuque Dourado",
        "Pegar 10 Cuques Dourados",
        "Possuir um Dedo Robótico",
    ],
    tree_title: " Árvore de Upgrades ",
    help_tree: "[hjkl/setas] pan  [Clq/arrastar] navegar  [Enter/BD] comprar  [r/BD] reembolsar  [0] nó raiz  [1] última compra  [t/Esc] fechar  [q] sair",
    tree_rarity_small: "Pequeno",
    tree_rarity_notable: "Notável",
    tree_rarity_keystone: "PEDRA-ANGULAR",
    tree_blurb_to: "a",
    tree_blurb_flat_to: "fixo a",
    tree_blurb_cost_on: "no custo de",
    tree_blurb_spawn_rate_for: "na taxa de spawn de",
    tree_blurb_effect_on: "no efeito de",
    tree_target_all_fingerers: "todos os dedos",
    tree_target_click: "poder do clique",
    tree_target_prestige: "multiplicador de prestígio",
    tree_target_green_coin_strength: "força da Moeda Verde",
    tree_target_powerup_spawn_fmt: "spawn de {}",
    tree_target_powerup_reward_fmt: "recompensa de {}",
    tree_target_powerup_duration_fmt: "duração de {}",
    tree_empty_lot_fmt: "(lote vazio em {:+}, {:+})",
    tree_empty_lot_hint: "Mova com setas / hjkl para achar lotes populados.",
    tree_owned_tag: "[possuído]",
    tree_unreachable_hint: "inacessível — compre um vizinho conectado primeiro",
    tree_cost_label: "Custo: ",
    tree_cost_need_more_fmt: "(faltam {})",
    tree_buy_button: "[Clique/Enter] comprar",
    tree_refund_button: "[Clique/R] reembolsar",
    tree_refund_returns_fmt: "(retorna {}, perde {})",
    tree_anchor_tag: "[Nó Raiz]",
    tree_anchor_blurb: "  - o cu trêmulo em si",
    tree_anchor_footer: "  cada caminho da árvore se ramifica para fora daqui.",
    tree_refund_reason_origin: "âncora — a origem não pode ser reembolsada",
    tree_refund_reason_orphan: "deixaria outro nó possuído órfão — reembolse uma folha primeiro",
    tree_no_refund_fmt: "(sem reembolso: {})",
    prestige_title: " Prestígio ",
    prestige_currency: "Papel de Seda",
    prestige_owned_label: "Possui",
    prestige_bonus_label: "Bônus de DPS",
    prestige_available_label: "Disponível para resgatar",
    prestige_lifetime_needed: "Próximo papel em",
    prestige_confirm_hint: "Pressione [r] para resetar e resgatar",
    prestige_confirm_question: "Tem CERTEZA que quer resetar?",
    prestige_confirm_warning: "Apaga TODOS dedos, árvore, bônus.\nNão pode ser desfeito.",
    prestige_confirm_yes: "[Y/Enter] Sim, resetar",
    prestige_confirm_no: "[N/Esc] Não, cancelar",
    prestige_not_enough: "Acumule mais cuques totais.\nFórmula: raiz(total / 1M)",
    help_prestige: "[p/Esc] voltar  [q] sair",
};

static LANG: OnceLock<&'static Lang> = OnceLock::new();

pub fn init() {
    let _ = LANG.set(detect());
}

pub fn t() -> &'static Lang {
    LANG.get().copied().unwrap_or(&EN)
}

fn detect() -> &'static Lang {
    let raw = env::var("LANG").unwrap_or_default().to_lowercase();
    let code = raw.split('.').next().unwrap_or("");
    if code.starts_with("pt") { &PT_BR } else { &EN }
}