- build.sh四处清单(mv/pip install/xls2ui/软链)删pipeline_dist - app/pipeline_app.py删import+load_pipeline_dist() - conf/config.json删module_dbname条目; conf/rp.json删/pipeline_dist两条 - bin/init_perms.py删分销管理访问权限; scripts/load_path.py删3条RBAC路径 - scripts/merge_i18n.py删MODULES条目; wwwroot/index.ui删分销管理菜单项 - deploy/smoke/cases.json删s09营销产线壳用例 - i18n源+产物删5词条(分销商产线配置/分销商管理/分销管理/2条描述语) - wwwroot/pipeline_dist软链删除(git跟踪) - deploy/migrations/m0020登记DROP两表+清码表+清权限(破坏性,dmig拒绝自动执行,人工复核手工跑;测试机两表0行) - supplychain的sub_distributor*权限/表不受影响(path前缀与表名均不同)
107 lines
3.8 KiB
Python
107 lines
3.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Merge i18n translations from all pipeline modules into wwwroot/i18n.
|
|
Scans each module's i18n directory and merges into the app's centralized i18n.
|
|
|
|
Usage: python scripts/merge_i18n.py
|
|
"""
|
|
import os, json, sys
|
|
from collections import OrderedDict
|
|
from pathlib import Path
|
|
|
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
ROOT_DIR = os.path.dirname(SCRIPT_DIR)
|
|
WWWROOT = os.path.join(ROOT_DIR, 'wwwroot')
|
|
I18N_OUT = os.path.join(WWWROOT, 'i18n')
|
|
|
|
# Modules to scan for i18n
|
|
MODULES = [
|
|
('app', os.path.join(ROOT_DIR, 'i18n')),
|
|
('pipeline_core', os.path.join(ROOT_DIR, 'pipeline_core', 'i18n')),
|
|
('pipeline_ops', os.path.join(ROOT_DIR, 'pipeline_ops', 'i18n')),
|
|
('pipeline-sdlc', os.path.join(os.path.dirname(ROOT_DIR), 'pipeline-sdlc', 'i18n')),
|
|
('showcase', os.path.join(os.path.dirname(ROOT_DIR), 'showcase', 'i18n')),
|
|
('pipeline-bidding', os.path.join(ROOT_DIR, 'pkgs', 'pipeline-bidding', 'i18n')),
|
|
('pipeline-opportunity', os.path.join(ROOT_DIR, 'pkgs', 'pipeline-opportunity', 'i18n')),
|
|
('dingdingflow', os.path.join(ROOT_DIR, 'pkgs', 'dingdingflow', 'i18n')),
|
|
('rbac', os.path.join(ROOT_DIR, 'pkgs', 'rbac', 'i18n')),
|
|
]
|
|
|
|
LANGS = ['zh', 'en', 'ko', 'jp']
|
|
|
|
|
|
def parse_msg_txt(filepath):
|
|
"""Parse msg.txt: 'key=value' or 'key: value' format."""
|
|
result = OrderedDict()
|
|
if not os.path.exists(filepath):
|
|
return result
|
|
with open(filepath, 'r', encoding='utf-8') as f:
|
|
for line in f:
|
|
line = line.strip()
|
|
if not line or line.startswith('#'):
|
|
continue
|
|
if '=' in line:
|
|
key, val = line.split('=', 1)
|
|
result[key.strip()] = val.strip()
|
|
elif ':' in line:
|
|
key, val = line.split(':', 1)
|
|
result[key.strip()] = val.strip()
|
|
return result
|
|
|
|
|
|
def merge():
|
|
os.makedirs(I18N_OUT, exist_ok=True)
|
|
stats = {}
|
|
|
|
for lang in LANGS:
|
|
merged = OrderedDict()
|
|
out_dir = os.path.join(I18N_OUT, lang)
|
|
os.makedirs(out_dir, exist_ok=True)
|
|
|
|
# Load existing merged translations
|
|
i18n_file = os.path.join(out_dir, 'i18n.json')
|
|
if os.path.exists(i18n_file):
|
|
with open(i18n_file, 'r', encoding='utf-8') as f:
|
|
merged = json.load(f, object_pairs_hook=OrderedDict)
|
|
|
|
# Scan each module
|
|
for mod_name, mod_i18n_dir in MODULES:
|
|
lang_dir = os.path.join(mod_i18n_dir, lang)
|
|
if not os.path.isdir(lang_dir):
|
|
# Try app's internal i18n
|
|
alt_dir = os.path.join(ROOT_DIR, 'pipeline_core', 'i18n', lang)
|
|
if not os.path.isdir(alt_dir):
|
|
continue
|
|
lang_dir = alt_dir
|
|
|
|
# Load msg.txt
|
|
msg_file = os.path.join(lang_dir, 'msg.txt')
|
|
if os.path.exists(msg_file):
|
|
msgs = parse_msg_txt(msg_file)
|
|
for k, v in msgs.items():
|
|
if k not in merged:
|
|
merged[k] = v
|
|
stats.setdefault(mod_name, 0)
|
|
stats[mod_name] += 1
|
|
|
|
# Load i18n.json
|
|
mod_i18n = os.path.join(lang_dir, 'i18n.json')
|
|
if os.path.exists(mod_i18n):
|
|
with open(mod_i18n, 'r', encoding='utf-8') as f:
|
|
extra = json.load(f, object_pairs_hook=OrderedDict)
|
|
for k, v in extra.items():
|
|
if k not in merged:
|
|
merged[k] = v
|
|
|
|
# Write merged
|
|
with open(i18n_file, 'w', encoding='utf-8') as f:
|
|
json.dump(merged, f, ensure_ascii=False, indent=2)
|
|
print(f' {lang}: {len(merged)} keys')
|
|
|
|
# Write msg.txt for the app root
|
|
print(f'\nMerged i18n for {len(MODULES)} modules -> {I18N_OUT}')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
merge()
|