All business modules overwrite common keys (Submit/Reset/Cancel) with English→English, erasing bricks' zh translations. Moving bricks to end of merge priority ensures framework built-in strings always win.
167 lines
5.6 KiB
Python
167 lines
5.6 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
合并所有Sage模块的i18n内容到 wwwroot/i18n
|
||
|
||
模块清单与 build.sh 保持一致(第29行 for m in ...),
|
||
读取每个模块的 i18n/{lang}/msg.txt,
|
||
合并输出到 wwwroot/i18n/{lang}/i18n.json + msg.txt。
|
||
|
||
冲突策略:按 build.sh 中模块顺序,后加载的覆盖先加载的。
|
||
sage 自身排在首位(优先级最低)。
|
||
"""
|
||
|
||
import json
|
||
import re
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
# --- 配置 ---
|
||
SAGE_DIR = Path(__file__).resolve().parent # /d/ymq/repos/sage
|
||
REPOS_DIR = SAGE_DIR.parent # /d/ymq/repos
|
||
I18N_OUTPUT_DIR = SAGE_DIR / 'wwwroot' / 'i18n' # 输出目标
|
||
LANGS = ['zh', 'en', 'jp', 'ko'] # 支持的语言
|
||
|
||
|
||
def parse_build_sh(build_sh_path):
|
||
"""从 build.sh 中提取模块清单(第29行 for m in ...)
|
||
|
||
build.sh 有两个 for m in 循环:
|
||
- 第21行: pip基础库(apppublic, sqlor, ahserver, ...)
|
||
- 第29行: Sage业务模块(appbase, rbac, accounting, ...)
|
||
我们取第二个(业务模块),与 sage 的 wwwroot 符号链接配置一致。
|
||
"""
|
||
with open(build_sh_path, 'r', encoding='utf-8') as f:
|
||
content = f.read()
|
||
|
||
# 匹配所有 "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个")
|
||
|
||
# 第二个 for m in 是 Sage 业务模块清单
|
||
modules_str = matches[1]
|
||
modules = [m for m in modules_str.strip().split() if '-' not in m]
|
||
# 业务模块 → bricks(最后加载,优先级最高,确保框架内置文本不被覆盖)
|
||
# bricks 是基础框架,不在 build.sh 业务模块循环中,需手动加入
|
||
result = ['sage'] + modules + ['bricks']
|
||
return result
|
||
|
||
|
||
def find_module_i18n_dir(module_name):
|
||
"""查找模块的 i18n 目录(先查 repos/ 同级目录,再查 sage/pkgs/ 内)"""
|
||
candidate = REPOS_DIR / module_name / 'i18n'
|
||
if candidate.is_dir():
|
||
return candidate
|
||
candidate = SAGE_DIR / 'pkgs' / module_name / 'i18n'
|
||
if candidate.is_dir():
|
||
return candidate
|
||
return None
|
||
|
||
|
||
def parse_msg_txt(filepath):
|
||
"""解析 msg.txt,格式: key: value(每行一个)"""
|
||
result = {}
|
||
if not filepath.is_file():
|
||
return result
|
||
|
||
with open(filepath, 'r', encoding='utf-8') as f:
|
||
for line in f:
|
||
line = line.rstrip('\n').rstrip('\r')
|
||
if not line:
|
||
continue
|
||
# 格式: key: value
|
||
idx = line.find(': ')
|
||
if idx > 0:
|
||
key = line[:idx]
|
||
value = line[idx+2:]
|
||
result[key] = value
|
||
else:
|
||
# 可能只有 key 没有 value,或者格式不对,跳过
|
||
idx = line.find(':')
|
||
if idx > 0:
|
||
key = line[:idx]
|
||
value = line[idx+1:]
|
||
result[key] = value
|
||
return result
|
||
|
||
|
||
def merge_i18n(modules):
|
||
"""合并所有模块的 i18n,返回 {lang: {key: value}}"""
|
||
merged = {lang: {} for lang in LANGS}
|
||
|
||
for module_name in modules:
|
||
i18n_dir = find_module_i18n_dir(module_name)
|
||
if not i18n_dir:
|
||
print(f" [跳过] {module_name}: 未找到i18n目录")
|
||
continue
|
||
|
||
for lang in LANGS:
|
||
msg_file = i18n_dir / lang / 'msg.txt'
|
||
if msg_file.is_file():
|
||
translations = parse_msg_txt(msg_file)
|
||
count = len(translations)
|
||
before = len(merged[lang])
|
||
merged[lang].update(translations)
|
||
after = len(merged[lang])
|
||
new_keys = after - before
|
||
if new_keys > 0 or count > 0:
|
||
print(f" {module_name}/{lang}: {count}条, 新增{new_keys}个唯一key")
|
||
else:
|
||
print(f" [警告] {module_name}/{lang}: msg.txt 不存在")
|
||
|
||
return merged
|
||
|
||
|
||
def write_output(merged):
|
||
"""将合并结果写入 wwwroot/i18n/{lang}/i18n.json 和 msg.txt"""
|
||
for lang in LANGS:
|
||
lang_dir = I18N_OUTPUT_DIR / lang
|
||
lang_dir.mkdir(parents=True, exist_ok=True)
|
||
|
||
data = merged[lang]
|
||
|
||
# 写入 i18n.json(前端读取此文件)
|
||
json_file = lang_dir / 'i18n.json'
|
||
with open(json_file, 'w', encoding='utf-8') as f:
|
||
json.dump(data, f, ensure_ascii=False, indent='\t')
|
||
|
||
# 同时写入 msg.txt(人类可读格式)
|
||
msg_file = lang_dir / 'msg.txt'
|
||
with open(msg_file, 'w', encoding='utf-8') as f:
|
||
for key, value in data.items():
|
||
f.write(f"{key}: {value}\n")
|
||
|
||
print(f" 写入: {json_file} ({len(data)} 条)")
|
||
print(f" 写入: {msg_file} ({len(data)} 条)")
|
||
|
||
|
||
def main():
|
||
build_sh_path = SAGE_DIR / 'build.sh'
|
||
if not build_sh_path.is_file():
|
||
print(f"错误: 找不到 {build_sh_path}")
|
||
sys.exit(1)
|
||
|
||
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()
|
||
status = '✓' if has_i18n else '✗'
|
||
print(f" {status} {m}")
|
||
|
||
print(f"\n开始合并 i18n...")
|
||
merged = merge_i18n(modules)
|
||
|
||
print(f"\n合并结果:")
|
||
for lang in LANGS:
|
||
print(f" {lang}: {len(merged[lang])} 个唯一key")
|
||
|
||
print(f"\n写入 wwwroot/i18n...")
|
||
write_output(merged)
|
||
|
||
print(f"\n完成!")
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main()
|