符号数据改用 rime-wanxiang 的符号表与 typst/codex 符号名,源数据放在 msime-dictionary 的 sources/symbols/,替换原来的 piliapp 符号表。 - 建库:新增 symbols_db.py,生成表情面板用的 symbol_catalog(中文分类)和 S 模式、符号混输用的 symbol_code;剔除 wanxiang-unrenderable.txt 列出的 Windows 自带字体显示不了的符号,以及与 ① ❶ 看不出区别的 Dingbats 带圈数字 - 新增 scripts/check-symbol-rendering.py,用 Windows 字体生成上面的剔除清单 - Shift+S 进入符号模式,按万象分组码(xl、sx、szq)、数字读音(yi → 一 ① ⑴) 或符号名(alpha、infinity)检索 - 符号混输:整串精确等于编码时混入,首个紧跟首选;读得成拼音的编码只混数字 序号写法;双拼先按方案换算成全拼再查(小鹤 sj → san → ③) - 表情面板符号页:中文分类,搜索把整词命中的符号列在「最佳匹配」 - 配置:utility.symbol_mode(默认开)、general.symbol_mixed_input(默认关) Refs #795
109 lines
5.9 KiB
Python
109 lines
5.9 KiB
Python
#!/usr/bin/env python3
|
||
"""从 msime-dictionary 的文本源数据本地构建 Windows 端词库,写到 MetasequoiaImeDict/out/。
|
||
|
||
读取 msime-dictionary checkout 的 sources/ 与 custom/,加上 scripts/dictionary_build/inputs.lock.json 固定的
|
||
仓外文件(msime 的快捷短语、读音纠错、emoji/颜文字表,ECDICT,SCOWL,rime-jp_sela),产出:
|
||
|
||
msime.db 全拼表(含地名补充、自定义词条、读音纠错)、86 五笔、快捷短语、japanese_lexicon
|
||
english.db 英文候选、中英双向释义(ECDICT)、sources/cn-en/ 的中译英释义(全部义项)、custom/translations.txt 覆盖
|
||
others.db emoji、颜文字、符号(sources/symbols/ 的万象符号表,剔除 wanxiang-unrenderable.txt 列出的)
|
||
dict_japanese.dat 日文整句模型(sources/japanese/ 的 Mozc 词库)
|
||
以及 Mozc 与 SCOWL 的声明、dictionary-manifest.json、SHA256SUMS.txt、local-dictionary.json
|
||
|
||
构建规则移植自 msime 的 Rust 构建器(crates/dict-builder)。--compare-release 把结果与官方 Release 逐表对比。
|
||
替换 out/ 前,如果里面是产品锁钉住的旧词库,先整份备份到 MetasequoiaImeDict/out.bak/。
|
||
|
||
用法:
|
||
python scripts/build-dictionary.py # 默认读与本仓同级的 msime-dictionary
|
||
python scripts/build-dictionary.py --dictionary D:/msime-dictionary
|
||
python scripts/build-dictionary.py --compare-release dict-v2.0.13 # 构建后与官方 Release 逐表对比
|
||
python scripts/build-dictionary.py --verify # 只校验 out/ 是否仍是本脚本构建的结果
|
||
python scripts/build-dictionary.py --if-stale # 源数据或构建脚本没变就跳过(installer\test.ps1 用)
|
||
|
||
构建 others.db 需要 pypinyin(python -m pip install pypinyin)。
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import argparse
|
||
import os
|
||
import sqlite3
|
||
import subprocess
|
||
import sys
|
||
import tempfile
|
||
import time
|
||
from pathlib import Path
|
||
|
||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||
|
||
from dictionary_build import build, compare, inputs # noqa: E402
|
||
|
||
|
||
def default_dictionary() -> Path:
|
||
if os.environ.get("MSIME_DICTIONARY"):
|
||
return Path(os.environ["MSIME_DICTIONARY"])
|
||
return build.ROOT.parent / "msime-dictionary"
|
||
|
||
|
||
def main() -> None:
|
||
parser = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
|
||
parser.add_argument("--dictionary", type=Path, default=None,
|
||
help="msime-dictionary checkout,默认取环境变量 MSIME_DICTIONARY,否则是本仓同级的 msime-dictionary")
|
||
parser.add_argument("--msime-resources", type=Path, default=None,
|
||
help="改用这个目录下的 msime resources/dictionary-sources 文件(本地修改用),不按锁校验")
|
||
parser.add_argument("--compare-release", metavar="TAG", help="构建后与这个 dict-v* Release 逐表对比,不一致时失败")
|
||
parser.add_argument("--verify", action="store_true", help="只校验 out/ 是否仍是本脚本构建的结果")
|
||
parser.add_argument("--if-stale", action="store_true",
|
||
help="out/ 已由当前 msime-dictionary 提交和当前构建脚本构建、且工作区干净时跳过,否则重新构建")
|
||
args = parser.parse_args()
|
||
|
||
if args.verify:
|
||
marker = build.verify_out()
|
||
state = ",有未提交改动" if marker.get("dirty") else ""
|
||
commit = marker["custom_dictionary_commit"][:12] or "不是 Git 工作区"
|
||
print(f"词库已就绪:{build.OUT}(msime-dictionary {commit}{state})")
|
||
return
|
||
|
||
dictionary = (args.dictionary or default_dictionary()).resolve()
|
||
if not (dictionary / "sources").is_dir() or not (dictionary / "custom").is_dir():
|
||
raise SystemExit(f"{dictionary} 不是 msime-dictionary checkout(没有 sources/ 和 custom/),用 --dictionary 指定")
|
||
commit, dirty = inputs.git_state(dictionary)
|
||
print(f"msime-dictionary:{dictionary}({commit[:12] or '不是 Git 工作区'}{',有未提交改动' if dirty else ''})")
|
||
if args.if_stale and not args.compare_release:
|
||
reason = build.stale_reason(commit, dirty or args.msime_resources is not None)
|
||
if reason is None:
|
||
print(f"词库已是最新:{build.OUT}")
|
||
return
|
||
print(f"重新构建词库:{reason}")
|
||
mismatched = inputs.check_upstream(dictionary)
|
||
if mismatched:
|
||
print(f"提示:{len(mismatched)} 个文件与 upstream.lock.json 记录的不同(本地改过的上游文件或生成表):"
|
||
f"{', '.join(mismatched[:5])}{' ...' if len(mismatched) > 5 else ''}")
|
||
|
||
source = inputs.fetch(dictionary, build.CACHE, args.msime_resources)
|
||
started = time.perf_counter()
|
||
build.DICT_ROOT.mkdir(parents=True, exist_ok=True)
|
||
# 整套构建并检查通过之前不动已有的 out/。
|
||
with tempfile.TemporaryDirectory(dir=build.DICT_ROOT, prefix="incoming-") as temporary:
|
||
staging = Path(temporary)
|
||
build.build_all(source, staging)
|
||
build.check_outputs(staging)
|
||
build.write_manifests(staging, commit, dirty or args.msime_resources is not None, source.msime_commit)
|
||
if args.compare_release:
|
||
problems = compare.compare(staging, args.compare_release, build.DICT_ROOT / "cache", commit,
|
||
source.msime_commit)
|
||
for problem in problems:
|
||
print(f" 不一致:{problem}")
|
||
if problems:
|
||
raise SystemExit(f"与 {args.compare_release} 不一致,out/ 未替换")
|
||
build.install(staging)
|
||
build.verify_out()
|
||
print(f"词库构建完毕({time.perf_counter() - started:.0f}s):{build.OUT}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
try:
|
||
main()
|
||
except (OSError, ValueError, KeyError, sqlite3.Error, subprocess.CalledProcessError) as error:
|
||
raise SystemExit(f"失败:{error}") from error
|