terms.py 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637
  1. # -*- coding: utf-8 -*-
  2. """显示层术语映射 (app_frontEnd/configs/terms/display_map.yaml): 内部说法 → 现场说法。
  3. **只在渲染边界用**, 不改数据、不改任何比较/匹配逻辑 (那些内部词就在 handoff/本体数据里, 改数据会断匹配)。
  4. 用法: from src.windscada.terms import humanize; humanize('发电机(引用同族, 见族主台)') → '发电机(无本台独立证据, 参照同型机组)'
  5. 前端同源: `pairs()` 出的表经语言包 `__display_zh` 注入 app.js 的 displayText。
  6. """
  7. from __future__ import annotations
  8. try:
  9. from app_common.app_common_guanlan.api import install_root as _install_root
  10. except ImportError: # 极端兜底(包结构异常时按位置上跳)
  11. from pathlib import Path as _P
  12. def _install_root(_f): return _P(_f).resolve().parents[3]
  13. import functools, pathlib, sys
  14. ROOT = _install_root(__file__)
  15. sys.path.insert(0, str(ROOT))
  16. from src import paths as P # 配置唯一取用口
  17. MAP_FILE = P.config("terms", "display_map.yaml") # 配置唯一取用口 (src/paths.py)
  18. @functools.lru_cache(maxsize=1)
  19. def pairs() -> tuple[tuple[str, str], ...]:
  20. """(内部词, 现场词) 按内部词长度降序 —— 长词先替, 否则 '引用同族, 见族主台' 会被 '引用同族' 先吃掉半句."""
  21. if not MAP_FILE.exists(): return ()
  22. import yaml
  23. d = yaml.safe_load(MAP_FILE.read_text(encoding="utf-8")) or {}
  24. ps = [(str(i["from"]), str(i["to"])) for i in (d.get("items") or []) if i.get("from")]
  25. return tuple(sorted(ps, key=lambda kv: -len(kv[0])))
  26. def humanize(s):
  27. """把内部词换成现场说法; 非字符串原样返回 (调用点可以无脑包)."""
  28. if not isinstance(s, str) or not s: return s
  29. for a, b in pairs():
  30. if a in s: s = s.replace(a, b)
  31. return s