chinese2english/patch-plugins.py

371 lines
14 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
import os
import re
import shutil
import sys
# Comprehensive dictionary mapping Chinese UI phrases to idiomatic English
UI_TRANSLATIONS = {
# DSH Market & Plugins
"插件市场": "Plugin Marketplace",
"插件市场设置": "Marketplace Settings",
"全部插件": "All Plugins",
"已安装插件": "Installed Plugins",
"已安装": "Installed",
"未安装": "Not Installed",
"推荐": "Featured",
"热门": "Popular",
"最新": "Recent",
"主题": "Themes",
"收藏": "Favorites",
"发现": "Discover",
"搜索插件": "Search plugins...",
"搜索插件...": "Search plugins...",
"搜索插件名称或作者": "Search by plugin name or author...",
"逛一逛,点一下,装好。": "Browse, click, and install.",
"下载区域": "Download Region",
"全球": "Global",
"中国大陆": "China Mainland",
"从 npm 和 GitHub 官方源下载。": "Download from official npm and GitHub sources.",
"中国大陆访问更快。仅改变下载线路,插件来源不变。": "Faster in China. Only changes CDN routing; source is identical.",
"GitHub 加速": "GitHub Mirror",
"自动选择可用线路,失败时才切换。": "Automatically selects available mirror, falls back on failure.",
"自定义": "Custom",
"优先使用自定义线路,失败后仍会尝试直连。": "Uses custom mirror first, falls back to direct connection.",
"由环境变量 DSHM_GITHUB_PROXY 管理,界面中不可修改。": "Managed by DSHM_GITHUB_PROXY environment variable.",
"构建环境变量": "Build Environment Variables",
"保存并重启": "Save & Restart",
"保存当前状态": "Save Current State",
"保存环境变量": "Save Environment Variables",
"保持现在的版本": "Keep Current Version",
"查看插件市场版本与设置。": "View marketplace version and settings.",
"更新会下载新版本,重启后生效。": "Update will download the new version; takes effect upon restart.",
"这份市场由桌面端安装,新版本请在桌面端更新。": "Installed via desktop app; please update from the desktop client.",
"已下载完成。重启 DeepSeek Harness 后新版本才会生效——页面会先显示新版本号。": "Download complete. Restart DeepSeek Harness to activate the update.",
"一键安装": "Install",
"一键更新": "Update",
"正在安装": "Installing...",
"正在下载": "Downloading...",
"安装中": "Installing...",
"更新中": "Updating...",
"下载中": "Downloading...",
"卸载中": "Uninstalling...",
"安装": "Install",
"卸载": "Uninstall",
"更新": "Update",
"重试": "Retry",
"已是最新版本": "Up to date",
"有新版本": "Update Available",
"发现新版本": "New version available",
"最新版本": "Latest Version",
"当前版本": "Current Version",
"版本": "Version",
"作者": "Author",
"下载量": "Downloads",
"评分": "Rating",
"大小": "Size",
"依赖": "Dependencies",
"依赖信息": "Dependency Info",
"依赖警告": "Dependency Warnings",
"依赖风险": "Dependency Risks",
"依赖版本不匹配": "Dependency version mismatch",
"仍然安装": "Install Anyway",
"仍然更新": "Update Anyway",
"全选": "Select All",
"全不选": "Deselect All",
"全部更新": "Update All",
"上一页": "Previous Page",
"下一页": "Next Page",
"上一张": "Previous",
"下一张": "Next",
"查看详情": "View Details",
"查看仓库": "View Repository",
"查看说明": "View Documentation",
"问题反馈": "Issues",
"使用说明": "Instructions",
"全屏浏览": "Fullscreen",
"恢复自动": "Restore Auto",
"HTTPS 加速前缀": "HTTPS Mirror Prefix",
"上传备份": "Upload Backup",
"备份": "Backup",
"恢复": "Restore",
"清除": "Clear",
# Actions & Buttons
"创建技能": "Create Skill",
"创建新技能": "Create Skill",
"新建技能": "New Skill",
"立即创建": "Create Now",
"导入技能": "Import Skill",
"导出技能": "Export Skill",
"导入": "Import",
"导出": "Export",
"刷新": "Refresh",
"检查更新": "Check Updates",
"正在检查更新…": "Checking for updates...",
"正在检查更新...": "Checking for updates...",
"检查并更新": "Check & Update",
"管理更新": "Manage Updates",
"立即更新": "Update Now",
"确认更新": "Confirm Update",
"回滚": "Rollback",
"确认回滚": "Confirm Rollback",
"移到回收站": "Move to Trash",
"移入回收站": "Move to Trash",
"永久删除": "Delete Forever",
"清空回收站": "Empty Trash",
"删除": "Delete",
"启用": "Enable",
"停用": "Disable",
"已启用": "Enabled",
"已停用": "Disabled",
"全部启用": "Enable All",
"全部停用": "Disable All",
"启停来源": "Toggle Source",
"启停技能": "Toggle Skill",
"更多": "More",
"取消": "Cancel",
"保存": "Save",
"关闭": "Close",
"确定": "OK",
"复制": "Copy",
"已复制": "Copied",
"复制成功": "Copied",
"搜索": "Search",
"选择文件": "Choose File",
"选择文件夹": "Choose Folder",
"设置": "Settings",
# Skills Manager Concepts
"技能管理": "Skills Manager",
"技能管理器": "Skills Manager",
"技能": "Skills",
"技能列表": "Skills List",
"已安装技能": "Installed Skills",
"可用技能": "Available Skills",
"发现技能": "Discover Skills",
"仓库订阅": "Repositories",
"仓库管理": "Repositories",
"技能来源": "Skill Sources",
"全局技能": "Global Skills",
"项目技能": "Project Skills",
"公共 Agent": "Shared Agent",
"项目 Agent": "Project Agent",
"项目 Skills": "Project Skills",
"会话技能": "Session Skills",
"回收站": "Trash",
"诊断异常": "Diagnostics",
"异常诊断": "Diagnostics",
"源文件只读": "Read-only",
"只读": "Read-only",
"创建位置": "Location",
"全局 DSH": "Global DSH",
"项目 DSH": "Project DSH",
"DSH 技能": "DSH Skills",
"全部来源": "All Sources",
"全部状态": "All Statuses",
"全部": "All",
"调用状态": "Invocation Status",
"状态": "Status",
"来源": "Source",
"被覆盖": "Shadowed",
"名称": "Name",
"类型": "Type",
"操作": "Actions",
"详情": "Details",
"描述": "Description",
"简介": "Description",
"正文": "Body",
"源文件": "Source File",
"更新时间": "Updated",
"创建时间": "Created",
"删除于": "Deleted at",
"来源:": "Source: ",
"正在加载技能…": "Loading skills...",
"正在加载…": "Loading...",
"加载中…": "Loading...",
"没有匹配的技能。": "No matching skills.",
"没有匹配的技能": "No matching skills",
"该来源目录不存在或暂时没有技能。": "This source directory does not exist or has no skills.",
"回收站为空。": "Trash is empty.",
"回收站为空": "Trash is empty",
"暂无技能": "No skills available",
"暂无数据": "No data available",
"未提供简介": "No description provided",
"未发现诊断问题。": "No diagnostic issues found.",
"拖拽技能到此处": "Drop skill here",
"支持 .zip、技能文件夹或单个 SKILL.md": "Supports .zip, a skill folder, or single SKILL.md",
"文件要求": "File Requirements",
"压缩包或文件夹需包含 SKILL.md": "Archives and folders must contain SKILL.md",
"SKILL.md 需包含 YAML 格式的技能名称和描述": "SKILL.md must include YAML name and description",
"导入时复制完整内容,不修改原始来源": "Import copies full content and never modifies original source",
"导入到全局 DSH": "Import to global DSH",
"移除所选内容": "Remove selection",
"请选择 .zip 或单个 SKILL.md。": "Please choose a .zip archive or single SKILL.md.",
"所选文件夹中没有找到 SKILL.md。": "No SKILL.md found in the selected folder.",
"例如 code-review-helper": "e.g. code-review-helper",
"一句话说明什么时候使用": "One sentence describing when to use it",
"正文(Markdown)": "Body (Markdown)",
"写下技能要遵循的指令、步骤和边界…": "Write the instructions, steps, and boundaries...",
"创建和导入均保存到全局 DSH,跨项目可用。": "Created and imported skills are saved to global DSH and available across projects.",
# Models & Codex UI
"专家": "Experts",
"专家管理": "Expert Manager",
"个人": "Personal",
"主菜单": "Main Menu",
"代码审查": "Code Review",
"任务": "Tasks",
"任务总览": "Tasks Overview",
"任务设置": "Task Settings",
"了解项目结构": "Inspect Project Structure",
"模型": "Models",
"模型设置": "Model Settings",
"通用设置": "General Settings",
"外观设置": "Appearance",
"语言设置": "Language",
"快捷键": "Shortcuts",
"关于": "About",
"语言": "Language",
"简体中文": "Simplified Chinese",
"英文": "English",
"深色模式": "Dark Mode",
"浅色模式": "Light Mode",
"跟随系统": "Follow System",
"会话": "Sessions",
"新会话": "New Session",
"历史会话": "History",
"工作区": "Workspace",
"暂无会话": "No sessions",
"发送": "Send",
"停止生成": "Stop generating",
"重新生成": "Regenerate",
"耗时": "Duration",
"步骤": "Steps",
"轮次": "Turns",
"退出": "Exit",
"重启": "Restart",
# Usage & Billing
"今日": "Today",
"估算成本": "Estimated Cost",
"上下文": "Context",
"上下文缓存命中率": "Context Cache Hit Rate",
"不可用": "Unavailable",
"不支持": "Not Supported",
"中文": "Chinese",
"从公开日历载入": "Load from Public Calendar",
"工作区用量": "Workspace Usage",
"模型用量": "Model Usage",
"供应商用量": "Provider Usage",
"供应商 / 模型": "Provider / Model",
"工作区别名": "Workspace Aliases",
"暂无工作区": "No workspaces yet",
"项目别名": "Project Alias",
"回车保存单个;清空别名还原文件夹名": "Press Enter to save; clear alias to restore folder name",
"全部保存": "Save All",
"一键领取": "Claim with 1-Click",
"上次检查": "Last Checked",
"上游请求": "Upstream Requests",
"上移": "Move Up",
"下移": "Move Down",
"不可驱动": "Cannot Drive",
"中继密钥": "Relay API Key",
"中国版端点与模型池": "China Endpoints & Model Pool",
}
# Merge dynamically generated dshmarket dictionary if present
dict_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "dshmarket_dict.json")
if os.path.exists(dict_path):
import json
with open(dict_path, "r", encoding="utf-8") as f:
extra_dict = json.load(f)
UI_TRANSLATIONS.update(extra_dict)
# Sort translations by descending string length so compound sentences replace first
SORTED_KEYS = sorted(UI_TRANSLATIONS.keys(), key=lambda k: -len(k))
TARGET_FILES = [
"/home/oiupoyt/.dsh/profiles/web/node_modules/dshmarket/client/client.js",
"/home/oiupoyt/.dsh/profiles/web/node_modules/dshmarket/lib/routes.js",
"/home/oiupoyt/.dsh/profiles/web/node_modules/@michengai/dsh-skills-manager/lib/client.js",
"/home/oiupoyt/.dsh/profiles/web/node_modules/@michengai/dsh-skills-manager/lib/core.js",
"/home/oiupoyt/.dsh/profiles/web/node_modules/@michengai/dsh-codex-ui/lib/client.js",
"/home/oiupoyt/.dsh/profiles/web/node_modules/dsh-all-usage/lib/client.js",
"/home/oiupoyt/Downloads/dsh-our-free-model/client.js",
"/home/oiupoyt/Downloads/dsh-our-free-model/index.js",
]
def patch_file(path):
if not os.path.exists(path):
print(f"Skipping absent: {path}")
return 0
backup_path = path + ".bak-c2e"
if not os.path.exists(backup_path):
shutil.copy2(path, backup_path)
print(f"Backed up: {path} -> {backup_path}")
with open(path, "r", encoding="utf-8", errors="ignore") as f:
content = f.read()
original_len = len(content)
replacements = 0
# 1. Structural runtime patches
if "dshmarket" in path and "client.js" in path:
# Force dshmarket lang to "en"
pattern = r'const lang = String\(localeSnap\.active\)\.toLowerCase\(\)\.startsWith\("zh"\) \? "zh" : "en";'
if re.search(pattern, content):
content = re.sub(pattern, 'const lang = "en";', content)
replacements += 1
if "dsh-skills-manager" in path and "client.js" in path:
# Force skills-manager to use en dictionary
if "Object.assign(yg.zh,Sg.zh)" in content:
content = content.replace("Object.assign(yg.zh,Sg.zh)", "Object.assign(yg.zh,Sg.en);yg.zh=yg.en")
replacements += 1
if "s=i.toLowerCase().startsWith(\"zh\")?e.zhName:e.enName" in content:
content = content.replace("s=i.toLowerCase().startsWith(\"zh\")?e.zhName:e.enName", "s=e.enName")
replacements += 1
# 2. String literal replacements
for zh in SORTED_KEYS:
en = UI_TRANSLATIONS[zh]
# Replace double quoted
target_dq = f'"{zh}"'
if target_dq in content:
count = content.count(target_dq)
en_clean_dq = en.replace('\\', '\\\\').replace('"', '\\"')
content = content.replace(target_dq, f'"{en_clean_dq}"')
replacements += count
# Replace single quoted
target_sq = f"'{zh}'"
if target_sq in content:
count = content.count(target_sq)
en_clean_sq = en.replace('\\', '\\\\').replace("'", "\\'")
content = content.replace(target_sq, f"'{en_clean_sq}'")
replacements += count
with open(path, "w", encoding="utf-8") as f:
f.write(content)
print(f"Patched {os.path.basename(path)}: {replacements} strings replaced ({len(content)} bytes)")
return replacements
def main():
print("=" * 60)
print("Direct Plugin Patching: Converting Chinese UI into English")
print("=" * 60)
total_patches = 0
for path in TARGET_FILES:
total_patches += patch_file(path)
print("=" * 60)
print(f"Total string replacements applied across plugins: {total_patches}")
print("=" * 60)
if __name__ == "__main__":
main()