khodpay_bip39/language.rs
1//! Language support for BIP39 mnemonic phrases.
2//!
3//! This module provides language abstraction for BIP39 word lists, allowing
4//! support for multiple languages while maintaining a clean API.
5//!
6//! # Supported Languages
7//!
8//! Currently supported languages match the BIP39 specification:
9//! - English (default and most widely used)
10//! - Japanese, Korean, French, Italian, Spanish, etc. (via upstream crate)
11//!
12//! # Examples
13//!
14//! ```rust
15//! use khodpay_bip39::{Language, validate_phrase_in_language};
16//!
17//! // Validate English mnemonic (most common)
18//! let phrase = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
19//! assert!(validate_phrase_in_language(phrase, Language::English).is_ok());
20//!
21//! // Future: Support for other languages
22//! // assert!(validate_phrase_in_language(japanese_phrase, Language::Japanese).is_ok());
23//! ```
24
25/// Supported languages for BIP39 mnemonic phrases.
26///
27/// This enum represents all languages supported by the BIP39 specification.
28/// Each language has its own 2048-word list for generating and validating
29/// mnemonic phrases.
30///
31/// # Default Language
32///
33/// [`English`] is the default and most widely supported language across
34/// cryptocurrency applications and hardware wallets.
35///
36/// [`English`]: Language::English
37#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
38pub enum Language {
39 /// English language word list.
40 ///
41 /// This is the default and most commonly used language for BIP39 mnemonics.
42 /// Supported by virtually all cryptocurrency wallets and applications.
43 ///
44 /// The English word list contains 2048 words, each 3-8 characters long,
45 /// chosen to be unambiguous and easy to distinguish.
46 English,
47
48 /// Japanese language word list.
49 ///
50 /// Uses hiragana characters and is popular in Japan.
51 /// Each word in the Japanese word list is carefully chosen to be
52 /// unambiguous when written in hiragana.
53 Japanese,
54
55 /// Korean language word list.
56 ///
57 /// Uses hangul (Korean alphabet) characters for Korean users.
58 /// Designed to avoid similar-looking or similar-sounding words.
59 Korean,
60
61 /// French language word list.
62 ///
63 /// Uses French words with proper accents and diacritics.
64 /// Words are chosen to be clear and unambiguous in French.
65 French,
66
67 /// Italian language word list.
68 ///
69 /// Uses Italian words selected for clarity and distinction.
70 /// Avoids words that might be confused with each other.
71 Italian,
72
73 /// Spanish language word list.
74 ///
75 /// Uses Spanish words carefully selected to avoid ambiguity.
76 /// Includes proper Spanish accents and spelling.
77 Spanish,
78
79 /// Simplified Chinese language word list.
80 ///
81 /// Uses simplified Chinese characters (mainland China standard).
82 /// Each character/word is chosen for uniqueness and clarity.
83 SimplifiedChinese,
84
85 /// Traditional Chinese language word list.
86 ///
87 /// Uses traditional Chinese characters (Taiwan/Hong Kong standard).
88 /// Characters selected to be easily distinguishable.
89 TraditionalChinese,
90
91 /// Czech language word list.
92 ///
93 /// Uses Czech words with proper diacritics and Czech spelling.
94 /// Words chosen to be unambiguous in Czech language context.
95 Czech,
96}
97
98impl Language {
99 /// Returns the default language (English).
100 ///
101 /// # Examples
102 ///
103 /// ```rust
104 /// # use khodpay_bip39::Language;
105 /// assert_eq!(Language::default(), Language::English);
106 /// ```
107 pub const fn default() -> Self {
108 Language::English
109 }
110
111 /// Returns all supported language variants.
112 ///
113 /// This is useful for iteration or UI language selection.
114 ///
115 /// # Examples
116 ///
117 /// ```rust
118 /// # use khodpay_bip39::Language;
119 /// let languages = Language::all_variants();
120 /// assert!(languages.contains(&Language::English));
121 /// assert!(languages.contains(&Language::Japanese));
122 /// assert_eq!(languages.len(), 9);
123 /// ```
124 pub const fn all_variants() -> &'static [Language] {
125 &[
126 Language::English,
127 Language::Japanese,
128 Language::Korean,
129 Language::French,
130 Language::Italian,
131 Language::Spanish,
132 Language::SimplifiedChinese,
133 Language::TraditionalChinese,
134 Language::Czech,
135 ]
136 }
137
138 /// Returns the language name as a string.
139 ///
140 /// # Examples
141 ///
142 /// ```rust
143 /// # use khodpay_bip39::Language;
144 /// assert_eq!(Language::English.name(), "English");
145 /// ```
146 pub const fn name(&self) -> &'static str {
147 match self {
148 Language::English => "English",
149 Language::Japanese => "Japanese",
150 Language::Korean => "Korean",
151 Language::French => "French",
152 Language::Italian => "Italian",
153 Language::Spanish => "Spanish",
154 Language::SimplifiedChinese => "Simplified Chinese",
155 Language::TraditionalChinese => "Traditional Chinese",
156 Language::Czech => "Czech",
157 }
158 }
159
160 /// Converts our Language enum to the upstream crate's Language type.
161 ///
162 /// This is an internal conversion method used to interface with the
163 /// upstream BIP39 crate while maintaining our own API.
164 ///
165 /// With the `all-languages` feature enabled, all BIP39 standard languages
166 /// are now properly supported and mapped to their upstream variants.
167 pub(crate) const fn to_upstream(self) -> bip39_upstream::Language {
168 match self {
169 Language::English => bip39_upstream::Language::English,
170 Language::Japanese => bip39_upstream::Language::Japanese,
171 Language::Korean => bip39_upstream::Language::Korean,
172 Language::French => bip39_upstream::Language::French,
173 Language::Italian => bip39_upstream::Language::Italian,
174 Language::Spanish => bip39_upstream::Language::Spanish,
175 Language::SimplifiedChinese => bip39_upstream::Language::SimplifiedChinese,
176 Language::TraditionalChinese => bip39_upstream::Language::TraditionalChinese,
177 Language::Czech => bip39_upstream::Language::Czech,
178 }
179 }
180}
181
182impl Default for Language {
183 /// Returns the default language (English).
184 fn default() -> Self {
185 Language::English
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192
193 #[test]
194 fn test_language_default() {
195 assert_eq!(Language::default(), Language::English);
196 assert_eq!(Language::default(), Language::default());
197 }
198
199 #[test]
200 fn test_language_name() {
201 assert_eq!(Language::English.name(), "English");
202 assert_eq!(Language::Japanese.name(), "Japanese");
203 assert_eq!(Language::Korean.name(), "Korean");
204 assert_eq!(Language::French.name(), "French");
205 assert_eq!(Language::Italian.name(), "Italian");
206 assert_eq!(Language::Spanish.name(), "Spanish");
207 assert_eq!(Language::SimplifiedChinese.name(), "Simplified Chinese");
208 assert_eq!(Language::TraditionalChinese.name(), "Traditional Chinese");
209 assert_eq!(Language::Czech.name(), "Czech");
210 }
211
212 #[test]
213 fn test_all_variants() {
214 let variants = Language::all_variants();
215 assert_eq!(variants.len(), 9);
216 assert!(variants.contains(&Language::English));
217 assert!(variants.contains(&Language::Japanese));
218 assert!(variants.contains(&Language::Korean));
219 assert!(variants.contains(&Language::French));
220 assert!(variants.contains(&Language::Italian));
221 assert!(variants.contains(&Language::Spanish));
222 assert!(variants.contains(&Language::SimplifiedChinese));
223 assert!(variants.contains(&Language::TraditionalChinese));
224 assert!(variants.contains(&Language::Czech));
225 }
226
227 #[test]
228 fn test_to_upstream_conversion() {
229 // Test that our enum values convert correctly to upstream types
230 assert_eq!(
231 Language::English.to_upstream(),
232 bip39_upstream::Language::English
233 );
234 assert_eq!(
235 Language::Japanese.to_upstream(),
236 bip39_upstream::Language::Japanese
237 );
238 assert_eq!(
239 Language::Korean.to_upstream(),
240 bip39_upstream::Language::Korean
241 );
242 assert_eq!(
243 Language::French.to_upstream(),
244 bip39_upstream::Language::French
245 );
246 assert_eq!(
247 Language::Italian.to_upstream(),
248 bip39_upstream::Language::Italian
249 );
250 assert_eq!(
251 Language::Spanish.to_upstream(),
252 bip39_upstream::Language::Spanish
253 );
254 assert_eq!(
255 Language::SimplifiedChinese.to_upstream(),
256 bip39_upstream::Language::SimplifiedChinese
257 );
258 assert_eq!(
259 Language::TraditionalChinese.to_upstream(),
260 bip39_upstream::Language::TraditionalChinese
261 );
262 assert_eq!(
263 Language::Czech.to_upstream(),
264 bip39_upstream::Language::Czech
265 );
266 }
267
268 #[test]
269 fn test_language_equality() {
270 assert_eq!(Language::English, Language::English);
271
272 // Test that copies are equal
273 let lang1 = Language::English;
274 let lang2 = lang1;
275 assert_eq!(lang1, lang2);
276 }
277
278 #[test]
279 fn test_language_debug() {
280 // Test that Debug trait works (for debugging/logging)
281 let debug_output = format!("{:?}", Language::English);
282 assert!(debug_output.contains("English"));
283 }
284}