scripts/gen_i18n_dict.py
Rama main · réplica de lectura del repositorio original.
#!/usr/bin/env python3
"""生成管理页 i18n 字典追加块并插入 scout/web/static/i18n.js"""
import json
import re, io, sys
# (zh, en) 翻译映射 —— 覆盖 11 个管理页静态文本 + JS 纯字符串
TRANS = [
("'+ 添加'", None), # 占位符,实际由下面覆盖
]
# 主翻译表
M = {
"0 核心": "0 cores",
"CPU 使用率": "CPU Usage",
"CPU 使用率 (%)": "CPU Usage (%)",
"AI 插件生成器 - Scout": "AI Plugin Builder - Scout",
"AI 正在生成插件代码,请稍候...": "AI is generating plugin code, please wait...",
"AI 生成的插件": "AI-generated plugin",
"EventBus · 模块间松耦合通信": "EventBus · loose-coupling inter-module communication",
"IM 渠道目标": "IM channel target",
"JSON 格式错误": "Invalid JSON format",
"SKILL.md 内容已复制": "SKILL.md content copied",
"Webhook 管理 · Scout Agent": "Webhook Management · Scout Agent",
"auto — 只读放行,写操作需白名单(推荐)": "auto — read-only allowed, writes require whitelist (recommended)",
"created 新增": "created",
"deleted 删除": "deleted",
"event 触发器": "event trigger",
"modified 修改": "modified",
"never — 全部放行(危险命令仍硬拦截)": "never — allow all (dangerous commands still blocked)",
"prompt — 白名单外拒绝+通知(保守)": "prompt — reject non-whitelisted + notify (conservative)",
"shell 命令正则白名单(逗号分隔)": "shell command regex whitelist (comma-separated)",
"writes — 文件写放行,高危需白名单": "writes — file writes allowed, high-risk needs whitelist",
"← 返回首页": "← Back to Home",
"← 选择一个会话查看执行时间线": "← Select a session to view the execution timeline",
"⏳ 安装中...": "⏳ Installing...",
"⏳ 搜索中...": "⏳ Searching...",
"⏳ 生成中...": "⏳ Generating...",
"⚠ 图片不会被识读": "⚠ Images will not be read",
"⚡ 触发方式": "⚡ Trigger type",
"✅ 已安装": "✅ Installed",
"✓ 已保存": "✓ Saved",
"✓ 配置格式正确": "✓ Config format is valid",
"✨ 生成插件代码": "✨ Generate plugin code",
"❌ 停止": "❌ Stopped",
"➕ 创建插件": "➕ Create Plugin",
"下午好!希望您今天过得愉快!": "Good afternoon! Hope you have a nice day!",
"个可复用方案": "reusable solutions",
"主模型不收图(交视觉模型识图)": "Main model won't take images (use a vision model)",
"事件处理失败的记录": "Records of failed event processing",
"事件总线 · Scout Agent": "Event Bus · Scout Agent",
"事件流": "Event stream",
"事件类型:": "Event type:",
"事件触发器": "Event trigger",
"事件触发(订阅 EventBus 事件)": "Event trigger (subscribe to EventBus events)",
"今日": "Today",
"从网上搜到的 Skill(SKILL.md)安装到这里,对话时自动触发": "Skills found online (SKILL.md) install here and trigger automatically in conversation",
"仓库根地址": "Repository root URL",
"任务完成": "Task completed",
"任务异常": "Task error",
"作者:": "Author:",
"你好": "Hello",
"使用 SSL/TLS": "Use SSL/TLS",
"保存偏好": "Save preferences",
"保存后插件会自动重新加载": "Plugins auto-reload after saving",
"保存失败:": "Save failed:",
"保存策略": "Save policy",
"保存配置失败": "Failed to save config",
"保存配置失败:": "Failed to save config:",
"先输入功能描述,再搜索现成方案": "Enter a feature description first, then search existing solutions",
"全年": "Full year",
"全部事件": "All events",
"关键词-响应映射配置": "Keyword-response mapping config",
"关键词插件": "Keyword plugin",
"关闭": "Close",
"关闭后所有跨渠道推送暂停": "Cross-channel push pauses when off",
"关闭视觉处理": "Disable vision",
"其他": "Other",
"内存使用率": "Memory Usage",
"内存使用率 (%)": "Memory Usage (%)",
"切换插件状态失败:": "Failed to toggle plugin state:",
"创建一个": "Create a",
"前往": "Go to",
"加载技能失败:": "Failed to load skills:",
"加载插件失败": "Failed to load plugins",
"加载插件失败:": "Failed to load plugins:",
"加载配置失败": "Failed to load config",
"加载配置失败:": "Failed to load config:",
"危险操作时推送通知": "Push notification on dangerous operations",
"卸载失败": "Uninstall failed",
"卸载失败:": "Uninstall failed:",
"去设置": "Open settings",
"去重窗口 (秒)": "Deduplication window (sec)",
"反思": "Reflection",
"发送测试通知": "Send test notification",
"可选,用于重要通知的邮件备份": "Optional, email backup for important notifications",
"启动监听": "Start listening",
"启用通知推送": "Enable notification push",
"图片将直接发给当前模型": "Images go straight to the current model",
"图片已转成文字描述": "Images were converted to text descriptions",
"在任务模板中使用占位符引用文件信息,例如:": "Use placeholders in task templates to reference file info, e.g.:",
"在左侧添加要监听的目录(支持递归)。": "Add directories to watch on the left (recursive supported).",
"基础模板": "Basic template",
"填成与主模型一样的名字 = 声明「主模型自己能看图」,图片将直接发给它(自定义模型最常用)。": "Enter the same name as the main model to declare native vision — images go straight to it (most common choice for custom models).",
"安装失败 (HTTP": "Install failed (HTTP",
"安装失败:": "Install failed:",
"安装成功!": "Install succeeded!",
"安装超时(仓库可能过大或网络慢)": "Install timeout (repo may be too large or network slow)",
"定时触发": "Scheduled trigger",
"实时监控 Scout Agent 运行状态": "Real-time monitoring of Scout Agent status",
"实测不收图片": "Tested: rejects images",
"实测能否看图": "Test vision",
"实测能看图": "Tested: can see images",
"审批策略 approval_policy": "Approval policy (approval_policy)",
"工具": "Tools",
"工具白名单(逗号分隔,空=不限)": "Tool whitelist (comma-separated, empty=unlimited)",
"工具类型: 0": "Tool types: 0",
"工具调用": "Tool calls",
"工具黑名单": "Tool blacklist",
"已加载": "Loaded",
"已卸载": "Unloaded",
"已取消:插件创建需要密码确认": "Cancelled: plugin creation requires password confirmation",
"已复制:": "Copied:",
"已实测:不收图片": "Tested: rejects images",
"已实测:能看图": "Tested: can see images",
"已禁用": "Disabled",
"已选中,请手动复制 (Ctrl+C)": "Selected, please copy manually (Ctrl+C)",
"帮助": "Help",
"常用字段": "Common fields",
"平均延迟": "Avg latency",
"建议使用验证功能检查配置": "Use the validate feature to check config",
"当前模型不直接看图,将由": "This model can't see images directly —",
"当前配置无可用视觉模型": "no vision model is available in the current config",
"总 Token": "Total Tokens",
"总 Token 消耗": "Total token usage",
"总会话数: 0": "Total sessions: 0",
"总插件数": "Total plugins",
"总调用次数": "Total calls",
"您好!有什么可以帮助您的吗?": "Hello! How can I help you?",
"我可以帮您解答问题、完成任务等。": "I can answer questions, complete tasks, etc.",
"手动触发": "Manual trigger",
"技能详情": "Skill details",
"按模型统计": "By model",
"按类型开关": "Toggle by type",
"捕获的文件变化(可配合触发器实现自动处理)": "Captured file changes (can auto-process with triggers)",
"探测中…": "Testing…",
"探测失败": "Vision test failed",
"探测请求失败": "Vision test request failed",
"控制哪些类型的通知值得推送": "Control which notification types are worth pushing",
"推送历史": "Push history",
"推送规则": "Push rules",
"描述你想要的插件功能,AI 会自动生成完整的插件代码": "Describe the plugin feature you want; AI will generate complete plugin code",
"提醒": "Reminder",
"插件不存在": "Plugin not found",
"插件代码不能为空": "Plugin code cannot be empty",
"插件代码生成成功!": "Plugin code generated!",
"插件保存成功!": "Plugin saved!",
"插件名称只能包含小写字母、数字和下划线,且必须以字母开头": "Plugin name must contain only lowercase letters, digits, underscores and start with a letter",
"插件管理 - Scout Agent": "Plugin Management - Scout Agent",
"插件配置": "Plugin config",
"插件配置编辑": "Plugin config editor",
"插件配置编辑 - Scout Agent": "Plugin Config Editor - Scout Agent",
"搜索失败:": "Search failed:",
"操作失败": "Operation failed",
"敏感词1": "Sensitive word 1",
"敏感词2": "Sensitive word 2",
"敏感词过滤配置": "Sensitive word filter config",
"文件监听 · Scout Agent": "File Watcher · Scout Agent",
"新建 Webhook": "New Webhook",
"新建定时任务": "New scheduled task",
"新建触发器": "New trigger",
"无人值守策略": "Unattended policy",
"无描述": "No description",
"无法判定": "Cannot determine",
"早上好!新的一天开始了!": "Good morning! A new day begins!",
"时间段问候配置": "Time-of-day greeting config",
"晚上好!注意休息哦!": "Good evening! Rest well!",
"暂无事件": "No events",
"更新 Agent 状态失败:": "Failed to update agent status:",
"更新插件状态失败:": "Failed to update plugin state:",
"更新系统状态失败:": "Failed to update system status:",
"最低级别": "Minimum level",
"最多保留 100 条": "Keep at most 100 entries",
"最多保留 500 条": "Keep at most 500 entries",
"最近 30 天": "Last 30 days",
"最近会话(按 trace 聚合)": "Recent sessions (aggregated by trace)",
"最近调用记录": "Recent call records",
"未加载": "Not loaded",
"未指定插件名称": "Plugin name not specified",
"未知": "Unknown",
"未能证实(疑似网关丢弃图片)": "Unverified (the gateway may drop images silently)",
"未送达": "Not delivered",
"本周": "This week",
"格式化": "Format",
"格式化成功": "Formatted",
"模型监控": "Model Monitor",
"模型监控 · Scout Agent": "Model Monitor · Scout Agent",
"每日 Token 消耗趋势": "Daily token usage trend",
"注意事项": "Notes",
"活跃会话": "Active sessions",
"点击「启动监听」,agent 会持续感知该目录的文件新增/修改/删除。": "Click \"Start listening\"; the agent keeps sensing file add/modify/delete in this directory.",
"版本:": "Version:",
"状态:": "Status:",
"生成失败": "Generation failed",
"生成失败:": "Generation failed:",
"登录已过期,请重新登录": "Login expired, please log in again",
"监听目录": "Watch directories",
"目标": "Target",
"确定要重新加载所有插件吗?": "Reload all plugins?",
"确定要重置配置吗?这将恢复到上次保存的状态。": "Reset config? This restores the last saved state.",
"磁盘使用率": "Disk Usage",
"空配置,适合自定义": "Empty config, good for customization",
"端点/网络异常,无法判定": "Endpoint/network error — cannot determine",
"管理插件 →": "Manage plugins →",
"系统": "System",
"系统监控 - Scout Agent": "System Monitor - Scout Agent",
"级联触发(上游完成后执行)": "Cascade trigger (runs after upstream completes)",
"缓存命中": "Cache hit",
"缺少 Pillow,无法生成测试图": "Pillow missing — cannot build the test image",
"网络速率": "Network speed",
"能力靠猜,建议实测一次": "Capability is guessed here — run the test once",
"能看图(主模型直收)": "Can see images (sent to the main model)",
"自动化中心": "Automation Center",
"自动化中心 · Scout Agent": "Automation Center · Scout Agent",
"视觉模型": "Vision model",
"识图成文字": "will describe them as text instead",
"请先选择或填写模型": "Select or enter a model first",
"请输入插件功能描述": "Enter plugin feature description",
"请输入插件名称": "Enter plugin name",
"请输入登录密码以确认插件创建(写码操作需二次验证)": "Enter login password to confirm plugin creation (write operation needs second verification)",
"调用次数": "Call count",
"过滤插件": "Filter plugins",
"运行历史": "Run history",
"运行时间: 0 小时": "Uptime: 0 hours",
"运行观测 · Scout Agent": "Run Observer · Scout Agent",
"运行观测 →": "Run Observer →",
"运行观测时间线": "Run observer timeline",
"返回主页": "Back to home",
"返回插件列表": "Back to plugin list",
"选择上游触发器…": "Select upstream trigger...",
"通知中心 · Scout Agent": "Notification Center · Scout Agent",
"通知将主动推送到这些渠道": "Notifications are actively pushed to these channels",
"邮件推送 (SMTP)": "Email push (SMTP)",
"部分图片未识读": "Some images were not read",
"配置保存成功": "Config saved",
"配置已重置": "Config reset",
"配置文件 (config.json)": "Config file (config.json)",
"配置文件必须是有效的 JSON 格式": "Config file must be valid JSON",
"配置格式": "Config format",
"配置格式错误,无法保存": "Invalid config format, cannot save",
"配置格式错误,无法格式化": "Invalid config format, cannot format",
"配置模板": "Config template",
"配置说明": "Config description",
"配置错误会导致插件无法加载": "Config errors prevent plugins from loading",
"重新加载失败": "Reload failed",
"重新加载所有插件失败:": "Failed to reload all plugins:",
"重新加载插件失败:": "Failed to reload plugin:",
"重置": "Reset",
"鉴权失败,无法判定": "Auth failed — cannot determine",
"问候插件": "Greeting plugin",
"验证配置": "Validate config",
"(无内容)": "(empty)",
"(无描述)": "(no description)",
"(未记录,可修正配置后重试)": "(not recorded — fix the config and retry)",
",事件名填": ", fill in the event name",
"🌐 网页": "🌐 Web",
"👁️ 文件监听": "👁️ File Watch",
"👋 智能问候": "👋 Smart Greeting",
"💀 死信队列 (DLQ)": "💀 Dead Letter Queue (DLQ)",
"💡 提示": "💡 Tip",
"💬 帮助信息": "💬 Help",
"💻 系统资源": "💻 System Resources",
"💾 保存插件": "💾 Save Plugin",
"📄 SKILL.md 内容": "📄 SKILL.md Content",
"📅 日期查询": "📅 Date Query",
"📈 CPU 使用历史": "📈 CPU History",
"📈 内存使用历史": "📈 Memory History",
"📊 工具监控": "📊 Tool Monitor",
"📊 模板: 每日自我报告": "📊 Template: Daily Self Report",
"📊 系统监控": "📊 System Monitor",
"📋 复制全文": "📋 Copy All",
"📋 复制命令": "📋 Copy Command",
"📚 已安装技能": "📚 Installed Skills",
"📝 描述": "📝 Description",
"📝 描述插件功能": "📝 Describe Plugin Feature",
"📡 事件总线": "📡 Event Bus",
"📦 一键安装": "📦 One-click Install",
"📦 全网找到": "📦 Found Online",
"📰 模板: 每日资讯简报": "📰 Template: Daily News Brief",
"🔄 刷新数据": "🔄 Refresh",
"🔄 重新加载全部": "🔄 Reload All",
"🔄 重新生成": "🔄 Regenerate",
"🔍 先搜全网现成 Skill/插件": "🔍 Search Online for Ready-made Skills/Plugins",
"🔔 通知中心": "🔔 Notification Center",
"🔗 Webhook 管理": "🔗 Webhook Management",
"🔗 查看仓库": "🔗 View Repo",
"🔧 插件代码": "🔧 Plugin Code",
"🚫 广告过滤": "🚫 Ad Blocker",
"🤖 AI 插件生成器": "🤖 AI Plugin Builder",
"🤖 Agent 状态": "🤖 Agent Status",
"🧩 插件状态": "🧩 Plugin Status",
"🧩 插件管理": "🧩 Plugin Management",
# 模板拆分片段(__tpl/__t 需要的前后缀片段)
"运行时间: ": "Uptime: ",
" 分钟": " min",
" 核心": " cores",
"总会话数: ": "Total sessions: ",
"工具类型: ": "Tool types: ",
"已清空 ": "Cleared ",
" 条": " entries",
"✗ 配置格式错误: ": "✗ Invalid config format: ",
"近7天共": "Last 7 days: ",
"次运行": " runs",
"状态": "Status",
"作用域: ": "Scope: ",
"目录: ": "Directory: ",
"路径: ": "Path: ",
"去抖": "debounce",
"轮询": "poll",
"模板": "template",
"配置": "config",
" 配置": " Config",
"· 状态": "· status",
"版本: ": "Version: ",
"优先级: ": "Priority: ",
# 更多模板片段
"次": " runs",
" 次": " runs",
"次 · 最近": " runs · recent",
"步 ·": " steps ·",
"运行时间:": "Uptime:",
"分钟": " min",
"核心": " cores",
"总会话数:": "Total sessions:",
"工具类型:": "Tool types:",
"成功率": "Success rate",
"24h 对话": "24h conversations",
"成本": "Cost",
"⚡缓存": "⚡ cached",
"确定要卸载技能「": "Uninstall skill 「",
"」吗?": "」?",
"将删除 $SCOUT_DATA_DIR/skills/": "will delete $SCOUT_DATA_DIR/skills/",
" 目录": " directory",
"✗ 配置格式错误:": "✗ Invalid config format:",
"重新输入后可自动记忆": "re-enter to auto-remember",
"本地无记忆": "no local memory",
"已复制": "copied",
"目录": "directory",
"敏感词": "sensitive word",
# ── 管理页卡片混合短语(第4轮补充) ──
"触发 ": "Triggered ",
" 次运行": " runs",
"近7天共 ": "Last 7 days: ",
" 步": " steps",
" 次工具调用": " tool calls",
"执行事件流(": "Event flow (",
" 条)": " items)",
"验证证据(": "Verification evidence (",
")": ")",
"通过": "passed",
"未通过": "failed",
"最近 ": "recent ",
"事件 ": "Event ",
"上游 ": "Upstream ",
"运行": "Run",
"停用": "Disable",
"递归": "Recursive",
"仅顶层": "Top-level only",
"轮询 ": "Poll every ",
"去抖 ": "Debounce ",
"✕ 删除": "✕ Delete",
"新增": "Add",
"修改": "Modify",
"调用 ": "Called ",
" 次 · 最近 ": " times · recent ",
"复制 URL": "Copy URL",
"(未命名)": "(unnamed)",
"事件载荷": "Event payload",
"已推送": "Pushed",
"未推送": "Not pushed",
"已过滤": "Filtered",
"📧 邮件✓": "📧 Email✓",
"24h 对话 ": "24h conversations ",
"成功率 ": "Success rate ",
"输出:": "Output:",
"输入:": "Input:",
"错误: ": "Error: ",
"状态 ": "Status ",
"(空)": "(empty)",
"(无消息)": "(no message)",
"无 span 数据": "No span data",
"技能": "Skill",
"👁️ 详情": "👁️ Details",
"已启用": "Enabled",
"暂无描述": "No description",
"作者: ": "Author: ",
"关键词: ": "Keywords: ",
"正则: ": "Regex: ",
"已加载 ": "Loaded ",
" 模板": " template",
# ── index.html 静态残留(第4轮补充) ──
"恢复": "Restore",
"拒绝": "Rejected",
"执行中...": "Running...",
"内容:": "Content:",
"字段": "field",
"键": "key",
"响应": "response",
"否": "No",
"是": "Yes",
# ── index.html 动态 alert/confirm/toast(第5轮补充) ──
"请填写 ": "Please fill in ",
"启动失败: ": "Start failed: ",
"启动失败,请重试": "Start failed, please retry",
"确定要停止渠道 \"": "Stop channel \"",
"\" 吗?": "\"? ",
"确定要删除渠道 \"": "Delete channel \"",
"\" 吗?此操作不可撤销。": "\"? This action cannot be undone.",
" 超过 20MB 限制": " exceeds the 20MB limit",
"确定删除「": "Delete \"",
"已自动识别 ": "Auto-detected ",
" 个目标": " targets",
"确定要删除任务 \"": "Delete task \"",
"确定要删除知识页面 \"": "Delete knowledge page \"",
"天": "d",
"小时": "h",
"次运行/天": "runs/day",
"最高": "max",
# ── index.html 渲染器混合模板(第6轮补充) ──
"任务分解为 ": "Task breakdown: ",
" 个子任务,并行委派:": " subtasks, delegating in parallel: ",
"子任务 ": "Subtask ",
"执行工具 ": "Running tool ",
"步骤 ": "Step ",
" (累计 ": " (cumulative ",
"缓存 ": "Cache ",
"✅ 完成 · ": "✅ Done · ",
"步": " steps",
"❌ 错误: ": "❌ Error: ",
"未找到「": "No results for \"",
"」相关内容": "\"",
"调度器: ": "Scheduler: ",
"... 还有 ": "... and ",
"凝萃失败: ": "Distillation failed: ",
"当前登录用户:": "Current user: ",
"(密码已设置,修改后立即生效)": " (password set, effective immediately)",
" 个工具 ": " tools ",
" 页": " pages",
" 字符": " characters",
") 解析 ": ") parsing ",
"✅ 成功导入 ": "✅ Imported ",
" 个文件:": " files: ",
"部分成功:": "Partial success: ",
" 个文件已导入": " files imported",
"⚠️ 渲染失败: ": "⚠️ Render failed: ",
"搜索 \"": "Search \"",
"\" 找到 ": "\" found ",
" 条结果:": " results: ",
"· 有新版本 ": "· New version ",
"标记完成": "Mark complete",
"重新激活": "Reactivate",
"暂无 MCP 服务器": "No MCP servers",
"最后访问": "Last accessed",
"最低": "min",
"调用": "calls",
"花费": "spent",
# ── index.html textContent 动态文本(第6轮补充) ──
"⏳ 运行中...": "⏳ Running...",
"⚡ 无委派子任务(主代理直接执行)": "⚡ No delegated subtasks (main agent executes directly)",
"✅ 完成": "✅ Done",
"✅ 已完成": "✅ Completed",
"❌ 失败": "❌ Failed",
"❌ 请先填写自定义模型名或选择预设模型": "❌ Please enter a custom model name or select a preset model",
"两次输入的密码不一致": "Passwords do not match",
"完成": "Done",
"密码长度至少 6 位": "Password must be at least 6 characters",
"已保存": "Saved",
"未保存": "Unsaved",
"未知错误": "Unknown error",
"网络错误": "Network error",
"请输入用户名": "Please enter a username",
"首次使用,请设置账户": "First time use, please set up an account",
# ── index.html prompt 对话框(第6轮补充) ──
"目标标题:": "Target title:",
"目标描述 (可选):": "Target description (optional):",
"任务标题:": "Task title:",
"任务描述 (可选):": "Task description (optional):",
"请输入搜索关键词:": "Enter a search keyword:",
# ── index.html 渲染器动态模板/静态文本(第7轮补充) ──
"血缘加载失败: ": "Lineage load failed: ",
"进度: ": "Progress: ",
"任务: ": "Tasks: ",
"创建: ": "Created: ",
"耗时: ": "Duration: ",
"消息: ": "Message: ",
"状态: ": "Status: ",
"执行步骤 (": "Execution steps (",
"步骤: ": "Step: ",
"预算: ": "Budget: ",
"工具: ": "Tools: ",
"调度: ": "Schedule: ",
" | 上次运行: ": " | Last run: ",
"新会话标题": "New session title",
"血缘关系": "Lineage",
"分叉": "Branch",
"工具配置": "Tool configuration",
"登录认证": "Login authentication",
"启用登录密码": "Enable login password",
"确认密码": "Confirm password",
"搜索引擎源(支持多个)": "Search engine sources (multiple)",
"配置至少一个启用的源后": "After configuring at least one enabled source",
"编排中...": "Orchestrating...",
"无血缘记录": "No lineage records",
"子分支:": "Child branch:",
"向量模型": "Vector model",
"拖拽文件到此处,或": "Drag files here, or",
"点击选择": "click to select",
"导入成功": "Import successful",
"导入失败": "Import failed",
"构建知识图谱...": "Building knowledge graph...",
"文档": "Document",
"数据": "Data",
"未修改": "Unmodified",
"已注册工具": "Registered tools",
"暂无 Webhook": "No webhooks",
"插件": "Plugin",
"强制提取": "Force extraction",
"总成本": "Total cost",
"最近追踪": "Recent traces",
"尚未运行过凝萃": "Distillation has not run yet",
"开启后访问 Web 界面需要输入用户名和密码登录;默认关闭": "When enabled, accessing the Web UI requires a username and password login; disabled by default",
"最小对话数(低于此数跳过提取)": "Minimum conversations (below this, extraction is skipped)",
"支持 PDF、DOCX、Markdown、TXT、CSV、JSON、HTML、代码文件": "Supports PDF, DOCX, Markdown, TXT, CSV, JSON, HTML, and code files",
"用于\"回退到某条消息再分叉\":只复制到指定序号为止,之后从分支重新开始。": "For \"branching by reverting to a message\": only copies up to the specified sequence number, then restarts from the branch.",
# ── index.html 属性 title/placeholder(第7轮补充) ──
"任务与追踪": "Tasks & Tracking",
"工具与监控": "Tools & Monitoring",
"切换主题": "Toggle theme",
"切换界面语言 / Toggle UI language": "Toggle UI language",
"留空则自动生成 (会话标题 + fork)": "Leave empty to auto-generate (session title + fork)",
"留空 = 复制全部消息": "Leave empty = copy all messages",
"输入自定义模型名,回车确认(Esc 取消)": "Enter custom model name, press Enter to confirm (Esc to cancel)",
"登录用户名": "Login username",
"至少 6 位": "At least 6 characters",
"再次输入密码": "Re-enter password",
"复制": "Copy",
"重新生成": "Regenerate",
"输入要记住的内容...": "Enter content to remember...",
"类别标签 (可选)": "Category label (optional)",
"加载选中页面": "Load selected page",
"新建页面": "New page",
"标题": "Heading",
"粗体": "Bold",
"斜体": "Italic",
"代码": "Code",
"链接": "Link",
"列表": "List",
"引用": "Quote",
"在这里输入 Markdown 内容...": "Enter Markdown content here...",
"名称": "Name",
"删除此源": "Delete this source",
"命令": "Command",
"任务描述,如:总结最新消息": "Task description, e.g. summarize the latest messages",
"名称,如 本地 SearXNG": "Name, e.g. local SearXNG",
"URL(留空用默认端点;Google 需带 ?cx=你的ID)": "URL (leave empty for default endpoint; Google needs ?cx=yourID)",
"API Key(可选;searxng / duckduckgo 无需)": "API Key (optional; not needed for searxng / duckduckgo)",
"启用": "Enable",
"重要性": "Importance",
"访问次数": "Access count",
"创建时间": "Created",
"查看详情": "View details",
"删除": "Delete",
"删除任务": "Delete task",
"删除目标": "Delete goal",
"点击查看大图": "Click to view full image",
"编辑": "Edit",
"分叉此会话": "Fork this session",
"编辑标题": "Edit title",
"删除会话": "Delete session",
"对话": "conversations",
"输出": "output",
"输入": "input",
"摘要": "summary",
"详情": "details",
"查看": "view",
"安装": "install",
"卸载": "uninstall",
"禁用": "disable",
"保存": "save",
"取消": "cancel",
"确认": "confirm",
"重试": "retry",
"刷新": "refresh",
"加载中...": "Loading...",
"暂无数据": "No data",
"加载失败": "Load failed",
"加载失败: ": "Load failed: ",
"请求失败": "Request failed",
"成功": "success",
"失败": "failed",
"等待中": "pending",
"进行中": "running",
"已完成": "completed",
"已终止": "terminated",
"已跳过": "skipped",
"触发": "trigger",
"执行": "execute",
"上次执行": "last run",
"下次执行": "next run",
"启用状态": "enabled",
"更新时间": "updated",
"事件名称": "event name",
"事件数据": "event data",
"事件处理": "event processing",
"推送": "push",
"通知": "notify",
"忽略": "ignore",
"测试": "test",
"提交": "submit",
"预览": "preview",
"已复制到剪贴板": "copied to clipboard",
"确定": "OK",
"正在加载": "Loading",
"搜索": "search",
"清空": "clear",
"全部": "all",
"描述": "description",
"类型": "type",
"操作": "actions",
"数量": "count",
"时间": "time",
"日期": "date",
"内容": "content",
"路径": "path",
"文件": "file",
"大小": "size",
"在线": "online",
"离线": "offline",
# watcher / plugin-builder / plugin-config 补充
"添加": "Add",
"添加失败: ": "Add failed: ",
"已添加监听目录": "Watch directory added",
"- 是否启用插件": "- whether the plugin is enabled",
"- 优先级 (0-100)": "- priority (0-100)",
"- 关键词列表": "- keyword list",
"- 响应映射": "- response mapping",
"」吗?\n将删除 $SCOUT_DATA_DIR/skills/": "」? \nwill delete $SCOUT_DATA_DIR/skills/",
"1. 可以编辑生成的代码进行自定义调整": "1. You can edit the generated code for customization",
"2. 插件名称只能包含小写字母、数字和下划线": "2. Plugin name may only contain lowercase letters, digits and underscores",
"3. 保存后的插件会自动启用,可在插件管理页面查看": "3. Saved plugins auto-enable; view them in Plugin Management",
"该会话没有追踪数据": "No trace data for this session",
" 轮": " rounds",
"轮": " rounds",
"删除定时任务「": "Delete scheduled task 「",
"」?": "」?",
"(成功率": "(success rate",
"%)": "%)",
"运行结果: ": "Run result: ",
# ── 管理页(automation/notify/plugins/watcher/webhooks/events)第8轮补充 ──
"名称,如: PR审查": "Name, e.g. PR review",
"事件名,如: tool.complete / file": "Event name, e.g. tool.complete / file",
"过滤器JSON(可选),如 {\"source\":\"cron:*\"}": "Filter JSON (optional), e.g. {\"source\":\"cron:*\"}",
"任务模板,支持 {{event.xxx}} 占位符。如: 处理新文件 {{event.file_path}}": "Task template supporting {{event.xxx}} placeholders. E.g. handle new file {{event.file_path}}",
"验证规则JSON(可选),如 [{\"type\":\"contains\",\"value\":[\"完成\"]}]": "Verify rule JSON (optional), e.g. [{\"type\":\"contains\",\"value\":[\"done\"]}]",
"冷却秒数(防抖),默认0": "Cooldown seconds (debounce), default 0",
"调度,如: 每30分钟 / 每天09:00": "Schedule, e.g. every 30 minutes / daily 09:00",
"任务描述(给 Agent 执行)": "Task description (for Agent to execute)",
"收件人邮箱": "Recipient email",
"SMTP 主机 (如 smtp.qq.com)": "SMTP host (e.g. smtp.qq.com)",
"端口 (465)": "Port (465)",
"SMTP 账号": "SMTP account",
"SMTP 密码/授权码": "SMTP password / auth code",
"渠道名 (如 telegram)": "Channel name (e.g. telegram)",
"目标 ID / 群组": "Target ID / group",
"例如:创建一个插件,当用户说“帮助”时显示帮助信息": "E.g. create a plugin that shows help when the user says \"help\"",
"插件名称(小写字母和下划线,如:my_plugin)": "Plugin name (lowercase letters and underscores, e.g. my_plugin)",
"生成的代码将显示在这里...": "Generated code will be shown here...",
"绝对路径,如 /data/inbox": "Absolute path, e.g. /data/inbox",
"名称(可选,如 部署通知)": "Name (optional, e.g. deploy notification)",
"任务描述(必填)——收到请求时 Agent 执行的任务。支持 {{event.xxx}} 占位符引用请求体字段。": "Task description (required) - task executed by Agent when request received. Supports {{event.xxx}} placeholders referencing request body fields.",
"重新加载": "Reload",
"查看配置": "View config",
"编辑配置": "Edit config",
"测试触发": "Test trigger",
"删除该触发器?": "Delete this trigger?",
"确认移除该监听目录?": "Remove this watch directory?",
"确认删除该 Webhook?": "Delete this Webhook?",
"确认清空死信队列?": "Clear dead-letter queue?",
"确认清空全部推送历史?": "Clear all push history?",
# ── index.html 多模型类型独立厂商(第9轮补充) ──
"主服务商": "Main provider",
"跟随主服务商": "Follow main provider",
"(可选独立服务商)": "(optional independent provider)",
"(文本对话与工具调用)": "(text chat & tool use)",
"(使用主服务商的 API Key)": "(uses main provider's API Key)",
# ── 服务商集中配置(第10轮补充) ──
"服务商 API 配置": "Provider API Config",
"(集中配置各服务商的 API Key 与 Base URL)": "(Centralized API Key & Base URL config for all providers)",
"保存服务商配置": "Save Provider Config",
"在此统一配置各服务商的 API Key 与 Base URL,文本/视觉/图像模型模块只需选择服务商和模型即可自动使用对应凭据。": "Configure API Keys & Base URLs for all providers here; the text/vision/image sections only need to select a provider and model.",
"✅ 该服务商已配置 API Key": "✅ API Key configured for this provider",
"⚠️ 该服务商未配置 API Key,请在上方\"服务商 API 配置\"中填写": "⚠️ No API Key for this provider; fill it in the \"Provider API Config\" section above",
"已保存,留空则不修改": "Saved; leave blank to keep unchanged",
"Base URL": "Base URL",
"未填写任何服务商凭据": "No provider credentials entered",
"服务商配置已保存": "Provider config saved",
" 个已保存,": " saved, ",
" 个失败": " failed",
"已配置": "Configured",
}
def esc(s):
# 转义为 JS 字符串字面量:\\ 与 " 之外,还必须把真实换行/回车/制表符转为 \\n \\r \\t 字面量,
# 否则多行文本会生成真实换行导致 i18n.js 语法错误(SyntaxError: Invalid or unexpected token)
return (s.replace('\\', '\\\\')
.replace('"', '\\"')
.replace('\r\n', '\\n')
.replace('\n', '\\n')
.replace('\r', '\\n')
.replace('\t', '\\t'))
def build_block(entries):
lines = []
for zh, en in sorted(entries.items(), key=lambda x: x[0]):
lines.append(f' "{esc(zh)}": {{ zh: "{esc(zh)}", en: "{esc(en)}" }},')
return "\n".join(lines)
def assert_no_duplicate_keys():
"""校验 M 无重复键,有则打印冲突明细并以非零码退出。
为什么必须显式检测:Python 的 dict 字面量遇到重复键**静默取最后一个**、
不报错也不告警(ruff F601 能查,但只有把 scripts/ 纳入阻断才真正拦得住)。
本表一旦静默覆盖,产物 i18n.js 的英文文案会随「哪条写在后面」而变,
属于典型的看不见的回归。这里用 AST 解析本文件自身的 M 字面量,
不维护并行清单、因此不会与数据脱节。
"""
import ast
from collections import Counter, defaultdict
tree = ast.parse(open(__file__, encoding="utf-8").read(), filename=__file__)
literal = None
for node in ast.walk(tree):
if isinstance(node, ast.Assign):
for tgt in node.targets:
if isinstance(tgt, ast.Name) and tgt.id == "M" and isinstance(node.value, ast.Dict):
literal = node.value
if literal is None:
print("⚠️ 未在本文件中找到 M 字面量,跳过重复键校验")
return
seen = defaultdict(list) # zh -> [(lineno, en), ...]
for k, v in zip(literal.keys, literal.values):
if isinstance(k, ast.Constant) and isinstance(v, ast.Constant):
seen[k.value].append((k.lineno, v.value))
dups = {zh: occ for zh, occ in seen.items() if len(occ) > 1}
if not dups:
return
print(f"❌ M 中存在 {len(dups)} 个重复键(dict 字面量会静默取最后一个值):")
for zh in sorted(dups):
occs = ", ".join(f'L{n}="{v}"' for n, v in dups[zh])
kept = dups[zh][-1][1]
print(f' "{zh}" 出现 {len(dups[zh])} 次 -> 实际生效 "{kept}" | {occs}')
print("请删除重复条目或统一取值后再运行本脚本。")
sys.exit(1)
def existing_keys(src):
"""解析 i18n.js 已有的 zh 键集合,还原 JS 转义后返回(与 M 的键同形)。
两处都得做对,否则已有键会被误判为"新键"、每跑一次就多插一份(实测曾把
10 份 `\" 吗?` 累积成 11 份):
1) 捕获要能吃下转义引号 —— 旧写法 `"([^"]+)"` 遇到 `"…\\" 吗?"` 这类
含 `\\"` 的键会整条漏掉;
2) 比较前要反转义 —— 文件里是 esc() 产出的 JS 形态(`\\"` `\\n` `\\\\`),
而 M 的键是 Python 原始字符串,不还原则永不相等。
文件形态本身即合法 JSON 字符串字面量,故用 json.loads 还原最稳。
"""
out = set()
for m in re.finditer(r'^ "((?:[^"\\]|\\.)*)":\s*\{\s*zh:', src, re.M):
raw = m.group(1)
try:
out.add(json.loads('"' + raw + '"'))
except Exception:
out.add(raw) # 兜底:极端手写条目按原样比较(宁可不插,也不重复插)
return out
def report_existing_dups(src):
"""报告 i18n.js 内已存在的重复键(JS 对象重复键同样是后者静默覆盖)。"""
from collections import Counter
keys = []
for m in re.finditer(r'^ "((?:[^"\\]|\\.)*)":\s*\{\s*zh:', src, re.M):
raw = m.group(1)
try:
keys.append(json.loads('"' + raw + '"'))
except Exception:
keys.append(raw)
dups = {k: n for k, n in Counter(keys).items() if n > 1}
if dups:
print(f"⚠️ i18n.js 已存在 {len(dups)} 个重复键(JS 会静默取最后一个值),"
f"最多者:{sorted(dups.items(), key=lambda x: -x[1])[:3]}")
return dups
def main():
assert_no_duplicate_keys()
path = "scout/web/static/i18n.js"
src = open(path, encoding="utf-8").read()
report_existing_dups(src)
# 已有键(还原转义后比较,避免把已存在的转义引号键当成新键重复插入)
have = existing_keys(src)
new = {zh: en for zh, en in M.items() if zh not in have}
if not new:
print("无新增条目")
return
block = "\n" + build_block(new) + "\n"
# 插入到字典结束 }; 前(最后一条 "⚠️ 未配置 API Key" 之后)
marker = '"⚠️ 未配置 API Key": { zh: "⚠️ 未配置 API Key", en: "⚠️ API Key not configured" },'
if marker not in src:
print("未找到插入锚点")
sys.exit(1)
src = src.replace(marker, marker + block, 1)
open(path, "w", encoding="utf-8").write(src)
print(f"已插入 {len(new)} 条新字典条目")
if __name__ == "__main__":
main()