1use 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
21pub 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 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 messages.insert(
46 "prompt.passphrase",
47 ("Enter passphrase: ", "パスフレーズを入力してください: "),
48 );
49
50 messages.insert(
51 "prompt.passphrase_confirm",
52 ("Confirm passphrase: ", "パスフレーズを再入力してください: "),
53 );
54
55 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 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 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 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}