Skip to main content

cuqueclicker_lib/
i18n.rs

1use std::env;
2use std::sync::OnceLock;
3
4pub struct Lang {
5    pub hud_cuques: &'static str,
6    pub hud_fps: &'static str,
7    /// Short form of the FPS/DPS acronym (no trademark, no expansion).
8    /// Used in inline strings like "+5% FPS" / "+5% DPS" where the long
9    /// form would be too noisy.
10    pub fps_unit: &'static str,
11    pub help_game: &'static str,
12    pub help_stats: &'static str,
13    pub help_ach: &'static str,
14    pub fingerers_title: &'static str,
15    pub owned: &'static str,
16    pub cost: &'static str,
17    pub fps_each: &'static str,
18    pub fingerer_names: &'static [&'static str],
19    pub stats_title: &'static str,
20    pub stat_session_time: &'static str,
21    pub stat_total_time: &'static str,
22    pub stat_total_clicks: &'static str,
23    pub stat_lifetime_cuques: &'static str,
24    pub stat_best_fps: &'static str,
25    pub stat_achievements: &'static str,
26    pub stat_fingerers_owned: &'static str,
27    pub stat_golden_caught: &'static str,
28    pub stat_lucky_caught: &'static str,
29    pub stat_frenzy_caught: &'static str,
30    pub stat_buff_caught: &'static str,
31    pub stat_green_coin_caught: &'static str,
32    pub achievements_title: &'static str,
33    pub ach_unlocked: &'static str,
34    pub ach_locked: &'static str,
35    pub ach_summary: &'static str,
36    pub achievement_names: &'static [&'static str],
37    pub achievement_descs: &'static [&'static str],
38    pub tree_title: &'static str,
39    /// Help line shown at the bottom of the screen while the upgrade-tree
40    /// modal is open.
41    pub help_tree: &'static str,
42    /// Localized rarity tags shown in the info pane next to the focused
43    /// node's title (e.g. `[Small]` / `[Pequeno]`).
44    pub tree_rarity_small: &'static str,
45    pub tree_rarity_notable: &'static str,
46    pub tree_rarity_keystone: &'static str,
47    /// Connector words used by `primitive_blurb` to assemble effect
48    /// descriptions. The math symbols + magnitude numbers are
49    /// locale-neutral; only the connector ("to", "cost on", ...) and
50    /// the target label flip per locale.
51    pub tree_blurb_to: &'static str,
52    pub tree_blurb_flat_to: &'static str,
53    pub tree_blurb_cost_on: &'static str,
54    pub tree_blurb_spawn_rate_for: &'static str,
55    pub tree_blurb_effect_on: &'static str,
56    /// Localized target labels.
57    pub tree_target_all_fingerers: &'static str,
58    pub tree_target_click: &'static str,
59    pub tree_target_prestige: &'static str,
60    pub tree_target_green_coin_strength: &'static str,
61    /// Localized suffixes for powerup-targeted primitives. Format slot:
62    /// `{}` → powerup name. Examples: "Lucky spawn" / "spawn de Lucky".
63    pub tree_target_powerup_spawn_fmt: &'static str,
64    pub tree_target_powerup_reward_fmt: &'static str,
65    pub tree_target_powerup_duration_fmt: &'static str,
66    /// Used by the info pane when a lot has no node ("empty lot at (x, y)").
67    pub tree_empty_lot_fmt: &'static str,
68    pub tree_empty_lot_hint: &'static str,
69    /// Owned / unreachable / cost states in the info pane.
70    pub tree_owned_tag: &'static str,
71    pub tree_unreachable_hint: &'static str,
72    pub tree_cost_label: &'static str,
73    pub tree_cost_need_more_fmt: &'static str,
74    pub tree_buy_button: &'static str,
75    pub tree_refund_button: &'static str,
76    pub tree_refund_returns_fmt: &'static str,
77    /// Anchor (cuque-at-origin) info-pane copy.
78    pub tree_anchor_tag: &'static str,
79    pub tree_anchor_blurb: &'static str,
80    pub tree_anchor_footer: &'static str,
81    /// Refund-rejection reasons (origin / orphan).
82    pub tree_refund_reason_origin: &'static str,
83    pub tree_refund_reason_orphan: &'static str,
84    /// Prefix label for the refund-rejected info-pane line. Format slot:
85    /// `{}` → the reason text. e.g. "(no refund: {reason})".
86    pub tree_no_refund_fmt: &'static str,
87    pub prestige_title: &'static str,
88    pub prestige_currency: &'static str,
89    pub prestige_owned_label: &'static str,
90    pub prestige_bonus_label: &'static str,
91    pub prestige_available_label: &'static str,
92    pub prestige_lifetime_needed: &'static str,
93    pub prestige_confirm_hint: &'static str,
94    pub prestige_confirm_question: &'static str,
95    pub prestige_confirm_warning: &'static str,
96    pub prestige_confirm_yes: &'static str,
97    pub prestige_confirm_no: &'static str,
98    pub prestige_not_enough: &'static str,
99    pub help_prestige: &'static str,
100}
101
102pub const EN: Lang = Lang {
103    hud_cuques: "Cuques",
104    hud_fps: "FPS (Fingers per Second®)",
105    fps_unit: "FPS",
106    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",
107    help_stats: "[s/Esc] back to game  [q] quit",
108    help_ach: "[a/Esc] back to game  [q] quit",
109    fingerers_title: " Fingerers ",
110    owned: "owned",
111    cost: "cost",
112    fps_each: "FPS each",
113    fingerer_names: &[
114        "Index Finger",
115        "Whole Hand",
116        "Latex Glove",
117        "Greek Kiss",
118        "Robotic Finger",
119        "Tentacle",
120        "Finger Vortex",
121        "Dimensional Hole",
122        "Cosmic Finger",
123        "Hand of God",
124    ],
125    stats_title: " Stats ",
126    stat_session_time: "Session time",
127    stat_total_time: "Total play time",
128    stat_total_clicks: "Total fingerings",
129    stat_lifetime_cuques: "Lifetime cuques",
130    stat_best_fps: "Best FPS",
131    stat_achievements: "Achievements",
132    stat_fingerers_owned: "Fingerers owned",
133    stat_golden_caught: "Powerups caught",
134    stat_lucky_caught: "  ↳ Golden",
135    stat_frenzy_caught: "  ↳ Frenzy",
136    stat_buff_caught: "  ↳ Buff",
137    stat_green_coin_caught: "  ↳ Green Coin",
138    achievements_title: " Achievements ",
139    ach_unlocked: "[X]",
140    ach_locked: "[ ]",
141    ach_summary: "unlocked",
142    achievement_names: &[
143        "First Finger",
144        "Warming Up",
145        "Seasoned Fingerer",
146        "Cuque Mogul",
147        "Automation",
148        "Factory of Fingers",
149        "Latex Enjoyer",
150        "Golden Touch",
151        "Golden Hoarder",
152        "Rise of the Machines",
153    ],
154    achievement_descs: &[
155        "Finger the cuque for the first time",
156        "Accumulate 100 cuques",
157        "Accumulate 10,000 cuques",
158        "Accumulate 1,000,000 cuques",
159        "Buy your first fingerer",
160        "Own 10 Whole Hands",
161        "Own 10 Latex Gloves",
162        "Catch your first Golden Cuque",
163        "Catch 10 Golden Cuques",
164        "Own a Robotic Finger",
165    ],
166    tree_title: " Upgrade Tree ",
167    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",
168    tree_rarity_small: "Small",
169    tree_rarity_notable: "Notable",
170    tree_rarity_keystone: "KEYSTONE",
171    tree_blurb_to: "to",
172    tree_blurb_flat_to: "flat to",
173    tree_blurb_cost_on: "cost on",
174    tree_blurb_spawn_rate_for: "spawn rate for",
175    tree_blurb_effect_on: "effect on",
176    tree_target_all_fingerers: "all fingerers",
177    tree_target_click: "click power",
178    tree_target_prestige: "prestige multiplier",
179    tree_target_green_coin_strength: "Green Coin strength",
180    tree_target_powerup_spawn_fmt: "{} spawn",
181    tree_target_powerup_reward_fmt: "{} reward",
182    tree_target_powerup_duration_fmt: "{} duration",
183    tree_empty_lot_fmt: "(empty lot at {:+}, {:+})",
184    tree_empty_lot_hint: "Pan with arrows / hjkl to find populated lots.",
185    tree_owned_tag: "[owned]",
186    tree_unreachable_hint: "unreachable — buy a connected neighbor first",
187    tree_cost_label: "Cost: ",
188    tree_cost_need_more_fmt: "(need {} more)",
189    tree_buy_button: "[Click/Enter] to buy",
190    tree_refund_button: "[Click/R] refund",
191    tree_refund_returns_fmt: "(returns {}, loses {})",
192    tree_anchor_tag: "[Root Node]",
193    tree_anchor_blurb: "  - the twitching ass itself",
194    tree_anchor_footer: "  every path of the tree branches outward from here.",
195    tree_refund_reason_origin: "anchor — origin cannot be refunded",
196    tree_refund_reason_orphan: "would orphan another owned node — refund a leaf first",
197    tree_no_refund_fmt: "(no refund: {})",
198    prestige_title: " Prestige ",
199    prestige_currency: "Tissue Paper",
200    prestige_owned_label: "Currently owned",
201    prestige_bonus_label: "FPS bonus",
202    prestige_available_label: "Available to claim",
203    prestige_lifetime_needed: "Next papel at",
204    prestige_confirm_hint: "Press [r] to reset and claim",
205    prestige_confirm_question: "Are you SURE you want to reset?",
206    // \n-split into chunks that EACH fit inside the bordered prestige
207    // panel's inner width (~34 chars usable after the 2-space indent).
208    // Pre-split is load-bearing: any chunk that's too wide would
209    // soft-wrap into 2 visual rows, breaking the Vec-index ==
210    // visual-row mapping the Y/N click rects depend on.
211    prestige_confirm_warning: "Wipes ALL fingerers, tree, buffs.\nCannot be undone.",
212    prestige_confirm_yes: "[Y/Enter] Yes, reset",
213    prestige_confirm_no: "[N/Esc] No, cancel",
214    prestige_not_enough: "Earn more lifetime cuques.\nFormula: sqrt(lifetime / 1M)",
215    help_prestige: "[p/Esc] back  [q] quit",
216};
217
218pub const PT_BR: Lang = Lang {
219    hud_cuques: "Cuques",
220    hud_fps: "DPS (Dedadas por Segundo®)",
221    fps_unit: "DPS",
222    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",
223    help_stats: "[s/Esc] voltar ao jogo  [q] sair",
224    help_ach: "[a/Esc] voltar ao jogo  [q] sair",
225    fingerers_title: " Dedadores ",
226    owned: "possui",
227    cost: "custo",
228    fps_each: "DPS cada",
229    fingerer_names: &[
230        "Dedo Indicador",
231        "Mão Inteira",
232        "Luva de Látex",
233        "Beijo Grego",
234        "Dedo Robótico",
235        "Tentáculo",
236        "Vórtice de Dedos",
237        "Buraco Dimensional",
238        "Dedo Cósmico",
239        "Mão de Deus",
240    ],
241    stats_title: " Estatísticas ",
242    stat_session_time: "Tempo de sessão",
243    stat_total_time: "Tempo total de jogo",
244    stat_total_clicks: "Total de dedadas",
245    stat_lifetime_cuques: "Cuques na vida",
246    stat_best_fps: "Melhor DPS",
247    stat_achievements: "Conquistas",
248    stat_fingerers_owned: "Dedadores possuídos",
249    stat_golden_caught: "Powerups pegos",
250    stat_lucky_caught: "  ↳ Dourado",
251    stat_frenzy_caught: "  ↳ Frenzy",
252    stat_buff_caught: "  ↳ Buff",
253    stat_green_coin_caught: "  ↳ Moeda Verde",
254    achievements_title: " Conquistas ",
255    ach_unlocked: "[X]",
256    ach_locked: "[ ]",
257    ach_summary: "desbloqueadas",
258    achievement_names: &[
259        "Primeiro Dedo",
260        "Esquentando",
261        "Dedador Experiente",
262        "Magnata do Cuque",
263        "Automação",
264        "Fábrica de Dedos",
265        "Amante de Látex",
266        "Toque Dourado",
267        "Acumulador Dourado",
268        "Ascensão das Máquinas",
269    ],
270    achievement_descs: &[
271        "Dedar o cuque pela primeira vez",
272        "Acumular 100 cuques",
273        "Acumular 10.000 cuques",
274        "Acumular 1.000.000 de cuques",
275        "Comprar o primeiro dedador",
276        "Possuir 10 Mãos Inteiras",
277        "Possuir 10 Luvas de Látex",
278        "Pegar o primeiro Cuque Dourado",
279        "Pegar 10 Cuques Dourados",
280        "Possuir um Dedo Robótico",
281    ],
282    tree_title: " Árvore de Upgrades ",
283    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",
284    tree_rarity_small: "Pequeno",
285    tree_rarity_notable: "Notável",
286    tree_rarity_keystone: "PEDRA-ANGULAR",
287    tree_blurb_to: "a",
288    tree_blurb_flat_to: "fixo a",
289    tree_blurb_cost_on: "no custo de",
290    tree_blurb_spawn_rate_for: "na taxa de spawn de",
291    tree_blurb_effect_on: "no efeito de",
292    tree_target_all_fingerers: "todos os dedos",
293    tree_target_click: "poder do clique",
294    tree_target_prestige: "multiplicador de prestígio",
295    tree_target_green_coin_strength: "força da Moeda Verde",
296    tree_target_powerup_spawn_fmt: "spawn de {}",
297    tree_target_powerup_reward_fmt: "recompensa de {}",
298    tree_target_powerup_duration_fmt: "duração de {}",
299    tree_empty_lot_fmt: "(lote vazio em {:+}, {:+})",
300    tree_empty_lot_hint: "Mova com setas / hjkl para achar lotes populados.",
301    tree_owned_tag: "[possuído]",
302    tree_unreachable_hint: "inacessível — compre um vizinho conectado primeiro",
303    tree_cost_label: "Custo: ",
304    tree_cost_need_more_fmt: "(faltam {})",
305    tree_buy_button: "[Clique/Enter] comprar",
306    tree_refund_button: "[Clique/R] reembolsar",
307    tree_refund_returns_fmt: "(retorna {}, perde {})",
308    tree_anchor_tag: "[Nó Raiz]",
309    tree_anchor_blurb: "  - o cu trêmulo em si",
310    tree_anchor_footer: "  cada caminho da árvore se ramifica para fora daqui.",
311    tree_refund_reason_origin: "âncora — a origem não pode ser reembolsada",
312    tree_refund_reason_orphan: "deixaria outro nó possuído órfão — reembolse uma folha primeiro",
313    tree_no_refund_fmt: "(sem reembolso: {})",
314    prestige_title: " Prestígio ",
315    prestige_currency: "Papel de Seda",
316    prestige_owned_label: "Possui",
317    prestige_bonus_label: "Bônus de DPS",
318    prestige_available_label: "Disponível para resgatar",
319    prestige_lifetime_needed: "Próximo papel em",
320    prestige_confirm_hint: "Pressione [r] para resetar e resgatar",
321    prestige_confirm_question: "Tem CERTEZA que quer resetar?",
322    prestige_confirm_warning: "Apaga TODOS dedos, árvore, bônus.\nNão pode ser desfeito.",
323    prestige_confirm_yes: "[Y/Enter] Sim, resetar",
324    prestige_confirm_no: "[N/Esc] Não, cancelar",
325    prestige_not_enough: "Acumule mais cuques totais.\nFórmula: raiz(total / 1M)",
326    help_prestige: "[p/Esc] voltar  [q] sair",
327};
328
329static LANG: OnceLock<&'static Lang> = OnceLock::new();
330
331pub fn init() {
332    let _ = LANG.set(detect());
333}
334
335pub fn t() -> &'static Lang {
336    LANG.get().copied().unwrap_or(&EN)
337}
338
339fn detect() -> &'static Lang {
340    let raw = env::var("LANG").unwrap_or_default().to_lowercase();
341    let code = raw.split('.').next().unwrap_or("");
342    if code.starts_with("pt") { &PT_BR } else { &EN }
343}