1use crate::cedict::{Dictionary, Item};
2use crate::Error;
3use std::collections::HashMap;
4use std::path::PathBuf;
5use std::sync::OnceLock;
6
7pub(crate) static SIMPLIFIED: OnceLock<HashMap<String, Item>> = OnceLock::new();
9pub(crate) static TRADTIONAL: OnceLock<HashMap<String, Item>> = OnceLock::new();
10
11#[derive(Debug, PartialEq, Clone)]
13pub enum KeyVariant {
14 Simplified,
15 Traditional,
16}
17
18impl Default for KeyVariant {
19 fn default() -> Self {
20 Self::Simplified
21 }
22}
23
24pub(crate) fn initialize_dictionaries(path: &PathBuf) -> Result<(), Error> {
30 let simplified = Dictionary::new(path, KeyVariant::Simplified)?;
31 let traditional = Dictionary::new(path, KeyVariant::Traditional)?;
32
33 SIMPLIFIED.get_or_init(|| simplified.items);
34 TRADTIONAL.get_or_init(|| traditional.items);
35
36 Ok(())
37}
38
39impl KeyVariant {
40 pub(crate) fn convert_text_to_desired_variant<S: AsRef<str>>(
48 text: S,
49 input_variant: Self,
50 target_variant: Self,
51 ) -> Option<String> {
52 let chars = text.as_ref().chars();
54
55 let dictionary = match input_variant {
57 KeyVariant::Simplified => SIMPLIFIED.get()?,
58 KeyVariant::Traditional => TRADTIONAL.get()?,
59 };
60
61 let mut rebuild_content: Vec<String> = Vec::new();
62 for c in chars {
64 match dictionary.get(&c.to_string()) {
65 Some(character) => {
66 rebuild_content.push(character.get_character_for_key_variant(&target_variant))
67 }
68 None => rebuild_content.push(c.to_string()),
70 }
71 }
72
73 Some(rebuild_content.join(""))
74 }
75
76 pub(crate) fn which_variant<S: AsRef<str>>(text: S) -> Option<Self> {
82 let (simplified_dict, traditional_dict) = SIMPLIFIED.get().zip(TRADTIONAL.get())?;
84
85 let characters = text.as_ref().chars();
86 for ch in characters {
87 let str_char = ch.to_string();
88 if simplified_dict.get(&str_char).is_none() && traditional_dict.get(&str_char).is_some()
90 {
91 return Some(Self::Traditional);
92 }
93 }
94
95 Some(Self::Simplified)
96 }
97
98 pub(crate) fn detect_variant_with_unicode<S: AsRef<str>>(content: S) -> Self {
104 let characters = content.as_ref().chars();
105
106 for c in characters {
107 match c {
108 '\u{3400}'..='\u{4DBF}' => return Self::Traditional,
109 '\u{20000}'..='\u{2A6DF}' => return Self::Traditional,
110 '\u{2A700}'..='\u{2B73F}' => return Self::Traditional,
111 '\u{2B740}'..='\u{2B81F}' => return Self::Traditional,
112 '\u{2B820}'..='\u{2CEAF}' => return Self::Traditional,
113 '\u{2CEB0}'..='\u{2EBEF}' => return Self::Traditional,
114 _ => {}
115 }
116 }
117
118 Self::default()
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use super::*;
125 use std::path::PathBuf;
126
127 #[test]
128 fn expect_to_transform_traditional_to_simplified() {
129 let text = "她是我的最好摯友";
130
131 let res = super::initialize_dictionaries(&PathBuf::from("../static/cedict_sample_ts.u8"));
132 assert!(res.is_ok());
133
134 let converted = super::KeyVariant::convert_text_to_desired_variant(
135 text,
136 KeyVariant::Traditional,
137 KeyVariant::Simplified,
138 )
139 .unwrap();
140
141 assert_eq!(converted, "她是我的最好挚友");
142 }
143
144 #[test]
145 fn expect_to_convert_simplified_into_traditional() {
146 let text = "她是我的最好挚友";
147
148 let res = super::initialize_dictionaries(&PathBuf::from("../static/cedict_sample_ts.u8"));
149 assert!(res.is_ok());
150
151 let converted = super::KeyVariant::convert_text_to_desired_variant(
152 text,
153 KeyVariant::Simplified,
154 KeyVariant::Traditional,
155 )
156 .unwrap();
157
158 assert_eq!(converted, "她是我的最好摯友");
159 }
160
161 #[test]
162 fn expect_to_detect_traditional() {
163 let res = initialize_dictionaries(&PathBuf::from("../static/cedict_sample_ts.u8"));
164 assert!(res.is_ok());
165
166 let res = super::KeyVariant::which_variant("她是我的最好摯友");
167 assert_eq!(res.unwrap(), KeyVariant::Traditional);
168 }
169
170 #[test]
171 fn expect_to_detect_simplified() {
172 let res = initialize_dictionaries(&PathBuf::from("../static/cedict_sample_ts.u8"));
173 assert!(res.is_ok());
174
175 let res = super::KeyVariant::which_variant("她是我的最好挚友");
176 assert_eq!(res.unwrap(), KeyVariant::Simplified);
177 }
178
179 #[test]
180 fn expect_to_detect_traditional_with_unicode() {
181 let res = super::KeyVariant::detect_variant_with_unicode("這個牛肉的顏色是𫞩的");
182 assert_eq!(res, KeyVariant::Traditional);
183 }
184}