# -*- coding: utf-8 -*- """新前端页面装配 —— shell.html + app.css + app.js + 语言包, 按语言出一页。 出页面之前先跑 lang.check(): 英文缺条目 / 含中文 / 占位符不一致 = **这里就 FAIL**, 不会走到用户眼前变成一处中文残留。这是新旧架构最根本的差别。 """ from __future__ import annotations import json import pathlib from .. import lang _HERE = pathlib.Path(__file__).resolve().parent # pages/ _ASSETS = _HERE.parent / 'assets' # 前端资源件 (js/css) def _read(name: str) -> str: """资源件在 assets/,页面外壳在 pages/ —— 两处都找(P5 分目录后)。""" for d in (_HERE, _ASSETS): f = d / name if f.is_file(): return f.read_text(encoding='utf-8') raise FileNotFoundError(f'前端资源件缺失: {name}(pages/ 与 assets/ 都没有)') def render(which: str = 'zh', include_records=True) -> str: if which not in lang.LANGS: raise ValueError('未知语言 %r' % which) bad = lang.check() if bad: raise RuntimeError('语言包未过闸, 拒绝出页:\n ' + '\n '.join(bad)) pack = lang.pack(which) if which == 'zh': # 显示层术语映射 (app_frontEnd/configs/terms/display_map.yaml): 界面标签在这里过一遍; # 数据里的内部词由前端 displayText 用 __display_zh 同表处理 (数据与匹配逻辑一律不动)。 from ..terms import humanize, pairs pack = {k: (humanize(v) if isinstance(v, str) else v) for k, v in pack.items()} pack['__display_zh'] = [list(x) for x in pairs()] if which == 'en' and include_records: from src.windscada.en_text import STANDARD_TERMS if include_records == 'terms': pack['__record_en'] = dict(STANDARD_TERMS) else: from src.windscada.data_tpl_en import RECORD_EN pack['__record_en'] = dict(RECORD_EN, **STANDARD_TERMS) # `` 出现在 JSON 里会提前闭合 script 标签; `<` 一律转义 packjs = json.dumps(pack, ensure_ascii=False).replace('<', '\\u003c') return (_read('shell.html') .replace('%LANG%', which) .replace('%TITLE%', pack['app.title']) .replace('%CSS%', _read('app.css')) .replace('%LANGPACK%', packjs) .replace('%CHARTS%', _read('charts.js')) .replace('%JS%', _read('app.js'))) if __name__ == '__main__': # python -m app_frontEnd.app_frontEnd_guanlan.pages.build en > v2_en.html (旧路径 `python -m src.windscada.ui.build` 经兼容壳照旧可用) import sys sys.stdout.write(render(sys.argv[1] if len(sys.argv) > 1 else 'zh'))