rustywallet_mnemonic/wordlist/
mod.rs1mod chinese_simplified;
7mod english;
8mod japanese;
9mod korean;
10mod spanish;
11
12pub use chinese_simplified::CHINESE_SIMPLIFIED_WORDLIST;
13pub use english::ENGLISH_WORDLIST;
14pub use japanese::JAPANESE_WORDLIST;
15pub use korean::KOREAN_WORDLIST;
16pub use spanish::SPANISH_WORDLIST;
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Hash)]
35pub enum Language {
36 #[default]
38 English,
39 Japanese,
41 Spanish,
43 ChineseSimplified,
45 Korean,
47}
48
49impl Language {
50 pub fn all() -> &'static [Language] {
52 &[
53 Language::English,
54 Language::Japanese,
55 Language::Spanish,
56 Language::ChineseSimplified,
57 Language::Korean,
58 ]
59 }
60
61 pub fn wordlist(&self) -> &'static [&'static str; 2048] {
63 match self {
64 Language::English => &ENGLISH_WORDLIST,
65 Language::Japanese => &JAPANESE_WORDLIST,
66 Language::Spanish => &SPANISH_WORDLIST,
67 Language::ChineseSimplified => &CHINESE_SIMPLIFIED_WORDLIST,
68 Language::Korean => &KOREAN_WORDLIST,
69 }
70 }
71
72 pub fn get_word(&self, index: usize) -> Option<&'static str> {
74 if index < 2048 {
75 Some(self.wordlist()[index])
76 } else {
77 None
78 }
79 }
80
81 pub fn get_index(&self, word: &str) -> Option<usize> {
83 let word_lower = word.to_lowercase();
84 self.wordlist().iter().position(|&w| w == word_lower)
85 }
86
87 pub fn contains(&self, word: &str) -> bool {
89 self.get_index(word).is_some()
90 }
91
92 pub fn name(&self) -> &'static str {
94 match self {
95 Language::English => "English",
96 Language::Japanese => "Japanese",
97 Language::Spanish => "Spanish",
98 Language::ChineseSimplified => "Chinese (Simplified)",
99 Language::Korean => "Korean",
100 }
101 }
102
103 pub fn detect_from_word(word: &str) -> Option<Language> {
108 for lang in Self::all() {
109 if lang.contains(word) {
110 return Some(*lang);
111 }
112 }
113 None
114 }
115
116 pub fn detect_from_phrase(phrase: &str) -> Option<Language> {
121 let words: Vec<&str> = phrase.split_whitespace().collect();
122 if words.is_empty() {
123 return None;
124 }
125
126 for lang in Self::all() {
127 let all_match = words.iter().all(|word| lang.contains(word));
128 if all_match {
129 return Some(*lang);
130 }
131 }
132 None
133 }
134}
135
136impl std::fmt::Display for Language {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 write!(f, "{}", self.name())
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_english_wordlist() {
148 let lang = Language::English;
149 assert_eq!(lang.wordlist().len(), 2048);
150 assert_eq!(lang.get_word(0), Some("abandon"));
151 assert_eq!(lang.get_word(2047), Some("zoo"));
152 assert!(lang.contains("abandon"));
153 assert!(!lang.contains("notaword"));
154 }
155
156 #[test]
157 fn test_japanese_wordlist() {
158 let lang = Language::Japanese;
159 assert_eq!(lang.wordlist().len(), 2048);
160 assert_eq!(lang.get_word(0), Some("あいこくしん"));
161 assert!(lang.contains("あいこくしん"));
162 }
163
164 #[test]
165 fn test_spanish_wordlist() {
166 let lang = Language::Spanish;
167 assert_eq!(lang.wordlist().len(), 2048);
168 assert_eq!(lang.get_word(0), Some("ábaco"));
169 assert!(lang.contains("ábaco"));
170 }
171
172 #[test]
173 fn test_chinese_simplified_wordlist() {
174 let lang = Language::ChineseSimplified;
175 assert_eq!(lang.wordlist().len(), 2048);
176 assert_eq!(lang.get_word(0), Some("的"));
177 assert!(lang.contains("的"));
178 }
179
180 #[test]
181 fn test_korean_wordlist() {
182 let lang = Language::Korean;
183 assert_eq!(lang.wordlist().len(), 2048);
184 assert_eq!(lang.get_word(0), Some("가격"));
185 assert!(lang.contains("가격"));
186 }
187
188 #[test]
189 fn test_detect_from_word() {
190 assert_eq!(Language::detect_from_word("abandon"), Some(Language::English));
191 assert_eq!(Language::detect_from_word("あいこくしん"), Some(Language::Japanese));
192 assert_eq!(Language::detect_from_word("ábaco"), Some(Language::Spanish));
193 assert_eq!(Language::detect_from_word("的"), Some(Language::ChineseSimplified));
194 assert_eq!(Language::detect_from_word("가격"), Some(Language::Korean));
195 assert_eq!(Language::detect_from_word("notaword"), None);
196 }
197
198 #[test]
199 fn test_detect_from_phrase() {
200 let english_phrase = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
201 assert_eq!(Language::detect_from_phrase(english_phrase), Some(Language::English));
202 }
203
204 #[test]
205 fn test_all_languages() {
206 let all = Language::all();
207 assert_eq!(all.len(), 5);
208 assert!(all.contains(&Language::English));
209 assert!(all.contains(&Language::Japanese));
210 assert!(all.contains(&Language::Spanish));
211 assert!(all.contains(&Language::ChineseSimplified));
212 assert!(all.contains(&Language::Korean));
213 }
214}