Skip to main content

slack_rs/auth/
i18n.rs

1//! Internationalization messages for auth commands
2
3use std::collections::HashMap;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub enum Language {
7    English,
8    Japanese,
9}
10
11impl Language {
12    pub fn from_code(code: &str) -> Option<Self> {
13        match code {
14            "en" | "EN" => Some(Language::English),
15            "ja" | "JA" => Some(Language::Japanese),
16            _ => None,
17        }
18    }
19}
20
21/// Message catalog for export/import operations
22pub struct Messages {
23    lang: Language,
24    messages: HashMap<&'static str, (&'static str, &'static str)>,
25}
26
27impl Messages {
28    pub fn new(lang: Language) -> Self {
29        let mut messages = HashMap::new();
30
31        // Warning messages
32        messages.insert(
33            "warn.export_sensitive",
34            (
35                "WARNING: You are about to export sensitive authentication data.\n\
36                 This file will contain access tokens that can be used to access your Slack workspaces.\n\
37                 Store this file securely and delete it after use.",
38                "警告: 機密認証情報をエクスポートしようとしています。\n\
39                 このファイルには Slack ワークスペースへのアクセスに使用できるアクセストークンが含まれます。\n\
40                 このファイルは安全に保管し、使用後は削除してください。"
41            ),
42        );
43
44        // Prompt messages
45        messages.insert(
46            "prompt.passphrase",
47            ("Enter passphrase: ", "パスフレーズを入力してください: "),
48        );
49
50        messages.insert(
51            "prompt.passphrase_confirm",
52            ("Confirm passphrase: ", "パスフレーズを再入力してください: "),
53        );
54
55        // Error messages
56        messages.insert(
57            "error.bad_permissions",
58            (
59                "Error: File must have 0600 permissions (owner read/write only)",
60                "エラー: ファイルは 0600 パーミッション(所有者の読み書きのみ)である必要があります"
61            ),
62        );
63
64        messages.insert(
65            "error.passphrase_mismatch",
66            (
67                "Error: Passphrases do not match",
68                "エラー: パスフレーズが一致しません",
69            ),
70        );
71
72        messages.insert(
73            "error.empty_passphrase",
74            (
75                "Error: Empty passphrase not allowed",
76                "エラー: 空のパスフレーズは許可されていません",
77            ),
78        );
79
80        messages.insert(
81            "error.confirmation_required",
82            (
83                "Error: Export requires --yes flag for confirmation",
84                "エラー: エクスポートには --yes フラグによる確認が必要です",
85            ),
86        );
87
88        messages.insert(
89            "error.profile_exists",
90            (
91                "Error: Profile already exists (use --force to overwrite)",
92                "エラー: プロファイルがすでに存在します(上書きするには --force を使用してください)"
93            ),
94        );
95
96        // Success messages
97        messages.insert(
98            "success.export",
99            (
100                "✓ Profiles exported successfully",
101                "✓ プロファイルのエクスポートが完了しました",
102            ),
103        );
104
105        messages.insert(
106            "success.import",
107            (
108                "✓ Profiles imported successfully",
109                "✓ プロファイルのインポートが完了しました",
110            ),
111        );
112
113        // Info messages
114        messages.insert(
115            "info.export_count",
116            (
117                "Exporting {count} profile(s)",
118                "{count} 件のプロファイルをエクスポート中",
119            ),
120        );
121
122        messages.insert(
123            "info.import_count",
124            (
125                "Importing {count} profile(s)",
126                "{count} 件のプロファイルをインポート中",
127            ),
128        );
129
130        Self { lang, messages }
131    }
132
133    pub fn get(&self, key: &str) -> &'static str {
134        match self.messages.get(key) {
135            Some(&(en, ja)) => match self.lang {
136                Language::English => en,
137                Language::Japanese => ja,
138            },
139            None => "",
140        }
141    }
142
143    #[allow(dead_code)]
144    pub fn format(&self, key: &str, replacements: &[(&str, &str)]) -> String {
145        let template = self.get(key);
146        let mut result = template.to_string();
147        for (placeholder, value) in replacements {
148            result = result.replace(&format!("{{{}}}", placeholder), value);
149        }
150        result
151    }
152}
153
154impl Default for Messages {
155    fn default() -> Self {
156        // Default to Japanese based on locale, or English if not detected
157        let lang = std::env::var("LANG")
158            .ok()
159            .map(|lang| {
160                if lang.starts_with("ja") {
161                    Language::Japanese
162                } else {
163                    Language::English
164                }
165            })
166            .unwrap_or(Language::English);
167
168        Self::new(lang)
169    }
170}
171
172#[cfg(test)]
173mod tests {
174    use super::*;
175
176    #[test]
177    fn test_messages_english() {
178        let messages = Messages::new(Language::English);
179        assert!(messages.get("warn.export_sensitive").starts_with("WARNING"));
180        assert!(messages.get("success.export").contains("exported"));
181    }
182
183    #[test]
184    fn test_messages_japanese() {
185        let messages = Messages::new(Language::Japanese);
186        assert!(messages.get("warn.export_sensitive").starts_with("警告"));
187        assert!(messages.get("success.export").contains("エクスポート"));
188    }
189
190    #[test]
191    fn test_format_message() {
192        let messages = Messages::new(Language::English);
193        let formatted = messages.format("info.export_count", &[("count", "3")]);
194        assert!(formatted.contains("3"));
195        assert!(formatted.contains("profile"));
196    }
197
198    #[test]
199    fn test_language_from_code() {
200        assert_eq!(Language::from_code("en"), Some(Language::English));
201        assert_eq!(Language::from_code("ja"), Some(Language::Japanese));
202        assert_eq!(Language::from_code("EN"), Some(Language::English));
203        assert_eq!(Language::from_code("JA"), Some(Language::Japanese));
204        assert_eq!(Language::from_code("fr"), None);
205    }
206}