From 2dda711b731411610cbfce5e84f76aaa6e36edd6 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Mon, 29 Jun 2026 11:22:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20merge=5Fi18n.py=20=E4=BD=BF=E7=94=A8=20b?= =?UTF-8?q?uild.sh=20=E6=A8=A1=E5=9D=97=E6=B8=85=E5=8D=95=E6=9B=BF?= =?UTF-8?q?=E4=BB=A3=20load=5Fpath.py=20=E8=A7=A3=E6=9E=90\n\n-=20?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E6=9D=A5=E6=BA=90=E6=94=B9=E4=B8=BA=20build.?= =?UTF-8?q?sh=20=E7=AC=AC29=E8=A1=8C=EF=BC=88Sage=E4=B8=9A=E5=8A=A1?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=EF=BC=8C=E4=B8=8E=20wwwroot=20=E7=AC=A6?= =?UTF-8?q?=E5=8F=B7=E9=93=BE=E6=8E=A5=E4=B8=80=E8=87=B4=EF=BC=89\n-=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A8=A1=E5=9D=97:=20discount,=20harnessed?= =?UTF-8?q?=5Freasoning,=20reallife=5Fasset,=20bugfix\n-=20=E7=A7=BB?= =?UTF-8?q?=E9=99=A4=E8=AF=AF=E5=88=A4=E6=A8=A1=E5=9D=97:=20dagflow,=20kbo?= =?UTF-8?q?ss,=20skillagent,=20checklang\n-=20=E5=BD=93=E5=89=8D:=2023?= =?UTF-8?q?=E6=A8=A1=E5=9D=97(=E5=90=ABsage),=2021=E4=B8=AA=E6=9C=89i18n?= =?UTF-8?q?=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- merge_i18n.py | 63 ++++++++++++++++++++++----------------------------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/merge_i18n.py b/merge_i18n.py index d11841f4..a98af109 100644 --- a/merge_i18n.py +++ b/merge_i18n.py @@ -2,16 +2,16 @@ """ 合并所有Sage模块的i18n内容到 wwwroot/i18n -从 load_path.py 中提取sage引用的所有模块, +模块清单与 build.sh 保持一致(第29行 for m in ...), 读取每个模块的 i18n/{lang}/msg.txt, -合并输出到 wwwroot/i18n/{lang}/i18n.json。 +合并输出到 wwwroot/i18n/{lang}/i18n.json + msg.txt。 -冲突策略:后加载的模块覆盖先加载的,sage自身覆盖所有。 +冲突策略:按 build.sh 中模块顺序,后加载的覆盖先加载的。 + sage 自身排在首位(优先级最低)。 """ -import os -import re import json +import re import sys from pathlib import Path @@ -22,36 +22,27 @@ I18N_OUTPUT_DIR = SAGE_DIR / 'wwwroot' / 'i18n' # 输出目标 LANGS = ['zh', 'en', 'jp', 'ko'] # 支持的语言 -def parse_load_path(load_path_file): - """从 load_path.py 中提取模块名列表 +def parse_build_sh(build_sh_path): + """从 build.sh 中提取模块清单(第29行 for m in ...) - load_path.py 中每行格式: /module_name/rest/of/path ... - 只提取行首的第一个路径段作为模块名。 + build.sh 有两个 for m in 循环: + - 第21行: pip基础库(apppublic, sqlor, ahserver, ...) + - 第29行: Sage业务模块(appbase, rbac, accounting, ...) + 我们取第二个(业务模块),与 sage 的 wwwroot 符号链接配置一致。 """ - modules = set() - # 已知的非模块路径前缀(系统路径、资源目录等) - skip_prefixes = { - 'conf', 'logs', 'files', 'script', 'skills', 'plugins', - 'py3', 'bin', 'initln', 'docs', 'agents', 'hermes_work', - 'bricks', 'imgs', 'i18n', 'public', 'api', 'shell', - } + with open(build_sh_path, 'r', encoding='utf-8') as f: + content = f.read() - with open(load_path_file, 'r', encoding='utf-8') as f: - for line in f: - line = line.strip() - if not line or line.startswith('#'): - continue - # 匹配行首的 /module_name/ - m = re.match(r'^/\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*/', line) - if not m: - continue - mod = m.group(1) - if mod not in skip_prefixes: - modules.add(mod) + # 匹配所有 "for m in ..." 行 —— 只到行尾(不用 \s 防止跨行匹配到 do) + matches = re.findall(r'^for m in ((?:[a-z][\w-]*[ \t]*)+)$', content, re.MULTILINE) + if len(matches) < 2: + sys.exit(f"错误: 在 build.sh 中找到 {len(matches)} 个 for m in 行,期望至少2个") - # sage 自身始终排在前面(优先级最低,因为 load_path 中 sage 是根路径) - modules.discard('sage') - result = ['sage'] + sorted(modules) + # 第二个 for m in 是 Sage 业务模块清单 + modules_str = matches[1] + modules = [m for m in modules_str.strip().split() if '-' not in m] + # sage 自身始终排在首位(优先级最低) + result = ['sage'] + modules return result @@ -141,13 +132,13 @@ def write_output(merged): def main(): - load_path_file = SAGE_DIR / 'load_path.py' - if not load_path_file.is_file(): - print(f"错误: 找不到 {load_path_file}") + build_sh_path = SAGE_DIR / 'build.sh' + if not build_sh_path.is_file(): + print(f"错误: 找不到 {build_sh_path}") sys.exit(1) - print(f"解析 load_path.py: {load_path_file}") - modules = parse_load_path(load_path_file) + print(f"解析 build.sh: {build_sh_path}") + modules = parse_build_sh(build_sh_path) print(f"发现 {len(modules)} 个模块:") for m in modules: has_i18n = (REPOS_DIR / m / 'i18n').is_dir()