1use std::sync::OnceLock;
11
12use crate::i18n::Language;
13
14static GLOBAL_LANGUAGE: OnceLock<Language> = OnceLock::new();
16
17pub fn resolve_language(force_lang: Option<&str>) -> Language {
22 if let Some(codigo) = force_lang {
24 if let Some(language) = code_to_language(codigo) {
25 return language;
26 }
27 }
28
29 if let Ok(env_lang) = std::env::var("SSH_CLI_LANG") {
31 if let Some(language) = code_to_language(&env_lang) {
32 return language;
33 }
34 }
35
36 if let Some(locale) = sys_locale::get_locale() {
38 if let Some(language) = code_to_language(&locale) {
39 return language;
40 }
41 }
42
43 Language::English
45}
46
47pub fn set_language(language: Language) {
52 let _ = GLOBAL_LANGUAGE.set(language);
53}
54
55pub fn current_language() -> Language {
60 GLOBAL_LANGUAGE.get().copied().unwrap_or(Language::English)
61}
62
63fn code_to_language(codigo: &str) -> Option<Language> {
68 let normalizado = codigo.to_lowercase();
69 match normalizado.as_str() {
70 "pt" | "pt-br" | "pt_br" => Some(Language::Portuguese),
71 "en" | "en-us" | "en_us" => Some(Language::English),
72 outro => {
73 if outro.starts_with("pt") {
74 Some(Language::Portuguese)
75 } else if outro.starts_with("en") {
76 Some(Language::English)
77 } else {
78 None
79 }
80 }
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn code_pt_returns_portuguese() {
90 assert_eq!(code_to_language("pt"), Some(Language::Portuguese));
91 }
92
93 #[test]
94 fn code_pt_br_returns_portuguese() {
95 assert_eq!(code_to_language("pt-BR"), Some(Language::Portuguese));
96 }
97
98 #[test]
99 fn code_pt_br_underscore_returns_portuguese() {
100 assert_eq!(code_to_language("pt_BR"), Some(Language::Portuguese));
101 }
102
103 #[test]
104 fn code_en_returns_english() {
105 assert_eq!(code_to_language("en"), Some(Language::English));
106 }
107
108 #[test]
109 fn code_en_us_returns_english() {
110 assert_eq!(code_to_language("en-US"), Some(Language::English));
111 }
112
113 #[test]
114 fn code_en_gb_returns_english_by_prefix() {
115 assert_eq!(code_to_language("en-GB"), Some(Language::English));
116 }
117
118 #[test]
119 fn unknown_code_returns_none() {
120 assert_eq!(code_to_language("fr-FR"), None);
121 }
122
123 #[test]
124 fn empty_code_returns_none() {
125 assert_eq!(code_to_language(""), None);
126 }
127
128 #[test]
129 fn uppercase_code_normalized() {
130 assert_eq!(code_to_language("PT"), Some(Language::Portuguese));
131 assert_eq!(code_to_language("EN"), Some(Language::English));
132 }
133
134 #[test]
135 fn resolve_force_pt_returns_portuguese() {
136 let result = resolve_language(Some("pt-BR"));
137 assert_eq!(result, Language::Portuguese);
138 }
139
140 #[test]
141 fn resolve_force_en_returns_english() {
142 let result = resolve_language(Some("en-US"));
143 assert_eq!(result, Language::English);
144 }
145
146 #[test]
147 fn resolve_force_invalid_uses_next_layers() {
148 std::env::remove_var("SSH_CLI_LANG");
150 let result = resolve_language(Some("xx-YY"));
151 assert!(
153 result == Language::English || result == Language::Portuguese,
154 "resolve_language must return a valid language even with invalid code"
155 );
156 }
157
158 #[test]
159 fn resolve_without_force_returns_valid_language() {
160 std::env::remove_var("SSH_CLI_LANG");
161 let result = resolve_language(None);
162 assert!(
163 result == Language::English || result == Language::Portuguese,
164 "resolve_language must return a valid language"
165 );
166 }
167
168 #[test]
169 fn current_language_fallback_english_before_set() {
170 let result = current_language();
173 assert!(
174 result == Language::English || result == Language::Portuguese,
175 "current_language must return a valid language"
176 );
177 }
178}