1use std::sync::OnceLock;
10
11use crate::i18n::Idioma;
12
13static IDIOMA_GLOBAL: OnceLock<Idioma> = OnceLock::new();
15
16pub fn resolver_idioma(forcar: Option<&str>) -> Idioma {
21 if let Some(codigo) = forcar {
23 if let Some(idioma) = codigo_para_idioma(codigo) {
24 return idioma;
25 }
26 }
27
28 if let Ok(env_lang) = std::env::var("SSH_CLI_LANG") {
30 if let Some(idioma) = codigo_para_idioma(&env_lang) {
31 return idioma;
32 }
33 }
34
35 if let Some(locale) = sys_locale::get_locale() {
37 if let Some(idioma) = codigo_para_idioma(&locale) {
38 return idioma;
39 }
40 }
41
42 Idioma::English
44}
45
46pub fn definir_idioma(idioma: Idioma) {
51 let _ = IDIOMA_GLOBAL.set(idioma);
52}
53
54pub fn idioma_atual() -> Idioma {
59 IDIOMA_GLOBAL.get().copied().unwrap_or(Idioma::English)
60}
61
62fn codigo_para_idioma(codigo: &str) -> Option<Idioma> {
67 let normalizado = codigo.to_lowercase();
68 match normalizado.as_str() {
69 "pt" | "pt-br" | "pt_br" => Some(Idioma::Portugues),
70 "en" | "en-us" | "en_us" => Some(Idioma::English),
71 outro => {
72 if outro.starts_with("pt") {
73 Some(Idioma::Portugues)
74 } else if outro.starts_with("en") {
75 Some(Idioma::English)
76 } else {
77 None
78 }
79 }
80 }
81}
82
83#[cfg(test)]
84mod testes {
85 use super::*;
86
87 #[test]
88 fn codigo_pt_retorna_portugues() {
89 assert_eq!(codigo_para_idioma("pt"), Some(Idioma::Portugues));
90 }
91
92 #[test]
93 fn codigo_pt_br_retorna_portugues() {
94 assert_eq!(codigo_para_idioma("pt-BR"), Some(Idioma::Portugues));
95 }
96
97 #[test]
98 fn codigo_pt_br_underscore_retorna_portugues() {
99 assert_eq!(codigo_para_idioma("pt_BR"), Some(Idioma::Portugues));
100 }
101
102 #[test]
103 fn codigo_en_retorna_english() {
104 assert_eq!(codigo_para_idioma("en"), Some(Idioma::English));
105 }
106
107 #[test]
108 fn codigo_en_us_retorna_english() {
109 assert_eq!(codigo_para_idioma("en-US"), Some(Idioma::English));
110 }
111
112 #[test]
113 fn codigo_en_gb_retorna_english_por_prefixo() {
114 assert_eq!(codigo_para_idioma("en-GB"), Some(Idioma::English));
115 }
116
117 #[test]
118 fn codigo_desconhecido_retorna_none() {
119 assert_eq!(codigo_para_idioma("fr-FR"), None);
120 }
121
122 #[test]
123 fn codigo_vazio_retorna_none() {
124 assert_eq!(codigo_para_idioma(""), None);
125 }
126
127 #[test]
128 fn codigo_maiusculo_normalizado() {
129 assert_eq!(codigo_para_idioma("PT"), Some(Idioma::Portugues));
130 assert_eq!(codigo_para_idioma("EN"), Some(Idioma::English));
131 }
132
133 #[test]
134 fn resolver_com_forcar_pt_retorna_portugues() {
135 let resultado = resolver_idioma(Some("pt-BR"));
136 assert_eq!(resultado, Idioma::Portugues);
137 }
138
139 #[test]
140 fn resolver_com_forcar_en_retorna_english() {
141 let resultado = resolver_idioma(Some("en-US"));
142 assert_eq!(resultado, Idioma::English);
143 }
144
145 #[test]
146 fn resolver_com_forcar_invalido_usa_camadas_seguintes() {
147 std::env::remove_var("SSH_CLI_LANG");
149 let resultado = resolver_idioma(Some("xx-YY"));
150 assert!(
152 resultado == Idioma::English || resultado == Idioma::Portugues,
153 "resolver_idioma deve retornar idioma válido mesmo com código inválido"
154 );
155 }
156
157 #[test]
158 fn resolver_sem_forcar_retorna_idioma_valido() {
159 std::env::remove_var("SSH_CLI_LANG");
160 let resultado = resolver_idioma(None);
161 assert!(
162 resultado == Idioma::English || resultado == Idioma::Portugues,
163 "resolver_idioma deve retornar idioma válido"
164 );
165 }
166
167 #[test]
168 fn idioma_atual_retorna_fallback_english_antes_de_definir() {
169 let resultado = idioma_atual();
172 assert!(
173 resultado == Idioma::English || resultado == Idioma::Portugues,
174 "idioma_atual deve retornar idioma válido"
175 );
176 }
177}