gitinstall 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gitinstall/__init__.py +61 -0
- gitinstall/_sdk.py +541 -0
- gitinstall/academic.py +831 -0
- gitinstall/admin.html +327 -0
- gitinstall/auto_update.py +384 -0
- gitinstall/autopilot.py +349 -0
- gitinstall/badge.py +476 -0
- gitinstall/checkpoint.py +330 -0
- gitinstall/cicd.py +499 -0
- gitinstall/clawhub.html +718 -0
- gitinstall/config_schema.py +353 -0
- gitinstall/db.py +984 -0
- gitinstall/db_backend.py +445 -0
- gitinstall/dep_chain.py +337 -0
- gitinstall/dependency_audit.py +1153 -0
- gitinstall/detector.py +542 -0
- gitinstall/doctor.py +493 -0
- gitinstall/education.py +869 -0
- gitinstall/enterprise.py +802 -0
- gitinstall/error_fixer.py +953 -0
- gitinstall/event_bus.py +251 -0
- gitinstall/executor.py +577 -0
- gitinstall/feature_flags.py +138 -0
- gitinstall/fetcher.py +921 -0
- gitinstall/huggingface.py +922 -0
- gitinstall/hw_detect.py +988 -0
- gitinstall/i18n.py +664 -0
- gitinstall/installer_registry.py +362 -0
- gitinstall/knowledge_base.py +379 -0
- gitinstall/license_check.py +605 -0
- gitinstall/llm.py +569 -0
- gitinstall/log.py +236 -0
- gitinstall/main.py +1408 -0
- gitinstall/mcp_agent.py +841 -0
- gitinstall/mcp_server.py +386 -0
- gitinstall/monorepo.py +810 -0
- gitinstall/multi_source.py +425 -0
- gitinstall/onboard.py +276 -0
- gitinstall/planner.py +222 -0
- gitinstall/planner_helpers.py +323 -0
- gitinstall/planner_known_projects.py +1010 -0
- gitinstall/planner_templates.py +996 -0
- gitinstall/remote_gpu.py +633 -0
- gitinstall/resilience.py +608 -0
- gitinstall/run_tests.py +572 -0
- gitinstall/skills.py +476 -0
- gitinstall/tool_schemas.py +324 -0
- gitinstall/trending.py +279 -0
- gitinstall/uninstaller.py +415 -0
- gitinstall/validate_top100.py +607 -0
- gitinstall/watchdog.py +180 -0
- gitinstall/web.py +1277 -0
- gitinstall/web_ui.html +2277 -0
- gitinstall-1.1.0.dist-info/METADATA +275 -0
- gitinstall-1.1.0.dist-info/RECORD +59 -0
- gitinstall-1.1.0.dist-info/WHEEL +5 -0
- gitinstall-1.1.0.dist-info/entry_points.txt +3 -0
- gitinstall-1.1.0.dist-info/licenses/LICENSE +21 -0
- gitinstall-1.1.0.dist-info/top_level.txt +1 -0
gitinstall/i18n.py
ADDED
|
@@ -0,0 +1,664 @@
|
|
|
1
|
+
"""
|
|
2
|
+
i18n.py - gitinstall 国际化框架
|
|
3
|
+
=================================
|
|
4
|
+
|
|
5
|
+
零外部依赖的轻量 i18n 系统。
|
|
6
|
+
支持:消息目录、区域切换、参数插值、复数形式。
|
|
7
|
+
|
|
8
|
+
用法:
|
|
9
|
+
from i18n import t, set_locale
|
|
10
|
+
set_locale("en")
|
|
11
|
+
print(t("install.complete")) # "Installation complete!"
|
|
12
|
+
print(t("error.password_min", n=8)) # "Password must be at least 8 characters"
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import os
|
|
18
|
+
import threading
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
# ── 当前区域设置 ──
|
|
22
|
+
_current_locale = "zh"
|
|
23
|
+
_locale_lock = threading.Lock()
|
|
24
|
+
|
|
25
|
+
# ── 支持的区域 ──
|
|
26
|
+
SUPPORTED_LOCALES = ("zh", "en")
|
|
27
|
+
DEFAULT_LOCALE = "zh"
|
|
28
|
+
|
|
29
|
+
# ─────────────────────────────────────────────
|
|
30
|
+
# 消息目录
|
|
31
|
+
# ─────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
_MESSAGES: dict[str, dict[str, str]] = {
|
|
34
|
+
# ── 通用 ──
|
|
35
|
+
"common.ok": {
|
|
36
|
+
"zh": "成功",
|
|
37
|
+
"en": "OK",
|
|
38
|
+
},
|
|
39
|
+
"common.error": {
|
|
40
|
+
"zh": "错误",
|
|
41
|
+
"en": "Error",
|
|
42
|
+
},
|
|
43
|
+
"common.retry_later": {
|
|
44
|
+
"zh": "请稍后重试",
|
|
45
|
+
"en": "Please try again later",
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
# ── 认证相关 ──
|
|
49
|
+
"auth.fields_required": {
|
|
50
|
+
"zh": "用户名、邮箱、密码均不能为空",
|
|
51
|
+
"en": "Username, email, and password are required",
|
|
52
|
+
},
|
|
53
|
+
"auth.password_min": {
|
|
54
|
+
"zh": "密码至少 {n} 位",
|
|
55
|
+
"en": "Password must be at least {n} characters",
|
|
56
|
+
},
|
|
57
|
+
"auth.email_exists": {
|
|
58
|
+
"zh": "该邮箱已注册",
|
|
59
|
+
"en": "This email is already registered",
|
|
60
|
+
},
|
|
61
|
+
"auth.username_taken": {
|
|
62
|
+
"zh": "用户名已被使用",
|
|
63
|
+
"en": "Username is already taken",
|
|
64
|
+
},
|
|
65
|
+
"auth.register_failed": {
|
|
66
|
+
"zh": "注册失败,请重试",
|
|
67
|
+
"en": "Registration failed, please try again",
|
|
68
|
+
},
|
|
69
|
+
"auth.invalid_credentials": {
|
|
70
|
+
"zh": "邮箱或密码错误",
|
|
71
|
+
"en": "Invalid email or password",
|
|
72
|
+
},
|
|
73
|
+
"auth.reset_expired": {
|
|
74
|
+
"zh": "重置链接已过期或无效,请重新申请",
|
|
75
|
+
"en": "Reset link has expired or is invalid, please request a new one",
|
|
76
|
+
},
|
|
77
|
+
"auth.password_reset_ok": {
|
|
78
|
+
"zh": "密码已重置,请重新登录",
|
|
79
|
+
"en": "Password has been reset, please log in again",
|
|
80
|
+
},
|
|
81
|
+
"auth.admin_required": {
|
|
82
|
+
"zh": "需要管理员权限",
|
|
83
|
+
"en": "Admin privileges required",
|
|
84
|
+
},
|
|
85
|
+
"auth.admin_set_ok": {
|
|
86
|
+
"zh": "管理员已设置",
|
|
87
|
+
"en": "Admin privileges granted",
|
|
88
|
+
},
|
|
89
|
+
"auth.no_permission": {
|
|
90
|
+
"zh": "无权限",
|
|
91
|
+
"en": "Permission denied",
|
|
92
|
+
},
|
|
93
|
+
"auth.enter_email": {
|
|
94
|
+
"zh": "请输入邮箱",
|
|
95
|
+
"en": "Please enter your email",
|
|
96
|
+
},
|
|
97
|
+
"auth.params_incomplete": {
|
|
98
|
+
"zh": "参数不完整",
|
|
99
|
+
"en": "Incomplete parameters",
|
|
100
|
+
},
|
|
101
|
+
"auth.reset_email_sent": {
|
|
102
|
+
"zh": "如果该邮箱已注册,重置链接已发送到你的邮箱",
|
|
103
|
+
"en": "If this email is registered, a reset link has been sent",
|
|
104
|
+
},
|
|
105
|
+
|
|
106
|
+
# ── Web API ──
|
|
107
|
+
"api.rate_limited": {
|
|
108
|
+
"zh": "请求过于频繁,请稍后再试",
|
|
109
|
+
"en": "Too many requests, please try again later",
|
|
110
|
+
},
|
|
111
|
+
"api.invalid_json": {
|
|
112
|
+
"zh": "无效的 JSON 请求",
|
|
113
|
+
"en": "Invalid JSON request",
|
|
114
|
+
},
|
|
115
|
+
"api.search_keyword_required": {
|
|
116
|
+
"zh": "请输入搜索关键词",
|
|
117
|
+
"en": "Please enter a search keyword",
|
|
118
|
+
},
|
|
119
|
+
"api.search_failed": {
|
|
120
|
+
"zh": "搜索失败,请稍后重试",
|
|
121
|
+
"en": "Search failed, please try again later",
|
|
122
|
+
},
|
|
123
|
+
"api.system_busy": {
|
|
124
|
+
"zh": "系统繁忙,请稍后重试",
|
|
125
|
+
"en": "System is busy, please try again later",
|
|
126
|
+
},
|
|
127
|
+
"api.project_required": {
|
|
128
|
+
"zh": "请输入项目名称",
|
|
129
|
+
"en": "Please enter a project name",
|
|
130
|
+
},
|
|
131
|
+
"api.missing_param": {
|
|
132
|
+
"zh": "缺少 {param} 参数",
|
|
133
|
+
"en": "Missing {param} parameter",
|
|
134
|
+
},
|
|
135
|
+
"api.param_format_error": {
|
|
136
|
+
"zh": "参数格式错误",
|
|
137
|
+
"en": "Invalid parameter format",
|
|
138
|
+
},
|
|
139
|
+
"api.query_failed": {
|
|
140
|
+
"zh": "查询失败",
|
|
141
|
+
"en": "Query failed",
|
|
142
|
+
},
|
|
143
|
+
"api.body_too_large": {
|
|
144
|
+
"zh": "请求体过大",
|
|
145
|
+
"en": "Request body too large",
|
|
146
|
+
},
|
|
147
|
+
"api.missing_user_id": {
|
|
148
|
+
"zh": "缺少 user_id",
|
|
149
|
+
"en": "Missing user_id",
|
|
150
|
+
},
|
|
151
|
+
"api.too_many_installs": {
|
|
152
|
+
"zh": "同时安装任务过多,请等待当前任务完成",
|
|
153
|
+
"en": "Too many concurrent installs, please wait",
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
# ── 安装相关 ──
|
|
157
|
+
"install.detecting_env": {
|
|
158
|
+
"zh": "🔍 正在检测系统环境...",
|
|
159
|
+
"en": "🔍 Detecting system environment...",
|
|
160
|
+
},
|
|
161
|
+
"install.fetching": {
|
|
162
|
+
"zh": "📡 正在获取 {project} 的项目信息...",
|
|
163
|
+
"en": "📡 Fetching project info for {project}...",
|
|
164
|
+
},
|
|
165
|
+
"install.analyzing": {
|
|
166
|
+
"zh": "🧠 SmartPlanner 分析中...",
|
|
167
|
+
"en": "🧠 SmartPlanner analyzing...",
|
|
168
|
+
},
|
|
169
|
+
"install.plan_generated": {
|
|
170
|
+
"zh": "✅ 安装计划已生成",
|
|
171
|
+
"en": "✅ Installation plan generated",
|
|
172
|
+
},
|
|
173
|
+
"install.executing": {
|
|
174
|
+
"zh": "🔧 正在执行...",
|
|
175
|
+
"en": "🔧 Executing...",
|
|
176
|
+
},
|
|
177
|
+
"install.step_done": {
|
|
178
|
+
"zh": "✅ 完成",
|
|
179
|
+
"en": "✅ Done",
|
|
180
|
+
},
|
|
181
|
+
"install.step_failed": {
|
|
182
|
+
"zh": "❌ 失败",
|
|
183
|
+
"en": "❌ Failed",
|
|
184
|
+
},
|
|
185
|
+
"install.complete": {
|
|
186
|
+
"zh": "🎉 安装完成!",
|
|
187
|
+
"en": "🎉 Installation complete!",
|
|
188
|
+
},
|
|
189
|
+
"install.not_complete": {
|
|
190
|
+
"zh": "安装未成功,请检查上方错误信息",
|
|
191
|
+
"en": "Installation failed, check errors above",
|
|
192
|
+
},
|
|
193
|
+
"install.plan_expired": {
|
|
194
|
+
"zh": "计划已过期,请重新分析",
|
|
195
|
+
"en": "Plan expired, please re-analyze",
|
|
196
|
+
},
|
|
197
|
+
"install.regenerating_plan": {
|
|
198
|
+
"zh": "重新生成安装计划...",
|
|
199
|
+
"en": "Regenerating installation plan...",
|
|
200
|
+
},
|
|
201
|
+
"install.plan_failed": {
|
|
202
|
+
"zh": "生成计划失败",
|
|
203
|
+
"en": "Plan generation failed",
|
|
204
|
+
},
|
|
205
|
+
"install.no_steps": {
|
|
206
|
+
"zh": "未能生成有效的安装步骤",
|
|
207
|
+
"en": "No valid installation steps generated",
|
|
208
|
+
},
|
|
209
|
+
"install.unsafe_command": {
|
|
210
|
+
"zh": "检测到不安全命令,已终止",
|
|
211
|
+
"en": "Unsafe command detected, terminated",
|
|
212
|
+
},
|
|
213
|
+
"install.dir_security": {
|
|
214
|
+
"zh": "安全限制:安装目录必须在用户家目录下",
|
|
215
|
+
"en": "Security: install directory must be under home",
|
|
216
|
+
},
|
|
217
|
+
"install.dir_path_changed": {
|
|
218
|
+
"zh": "安全限制:检测到路径异常变化",
|
|
219
|
+
"en": "Security: abnormal path change detected",
|
|
220
|
+
},
|
|
221
|
+
"install.dir_invalid": {
|
|
222
|
+
"zh": "安装目录不合法",
|
|
223
|
+
"en": "Invalid installation directory",
|
|
224
|
+
},
|
|
225
|
+
"install.output_truncated": {
|
|
226
|
+
"zh": "...[输出过多,已截断]...",
|
|
227
|
+
"en": "...[output truncated]...",
|
|
228
|
+
},
|
|
229
|
+
"install.cmd_timeout": {
|
|
230
|
+
"zh": "命令超时({minutes} 分钟)",
|
|
231
|
+
"en": "Command timed out ({minutes} min)",
|
|
232
|
+
},
|
|
233
|
+
"install.cmd_exit_code": {
|
|
234
|
+
"zh": "命令返回 exit code {code}",
|
|
235
|
+
"en": "Command returned exit code {code}",
|
|
236
|
+
},
|
|
237
|
+
"install.dangerous_cmd_rejected": {
|
|
238
|
+
"zh": "🚫 危险命令,已拒绝执行:{cmd}",
|
|
239
|
+
"en": "🚫 Dangerous command rejected: {cmd}",
|
|
240
|
+
},
|
|
241
|
+
|
|
242
|
+
# ── 审计/许可证 ──
|
|
243
|
+
"audit.failed": {
|
|
244
|
+
"zh": "审计失败,请稍后重试",
|
|
245
|
+
"en": "Audit failed, please try again later",
|
|
246
|
+
},
|
|
247
|
+
"audit.no_deps": {
|
|
248
|
+
"zh": "未找到依赖文件",
|
|
249
|
+
"en": "No dependency files found",
|
|
250
|
+
},
|
|
251
|
+
"license.no_license": {
|
|
252
|
+
"zh": "项目未声明许可证",
|
|
253
|
+
"en": "Project has no declared license",
|
|
254
|
+
},
|
|
255
|
+
"license.check_failed": {
|
|
256
|
+
"zh": "许可证检查失败,请稍后重试",
|
|
257
|
+
"en": "License check failed, please try again later",
|
|
258
|
+
},
|
|
259
|
+
|
|
260
|
+
# ── 更新/卸载 ──
|
|
261
|
+
"update.check_failed": {
|
|
262
|
+
"zh": "更新检查失败",
|
|
263
|
+
"en": "Update check failed",
|
|
264
|
+
},
|
|
265
|
+
"uninstall.failed": {
|
|
266
|
+
"zh": "卸载失败,请稍后重试",
|
|
267
|
+
"en": "Uninstall failed, please try again later",
|
|
268
|
+
},
|
|
269
|
+
"uninstall.not_found": {
|
|
270
|
+
"zh": "未找到 {project} 的安装记录",
|
|
271
|
+
"en": "No install record found for {project}",
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
# ── LLM ──
|
|
275
|
+
"llm.using_heuristic": {
|
|
276
|
+
"zh": "[LLM] 使用规则引擎模式(无 LLM)",
|
|
277
|
+
"en": "[LLM] Using heuristic mode (no LLM)",
|
|
278
|
+
},
|
|
279
|
+
"llm.using_provider": {
|
|
280
|
+
"zh": "[LLM] 使用 {provider}: {endpoint}",
|
|
281
|
+
"en": "[LLM] Using {provider}: {endpoint}",
|
|
282
|
+
},
|
|
283
|
+
"llm.using_named": {
|
|
284
|
+
"zh": "[LLM] 使用 {name}",
|
|
285
|
+
"en": "[LLM] Using {name}",
|
|
286
|
+
},
|
|
287
|
+
"llm.using_with_model": {
|
|
288
|
+
"zh": "[LLM] 使用 {name}: {model}",
|
|
289
|
+
"en": "[LLM] Using {name}: {model}",
|
|
290
|
+
},
|
|
291
|
+
"llm.detected_local": {
|
|
292
|
+
"zh": "[LLM] 检测到 {name},使用模型:{model}",
|
|
293
|
+
"en": "[LLM] Detected {name}, using model: {model}",
|
|
294
|
+
},
|
|
295
|
+
"llm.ollama_hint": {
|
|
296
|
+
"zh": "[LLM] 提示:默认使用 {model}(~1GB)。更大模型质量更好但需要更多内存。",
|
|
297
|
+
"en": "[LLM] Hint: using {model} (~1GB) by default. Larger models give better results but need more memory.",
|
|
298
|
+
},
|
|
299
|
+
"llm.no_provider": {
|
|
300
|
+
"zh": "[LLM] 未检测到任何 LLM,使用规则引擎模式(功能完整,对未知项目质量略低)",
|
|
301
|
+
"en": "[LLM] No LLM detected, using heuristic mode (fully functional, slightly lower quality for unknown projects)",
|
|
302
|
+
},
|
|
303
|
+
"llm.hint_ollama": {
|
|
304
|
+
"zh": "[LLM] 免费方案 1:安装 Ollama + ollama pull qwen2.5:1.5b(推荐,~1GB,本地运行)",
|
|
305
|
+
"en": "[LLM] Free option 1: Install Ollama + ollama pull qwen2.5:1.5b (recommended, ~1GB, local)",
|
|
306
|
+
},
|
|
307
|
+
"llm.hint_groq": {
|
|
308
|
+
"zh": "[LLM] 免费方案 2:注册 groq.com 设置 GROQ_API_KEY(云端免费额度)",
|
|
309
|
+
"en": "[LLM] Free option 2: Register at groq.com and set GROQ_API_KEY (free cloud quota)",
|
|
310
|
+
},
|
|
311
|
+
"llm.api_error": {
|
|
312
|
+
"zh": "[LLM] API 调用失败",
|
|
313
|
+
"en": "[LLM] API call failed",
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
# ── 执行器 ──
|
|
317
|
+
"exec.install_start": {
|
|
318
|
+
"zh": "🚀 开始安装 {project}(共 {steps} 步)",
|
|
319
|
+
"en": "🚀 Installing {project} ({steps} steps)",
|
|
320
|
+
},
|
|
321
|
+
"exec.step_progress": {
|
|
322
|
+
"zh": "[{current}/{total}] {description}",
|
|
323
|
+
"en": "[{current}/{total}] {description}",
|
|
324
|
+
},
|
|
325
|
+
"exec.step_done": {
|
|
326
|
+
"zh": " ✅ 完成({duration}s)",
|
|
327
|
+
"en": " ✅ Done ({duration}s)",
|
|
328
|
+
},
|
|
329
|
+
"exec.step_failed": {
|
|
330
|
+
"zh": " ❌ 失败(退出码 {code})",
|
|
331
|
+
"en": " ❌ Failed (exit code {code})",
|
|
332
|
+
},
|
|
333
|
+
"exec.install_done": {
|
|
334
|
+
"zh": "🎉 {project} 安装完成!",
|
|
335
|
+
"en": "🎉 {project} installed successfully!",
|
|
336
|
+
},
|
|
337
|
+
"exec.launch_cmd": {
|
|
338
|
+
"zh": "▶ 启动命令:{cmd}",
|
|
339
|
+
"en": "▶ Launch command: {cmd}",
|
|
340
|
+
},
|
|
341
|
+
"exec.install_dir": {
|
|
342
|
+
"zh": "📁 安装目录:{dir}",
|
|
343
|
+
"en": "📁 Install directory: {dir}",
|
|
344
|
+
},
|
|
345
|
+
"exec.rule_diagnosis": {
|
|
346
|
+
"zh": " 🔧 规则引擎诊断:{cause}(置信度:{confidence})",
|
|
347
|
+
"en": " 🔧 Rule engine diagnosis: {cause} (confidence: {confidence})",
|
|
348
|
+
},
|
|
349
|
+
"exec.fix_cmd": {
|
|
350
|
+
"zh": " 🔧 修复:{cmd}",
|
|
351
|
+
"en": " 🔧 Fix: {cmd}",
|
|
352
|
+
},
|
|
353
|
+
"exec.fix_failed": {
|
|
354
|
+
"zh": " ⚠ 修复命令失败,跳过规则修复",
|
|
355
|
+
"en": " ⚠ Fix command failed, skipping rule-based fix",
|
|
356
|
+
},
|
|
357
|
+
"exec.retrying": {
|
|
358
|
+
"zh": " 🔄 重试原始命令...",
|
|
359
|
+
"en": " 🔄 Retrying original command...",
|
|
360
|
+
},
|
|
361
|
+
"exec.rule_fix_ok": {
|
|
362
|
+
"zh": " ✅ 规则修复成功!",
|
|
363
|
+
"en": " ✅ Rule-based fix succeeded!",
|
|
364
|
+
},
|
|
365
|
+
"exec.llm_fallback": {
|
|
366
|
+
"zh": " 🔧 规则引擎无法修复,调用 LLM 分析...",
|
|
367
|
+
"en": " 🔧 Rule engine cannot fix, calling LLM...",
|
|
368
|
+
},
|
|
369
|
+
"exec.llm_root_cause": {
|
|
370
|
+
"zh": " 💡 根本原因:{cause}",
|
|
371
|
+
"en": " 💡 Root cause: {cause}",
|
|
372
|
+
},
|
|
373
|
+
"exec.fix_rejected": {
|
|
374
|
+
"zh": " 🚫 修复命令被安全策略拒绝:{cmd}",
|
|
375
|
+
"en": " 🚫 Fix command rejected by security policy: {cmd}",
|
|
376
|
+
},
|
|
377
|
+
"exec.fix_cmd_failed": {
|
|
378
|
+
"zh": " ❌ 修复命令失败",
|
|
379
|
+
"en": " ❌ Fix command failed",
|
|
380
|
+
},
|
|
381
|
+
"exec.llm_fix_ok": {
|
|
382
|
+
"zh": " ✅ LLM 修复成功!",
|
|
383
|
+
"en": " ✅ LLM fix succeeded!",
|
|
384
|
+
},
|
|
385
|
+
"exec.llm_fix_error": {
|
|
386
|
+
"zh": " ⚠️ LLM 自动修复失败({error}),跳过",
|
|
387
|
+
"en": " ⚠️ LLM auto-fix failed ({error}), skipping",
|
|
388
|
+
},
|
|
389
|
+
|
|
390
|
+
# ── 错误修复 ──
|
|
391
|
+
"fixer.diagnosing": {
|
|
392
|
+
"zh": "🔧 规则引擎诊断",
|
|
393
|
+
"en": "🔧 Rule engine diagnosis",
|
|
394
|
+
},
|
|
395
|
+
"fixer.missing_dep": {
|
|
396
|
+
"zh": "缺依赖",
|
|
397
|
+
"en": "Missing dependency",
|
|
398
|
+
},
|
|
399
|
+
"fixer.permission_denied": {
|
|
400
|
+
"zh": "权限不足",
|
|
401
|
+
"en": "Permission denied",
|
|
402
|
+
},
|
|
403
|
+
"fixer.use_venv": {
|
|
404
|
+
"zh": "需使用虚拟环境",
|
|
405
|
+
"en": "Virtual environment required",
|
|
406
|
+
},
|
|
407
|
+
"fixer.system_python_protected": {
|
|
408
|
+
"zh": "系统 Python 受保护",
|
|
409
|
+
"en": "System Python is protected",
|
|
410
|
+
},
|
|
411
|
+
"fixer.pip_permission": {
|
|
412
|
+
"zh": "pip 权限",
|
|
413
|
+
"en": "pip permission",
|
|
414
|
+
},
|
|
415
|
+
|
|
416
|
+
# ── 服务器 ──
|
|
417
|
+
"server.started": {
|
|
418
|
+
"zh": "服务器已启动: {host}:{port}",
|
|
419
|
+
"en": "Server started: {host}:{port}",
|
|
420
|
+
},
|
|
421
|
+
"server.port_unavailable": {
|
|
422
|
+
"zh": "❌ 端口 {start}~{end} 都被占用,请指定其他端口",
|
|
423
|
+
"en": "❌ Ports {start}~{end} are all in use, please specify another",
|
|
424
|
+
},
|
|
425
|
+
"server.stopped": {
|
|
426
|
+
"zh": "👋 服务器已停止",
|
|
427
|
+
"en": "👋 Server stopped",
|
|
428
|
+
},
|
|
429
|
+
"server.listening_all": {
|
|
430
|
+
"zh": "📡 监听所有网络接口",
|
|
431
|
+
"en": "📡 Listening on all interfaces",
|
|
432
|
+
},
|
|
433
|
+
"server.exposed_warning": {
|
|
434
|
+
"zh": "⚠️ 警告:已暴露到外网",
|
|
435
|
+
"en": "⚠️ Warning: exposed to external network",
|
|
436
|
+
},
|
|
437
|
+
"server.session_cleanup": {
|
|
438
|
+
"zh": "已清理 {n} 个过期会话/token",
|
|
439
|
+
"en": "Cleaned up {n} expired sessions/tokens",
|
|
440
|
+
},
|
|
441
|
+
"server.stats_error": {
|
|
442
|
+
"zh": "获取统计信息时出错",
|
|
443
|
+
"en": "Error fetching statistics",
|
|
444
|
+
},
|
|
445
|
+
|
|
446
|
+
# ── 邮件 ──
|
|
447
|
+
"email.welcome_subject": {
|
|
448
|
+
"zh": "欢迎加入 gitinstall",
|
|
449
|
+
"en": "Welcome to gitinstall",
|
|
450
|
+
},
|
|
451
|
+
"email.reset_subject": {
|
|
452
|
+
"zh": "gitinstall 密码重置",
|
|
453
|
+
"en": "gitinstall Password Reset",
|
|
454
|
+
},
|
|
455
|
+
"email.welcome_greeting": {
|
|
456
|
+
"zh": "🎉 欢迎加入 gitinstall!",
|
|
457
|
+
"en": "🎉 Welcome to gitinstall!",
|
|
458
|
+
},
|
|
459
|
+
"email.register_success": {
|
|
460
|
+
"zh": "你已成功注册 gitinstall 账号。",
|
|
461
|
+
"en": "You have successfully registered a gitinstall account.",
|
|
462
|
+
},
|
|
463
|
+
"email.account_info": {
|
|
464
|
+
"zh": "你的账号信息:",
|
|
465
|
+
"en": "Your account information:",
|
|
466
|
+
},
|
|
467
|
+
"email.tier_free": {
|
|
468
|
+
"zh": "免费用户(每月 20 次计划生成)",
|
|
469
|
+
"en": "Free tier (20 plan generations per month)",
|
|
470
|
+
},
|
|
471
|
+
"email.start_using": {
|
|
472
|
+
"zh": "开始使用",
|
|
473
|
+
"en": "Get Started",
|
|
474
|
+
},
|
|
475
|
+
"email.forgot_password_hint": {
|
|
476
|
+
"zh": "如需找回密码,请在登录页点击「忘记密码」。",
|
|
477
|
+
"en": "To recover your password, click 'Forgot Password' on the login page.",
|
|
478
|
+
},
|
|
479
|
+
"email.auto_sent": {
|
|
480
|
+
"zh": "此邮件由 gitinstall 自动发送,无需回复。",
|
|
481
|
+
"en": "This email was sent automatically by gitinstall. No reply needed.",
|
|
482
|
+
},
|
|
483
|
+
"email.reset_title": {
|
|
484
|
+
"zh": "🔑 重置密码",
|
|
485
|
+
"en": "🔑 Reset Password",
|
|
486
|
+
},
|
|
487
|
+
"email.reset_request": {
|
|
488
|
+
"zh": "我们收到了你的密码重置请求。点击下方按钮设置新密码:",
|
|
489
|
+
"en": "We received your password reset request. Click the button below to set a new password:",
|
|
490
|
+
},
|
|
491
|
+
"email.reset_button": {
|
|
492
|
+
"zh": "重置密码",
|
|
493
|
+
"en": "Reset Password",
|
|
494
|
+
},
|
|
495
|
+
"email.reset_validity": {
|
|
496
|
+
"zh": "此链接 30 分钟内有效。如果不是你本人操作,请忽略此邮件。",
|
|
497
|
+
"en": "This link is valid for 30 minutes. If you didn't request this, please ignore.",
|
|
498
|
+
},
|
|
499
|
+
"email.reset_fallback": {
|
|
500
|
+
"zh": "如果按钮无法点击,请复制以下链接到浏览器:",
|
|
501
|
+
"en": "If the button doesn't work, copy this link to your browser:",
|
|
502
|
+
},
|
|
503
|
+
|
|
504
|
+
# ── Fetcher ──
|
|
505
|
+
"fetcher.not_found": {
|
|
506
|
+
"zh": "GitHub 上找不到该资源",
|
|
507
|
+
"en": "Resource not found on GitHub",
|
|
508
|
+
},
|
|
509
|
+
"fetcher.rate_limit": {
|
|
510
|
+
"zh": "RATELIMIT: GitHub API 频率超限",
|
|
511
|
+
"en": "RATELIMIT: GitHub API rate limit exceeded",
|
|
512
|
+
},
|
|
513
|
+
"fetcher.network_failed": {
|
|
514
|
+
"zh": "网络连接失败",
|
|
515
|
+
"en": "Network connection failed",
|
|
516
|
+
},
|
|
517
|
+
"fetcher.searching": {
|
|
518
|
+
"zh": " 📡 正在搜索 GitHub 上的 {repo}...",
|
|
519
|
+
"en": " 📡 Searching GitHub for {repo}...",
|
|
520
|
+
},
|
|
521
|
+
"fetcher.fetching_info": {
|
|
522
|
+
"zh": " 📡 获取 {owner}/{repo} 信息...",
|
|
523
|
+
"en": " 📡 Fetching {owner}/{repo} info...",
|
|
524
|
+
},
|
|
525
|
+
"fetcher.reading_readme": {
|
|
526
|
+
"zh": " 📖 读取 README...",
|
|
527
|
+
"en": " 📖 Reading README...",
|
|
528
|
+
},
|
|
529
|
+
"fetcher.detecting_deps": {
|
|
530
|
+
"zh": " 🔍 检测依赖文件...",
|
|
531
|
+
"en": " 🔍 Detecting dependency files...",
|
|
532
|
+
},
|
|
533
|
+
"fetcher.cloning": {
|
|
534
|
+
"zh": " 📥 git clone --depth 1 {owner}/{repo}...",
|
|
535
|
+
"en": " 📥 git clone --depth 1 {owner}/{repo}...",
|
|
536
|
+
},
|
|
537
|
+
"fetcher.local_analysis": {
|
|
538
|
+
"zh": " 🔍 本地分析项目文件...",
|
|
539
|
+
"en": " 🔍 Analyzing local project files...",
|
|
540
|
+
},
|
|
541
|
+
|
|
542
|
+
# ── Autopilot ──
|
|
543
|
+
"autopilot.title": {
|
|
544
|
+
"zh": "🚗 自动驾驶",
|
|
545
|
+
"en": "🚗 Autopilot",
|
|
546
|
+
},
|
|
547
|
+
"autopilot.progress": {
|
|
548
|
+
"zh": "🚗 自动驾驶 [{current}/{total}] 安装:{identifier}",
|
|
549
|
+
"en": "🚗 Autopilot [{current}/{total}] Installing: {identifier}",
|
|
550
|
+
},
|
|
551
|
+
"autopilot.success": {
|
|
552
|
+
"zh": " ✅ 安装成功({duration}s)",
|
|
553
|
+
"en": " ✅ Installed successfully ({duration}s)",
|
|
554
|
+
},
|
|
555
|
+
"autopilot.install_failed": {
|
|
556
|
+
"zh": " ❌ 安装失败:{error}",
|
|
557
|
+
"en": " ❌ Installation failed: {error}",
|
|
558
|
+
},
|
|
559
|
+
"autopilot.user_interrupted": {
|
|
560
|
+
"zh": " ⏹️ 用户中断",
|
|
561
|
+
"en": " ⏹️ User interrupted",
|
|
562
|
+
},
|
|
563
|
+
"autopilot.exception": {
|
|
564
|
+
"zh": " ❌ 异常:{error}",
|
|
565
|
+
"en": " ❌ Exception: {error}",
|
|
566
|
+
},
|
|
567
|
+
|
|
568
|
+
# ── 环境检测 ──
|
|
569
|
+
"detect.chip": {
|
|
570
|
+
"zh": "芯片:{chip}",
|
|
571
|
+
"en": "Chip: {chip}",
|
|
572
|
+
},
|
|
573
|
+
"detect.wsl2": {
|
|
574
|
+
"zh": "WSL2:{status}",
|
|
575
|
+
"en": "WSL2: {status}",
|
|
576
|
+
},
|
|
577
|
+
"detect.gpu": {
|
|
578
|
+
"zh": "GPU:{gpu}",
|
|
579
|
+
"en": "GPU: {gpu}",
|
|
580
|
+
},
|
|
581
|
+
|
|
582
|
+
# ── Resilience ──
|
|
583
|
+
"resilience.preflight_found": {
|
|
584
|
+
"zh": "预检发现",
|
|
585
|
+
"en": "Preflight check found",
|
|
586
|
+
},
|
|
587
|
+
"resilience.missing_tool": {
|
|
588
|
+
"zh": "缺失工具",
|
|
589
|
+
"en": "Missing tool",
|
|
590
|
+
},
|
|
591
|
+
|
|
592
|
+
# ── Health ──
|
|
593
|
+
"health.ok": {
|
|
594
|
+
"zh": "服务正常",
|
|
595
|
+
"en": "Service healthy",
|
|
596
|
+
},
|
|
597
|
+
"health.degraded": {
|
|
598
|
+
"zh": "服务降级",
|
|
599
|
+
"en": "Service degraded",
|
|
600
|
+
},
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
def set_locale(locale: str):
|
|
605
|
+
"""
|
|
606
|
+
设置当前区域。
|
|
607
|
+
|
|
608
|
+
Args:
|
|
609
|
+
locale: 语言代码 ("zh", "en")
|
|
610
|
+
|
|
611
|
+
环境变量 GITINSTALL_LANG 优先。
|
|
612
|
+
"""
|
|
613
|
+
global _current_locale
|
|
614
|
+
with _locale_lock:
|
|
615
|
+
loc = locale.lower().split("_")[0].split("-")[0] # "zh_CN" -> "zh"
|
|
616
|
+
if loc in SUPPORTED_LOCALES:
|
|
617
|
+
_current_locale = loc
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
def get_locale() -> str:
|
|
621
|
+
"""获取当前区域"""
|
|
622
|
+
return _current_locale
|
|
623
|
+
|
|
624
|
+
|
|
625
|
+
def t(key: str, **kwargs) -> str:
|
|
626
|
+
"""
|
|
627
|
+
翻译消息键。
|
|
628
|
+
|
|
629
|
+
Args:
|
|
630
|
+
key: 消息键 (如 "auth.password_min")
|
|
631
|
+
**kwargs: 插值参数 (如 n=8)
|
|
632
|
+
|
|
633
|
+
Returns:
|
|
634
|
+
翻译后的字符串。若键不存在,返回键名本身。
|
|
635
|
+
"""
|
|
636
|
+
msg_entry = _MESSAGES.get(key)
|
|
637
|
+
if not msg_entry:
|
|
638
|
+
return key
|
|
639
|
+
|
|
640
|
+
text = msg_entry.get(_current_locale) or msg_entry.get(DEFAULT_LOCALE, key)
|
|
641
|
+
|
|
642
|
+
if kwargs:
|
|
643
|
+
try:
|
|
644
|
+
text = text.format(**kwargs)
|
|
645
|
+
except (KeyError, IndexError):
|
|
646
|
+
pass # 插值失败时返回原文
|
|
647
|
+
|
|
648
|
+
return text
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
def register_messages(messages: dict[str, dict[str, str]]):
|
|
652
|
+
"""
|
|
653
|
+
注册额外的消息条目(供插件/扩展模块使用)。
|
|
654
|
+
|
|
655
|
+
Args:
|
|
656
|
+
messages: {"msg.key": {"zh": "中文", "en": "English"}, ...}
|
|
657
|
+
"""
|
|
658
|
+
_MESSAGES.update(messages)
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
# ── 初始化:从环境变量读取语言 ──
|
|
662
|
+
_env_lang = os.environ.get("GITINSTALL_LANG", "")
|
|
663
|
+
if _env_lang:
|
|
664
|
+
set_locale(_env_lang)
|