browser_automation_cli/i18n/
idioma.rs1use unic_langid::{langid, LanguageIdentifier};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[non_exhaustive]
9pub enum Direcao {
10 Ltr,
12 Rtl,
14}
15
16#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
18#[non_exhaustive]
19pub enum ScriptEscrita {
20 Latn,
22 Hans,
24 Hant,
26 Jpan,
28 Kore,
30 Arab,
32 Hebr,
34}
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41#[non_exhaustive]
42pub enum Idioma {
43 En,
45 PtBr,
47}
48
49impl Idioma {
50 pub const DISPONIVEIS: &'static [Idioma] = &[Idioma::En, Idioma::PtBr];
52
53 pub const fn bcp47(self) -> &'static str {
55 match self {
56 Idioma::En => "en",
57 Idioma::PtBr => "pt-BR",
58 }
59 }
60
61 pub const fn legacy_token(self) -> &'static str {
63 match self {
64 Idioma::En => "en",
65 Idioma::PtBr => "pt",
66 }
67 }
68
69 pub const fn language(self) -> &'static str {
71 match self {
72 Idioma::En => "en",
73 Idioma::PtBr => "pt",
74 }
75 }
76
77 pub const fn fallback(self) -> Idioma {
79 match self {
80 Idioma::En => Idioma::En,
81 Idioma::PtBr => Idioma::PtBr,
82 }
83 }
84
85 pub const fn direcao(self) -> Direcao {
87 Direcao::Ltr
88 }
89
90 pub const fn script(self) -> ScriptEscrita {
92 ScriptEscrita::Latn
93 }
94
95 pub fn language_identifier(self) -> LanguageIdentifier {
97 match self {
98 Idioma::En => langid!("en"),
99 Idioma::PtBr => langid!("pt-BR"),
100 }
101 }
102
103 pub fn from_langid(id: &LanguageIdentifier) -> Option<Idioma> {
105 let lang = id.language.as_str();
106 match lang {
107 "en" => Some(Idioma::En),
108 "pt" => {
109 match id.region.as_ref().map(|r| r.as_str()) {
112 Some("PT") => None,
113 Some("BR") | None => Some(Idioma::PtBr),
114 _ => Some(Idioma::PtBr),
115 }
116 }
117 _ => None,
118 }
119 }
120
121 pub fn parse_token(raw: &str) -> Option<Idioma> {
123 let s = raw.trim().replace('_', "-");
124 if s.is_empty() {
125 return None;
126 }
127 let lower = s.to_ascii_lowercase();
129 if lower == "pt" || lower.starts_with("pt-br") || lower == "pt-br" {
130 return Some(Idioma::PtBr);
131 }
132 if lower == "en" || lower.starts_with("en-") {
133 return Some(Idioma::En);
134 }
135 let id: LanguageIdentifier = s.parse().ok()?;
136 Self::from_langid(&id)
137 }
138}
139
140impl std::fmt::Display for Idioma {
141 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
142 f.write_str(self.bcp47())
143 }
144}
145
146#[cfg(test)]
147mod tests {
148 use super::*;
149
150 #[test]
151 fn parse_tokens_accept_regional_and_legacy() {
152 assert_eq!(Idioma::parse_token("pt-BR"), Some(Idioma::PtBr));
153 assert_eq!(Idioma::parse_token("pt_BR.UTF-8"), Some(Idioma::PtBr));
154 assert_eq!(Idioma::parse_token("pt"), Some(Idioma::PtBr));
155 assert_eq!(Idioma::parse_token("EN-us"), Some(Idioma::En));
156 assert_eq!(Idioma::parse_token("de-DE"), None);
157 }
158
159 #[test]
160 fn disponiveis_is_mvp_bilingual() {
161 assert_eq!(Idioma::DISPONIVEIS, &[Idioma::En, Idioma::PtBr]);
162 }
163}