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}