14 KiB
辅码
issue #8:联想里没有的词要翻很多页;加辅码(拼音后补码筛选)能把第一次打句子的效率提上来,选过一次的词靠既有学习在下次纯拼音就往前排。
本文是这份需求的设计来源:要做什么、为什么这么做、数据从哪来、许可怎么算。实现按 docs/plan/todo.md 排期。
术语
| 词 | 意思 |
|---|---|
| 辅码 | 拼音之后键入的、用来缩小候选范围的码。形态是「拼音 + 触发键 + 码」。 |
| 触发键 | 进入辅码态的那个键。可配置,缺省 ;。 |
| 码段 | 输入串里触发键之后的字母,与拼音段分开记账、分开画。 |
| 码表 | 「词 → 码」的映射数据,导入与管理的单位。 |
| 原生表 | 随包分发、开箱可用的码表。v1 只有笔画。 |
| 引导导入 | 不随包带表,由用户自己从官方渠道取得码表后一键导入。第三方形码(小鹤形、自然码形)走这条路。 |
辅码的语义(Core)
触发
- 配置项
[general] aux_code_key,缺省;;也想跟雾凇(反引号 + 偏旁部首拼音)或万象(/前置引导符)对齐的用户改这一个键即可。 - 优先级规则(与现有行为共存):当前 preedit 能完整切分成音节、且敲下的字符是配置的触发键 → 进辅码态;否则维持现有语义(
;仍按中文标点转全角、不会转全角的符号仍进英文直输段——会转全角的标点先把高亮候选上屏再补标点——翻页键仍是翻页键)。 - 微软 / 搜狗 / 紫光双拼里
;是ing的韵母键:能构成合法音节就当韵母,否则当触发键。x;是 xing(;被韵母吃掉),再敲一个;才进辅码态。
过滤
- 词级(含单字):码只筛词候选,不改选词逻辑,也不改整句转换。
- 逐键即筛:码段每多一个字母就重新筛一次,不要求敲满该词的码位;敲到满意即可上屏。
- 无码词在辅码态直接隐藏:码表没覆盖的词不出候选;码段删空后停在辅码态——
;仍在、候选全部回来,空码段再按一次退格才退出([general] aux_code_keep_empty,缺省开;关掉则删空即回纯拼音态)。 - 筛空时候选窗口收起,只剩拼音行。
学习(issue 里「下一次不用辅码也能联想出来」就落在这)
不新造机制:辅码态选中的词按输入串记进 user-choices.tsv(词级排序里同输入串选过的优先),并计入词频与个人 n-gram。
下次同样的拼音,这个词自然往前排。也就是说辅码只需解决「第一次怎么少翻页」。
与整句、简拼的关系
v1 只支持全拼 + 辅码、双拼 + 辅码。简拼 + 辅码、整句转换 + 辅码(形码逐字约束进 Viterbi 词图)都留到后续,见「后续与不做」。
码表
格式:Rime .dict.yaml
沿用已有的 Rime 词库导入传统(crates/qingjian-dictionary/src/import/rime.rs 已能把 .dict.yaml 转成 .qj),码表用它同一套外形:
- 头部
---…...是 meta(name/version/sort),正文每行词\t码[\t权重],#是注释。 columns必须解析:缺省是text/code/weight三列,但真实存在columns: [text, weight]的纯词表——照缺省解析会把词频当码,静默写坏数据。解析按columns列表的下标定位。import_tables表示跨文件合表(一本码表由 base + stem + extended 拼成):导入时一并读入,否则数据不完整。- 「有词无码」的行要报错或警告,不能像词库导入那样静默跳过(码表少一行就是少一个词可用,用户得知道)。
- 导入完成给一份统计:读入多少条、多少词有码、多少词无码、跳过多少行。
索引:独立码索引,两段式查询
码表不能复用词库的存储:
- 词库的
Slot{text_start, frequency, text_len, reserved}没有码字段; - 键空间会串台——
de/he/bu/ge这类两位码同时是合法拼音音节,同一个索引里既当码又当拼音,约束互相污染。
所以码表落成自己的索引(码 → 词集合),查询是两段式:先用拼音段查词库得到候选集合,再用码段在该索引里取交集、按码命中重排。码表文件与词库文件一样进用户数据目录,单独管理。
原生表:只带笔画
第三方形码表都不随包,理由在「许可」一节。随包的只有笔画:
- 键位:
h横、s竖、p撇、n捺(含点)、z折——与大陆厂商(搜狗 / QQ)的笔画输入一致,键盘手位在拼音区。 - 取码:单字「前 4 笔 + 末笔」;词组每字首笔(二字 2 码、三字 3 码、四字以上 = 前三字首笔 + 末字首笔)。
- 归一化:点与捺合并为
n、提并入横。 - 数据管线:以 CNS11643 全字庫「筆順資料」(
CNS_strokes_sequence.txt,官方定义 1 橫 / 2 豎 / 3 撇 / 4 點 / 5 折)作字形来源,经官方 CNS→Unicode 对照表映射;其上叠加大陆序覆盖表——CNS 是台湾标准,与大陆规范按部件成片不一致(艹:台 4 笔首笔竖 / 陆 3 笔首笔横;辶 4/3、阝 3/2),一级字抽样 299 字里 31 例笔画数不符(10.4%)。混合表不可接受:rime-stroke 就是双轨(花 = 艹 4 画台湾序、节 = 艹 3 画大陆序),大陆用户按学校笔顺敲不出 花 这类字。 - 工具:
tools/dict-convert新增stroke子命令,输入--cns-seq(笔顺表)、--cns-map(CNS→Unicode 对照)、--cns-count(可选,与笔画数自洽过滤,建议|d| ≤ 1)、--filter(字表白名单,取通用规范字表)、--prc-rules(大陆序覆盖),输出字\t[1-5]{n}(8,105 字约 40–80 KB)。原始 zip 不入库,走data/的既有惯例只留生成产物。
导入
- 「导入码表…」:接受 Rime
.dict.yaml,走系统打开文件对话框 / 文件选择器;失败时在窗口底部红字一行说明(例如「这个文件里没有识别到码表(需要词 + 码两列)」)。 - 导入完成给一份统计:读入多少条、多少词有码、多少词无码、跳过多少行。
- 引导导入的文案要写清:码表由用户自己取得(例如小鹤形的官方码表),青简不随包分发第三方形码表。
设置界面(两个壳都要做)
同一组设置项在两个平台的设置界面各出现一次,写进同一份 config.toml(配置文件是唯一事实源):
| 设置项 | macOS(偏好设置,AppKit) | Windows(设置程序,WinUI 3) |
|---|---|---|
| 触发键 | 录制按钮,缺省 ; |
录制控件,同一缺省 |
| 候选上显示码 | 勾选框,缺省不勾 | 同左 |
| 码表列表 | 随包笔画标「随包」不可移除;导入的显示名字 · 条数 · 许可,可开关、可移除(与「词库」页同构) | 同结构的一页 |
| 导入码表… | 系统打开文件对话框 | 系统文件选择器 |
设置项命名、文案与失败提示两平台保持一致;Core 只提供配置项与状态,界面归壳。
候选窗口与输入串
- 输入串(preedit):码段用淡色 + 下划线画法、
;不突出——与既有段样式同一套视觉词汇(敲的拼音正常色、剩余拼音画淡、被纠错改掉的画删除线)。Core 把码段作为新的段类型(MarkedKind)给出,两个壳各自落到自己的载体:macOS 走行内 marked text 与窗口拼音行,Windows 走protocol的PreeditSegment(TSF DLL 交给系统)。 - 候选:辅码态只出命中码的词(无码词隐藏);敲码筛空时候选窗口收起,只剩拼音行。
- 显示码开关打开时:码用方括号紧跟在候选词后面(
1 鹤[rbm] crane,渲染器Row.code,小字淡色):码是词本身的属性,不进右侧的 annotation;译文仍是候选词的单条 annotation(docs/design/architecture.md)。开着时不用进辅码态:纯拼音打字与辅码态空码段也把词的首条码挂上(边打边认码),筛码时显示命中的那条。竖排会比纯译文挤、横排更难放下,这是这个开关的已知代价(缺省关)。 - 窗口布局、视觉层级、翻页键等沿用
docs/design/candidate-ui.md;绘制归各壳(macOS 自绘 NSPanel,Windows Server 自绘候选窗与状态条)。渲染器 spike(crates/qingjian-render,分支renderer-spike)落地后两个平台都只贴图。
配置
| 键 | 缺省 | 说明 |
|---|---|---|
[general] aux_code_key |
";" |
触发键,可改反引号或 / |
[general] aux_code_show |
false |
候选上是否显示码(与译文拼接;开着时未进辅码态也显示词的首条码) |
[general] aux_code_keep_empty |
true |
码段删空后是否留在辅码态(空码段再按一次退格才退出);false 删空即回拼音态 |
[aux_code] enabled |
false |
辅码总开关:关掉整条辅码线(; 回到原生行为);开着但没有可用码表也不进辅码态 |
[aux_code] disabled |
[] |
关掉某张导入的码表,与 [dictionaries] disabled 同形 |
分层与落点
| 层 | 放什么 |
|---|---|
qingjian-core |
码段解析(触发键消歧、码段与拼音段分开记账)、码索引的两段式查询、过滤与重排、MarkedKind 新段;码表查询走 trait,不认识文件 |
qingjian-dictionary |
码表解析(.dict.yaml + columns / import_tables 规则)、独立码索引与落盘、导入统计 |
qingjian-platform |
配置项、码表与方案的目录与开关 |
| 平台壳 | macOS:apps/macos(IMK 偏好设置页、候选窗自绘);Windows:apps/windows/settings(WinUI 3 设置页)与 apps/windows/server(自绘候选窗与状态条)。两边都只做两件事:把码段画出来、把设置界面画出来 |
平台层不出现排序逻辑、词库访问或翻译调用(docs/design/architecture.md 的架构约束)。
测试与评测
- Core 单测:码段解析与消歧(
x;= xing、再;才进辅码)、逐键即筛、无码词隐藏、码段删空两态(缺省停在辅码态、aux_code_keep_empty = false回拼音态)、码表columns/import_tables/ 「有词无码」三类边界。 - 学习闭环:辅码态选词后,同输入串(纯拼音)首选命中——用
apps/cli --replay在现有输入日志上验。 - 评测:导入时报告「多少词有码 / 无码」,用码表覆盖率与
--eval-text的整句命中率当两把尺子。 - 排序、整句、纠错的改动一律先跑
--replay与--eval-text(仓库既有规矩)。 - Windows:本机只
cargo check --target x86_64-pc-windows-gnu;真编译与真机测试在 Windows 机器上做(Server + TSF DLL + 设置程序)。 - macOS:IMK 不能
cargo run验证,要apps/macos/scripts/bundle.sh --install装到本机;osascript往 TextEdit 发按键读回文本可做端到端。
许可
- 项目是 GPL-3.0-or-later(
LICENSE、Cargo.toml)。 - 小鹤形(小鹤音形的形码部分):官网声明「未经本站允许,不得用于任何商业目的」+ All Rights Reserved,无开放许可,不能随包;要内置须先取得作者书面许可。
- 自然码形:作者坚持商业发行,形码无授权记录,不能随包。
- 笔画(CNS11643 筆順資料):台湾数位发展部开放数据,许可为「政府資料開放授權條款第 1 版」或「OFL-1.1」二选一,可再分发、含商用,需署名——随包时在「关于」页与数据目录署名,沿用
assets/levels、assets/glossary的做法。 - Make Me a Hanzi / hanzi-writer-data:PRC 笔顺,只作开发期差异定位,不随包(其笔顺数据是 Arphic Public License)。
- 第三方码表不随包:码表由用户自己从官方渠道取得后导入;这是工程偏好(文件小、可控、不带上游维护负担),不是许可禁令。
- 用户导入第三方码表是用户自己的行为,不构成再分发。
后续与不做
平台范围:本设计对两个现役平台一视同仁——macOS(apps/macos)与 Windows(apps/windows/{server,tsf,settings})的壳与设置界面都要接;逻辑全在 Core,Linux 未开工,落地时走同一套通路,不需要改 Core。
落地分工(按 docs/contributing.md「一个 PR 只做一件事、只碰一个平台」):三步可以独立合,只有一个平台机器的人也能完成自己那一步——
| 步 | 范围 | 验证方式 |
|---|---|---|
| 1 | Core:码表解析、独立码索引、码段与两段式查询(单独一个 PR,不碰壳) | cargo test -p qingjian-core / -p qingjian-dictionary、apps/cli 手测、--replay |
| 2 | Windows 壳:Server / TSF 的 preedit 分段与候选绘制、apps/windows/settings(WinUI 3)的「辅码」页 |
Windows 机器上 cargo check --target x86_64-pc-windows-gnu + 真机部署(Server + DLL + 设置程序) |
| 3 | macOS 壳:IMK 的 marked text 分段、候选窗绘制、偏好设置页 | macOS 机器上 bundle.sh --install + 真机输入验证 |
第 1 步是后两步共同的前置;第 2、3 步之间没有依赖——先合哪一个都行,只有一个平台的贡献者只做自己那一步,另一平台由别的贡献者或维护者补。
后续(未定,需要时另开设计):简拼 + 辅码;整句转换 + 辅码(形码逐字约束进词图);码表导入后的生效时机与热切换。
不做:五笔原生表;社区码表在线下载 / 同步;内置任何第三方形码表。
参考
docs/design/candidate-ui.md:候选窗口与按键约定(本文的码段与注记沿用它的视觉词汇)。docs/design/architecture.md:Core 与平台层的划分、翻译是单条 annotation 的约束。- 渲染器 spike(分支
renderer-spike上的crates/qingjian-render与docs/design/rendering.md):候选窗一帧 + 主题 → 位图,各平台只贴图。 docs/notes/crate-notes.md:各 crate / app / tool 的实现要点(改了实现要同步那里)。docs/plan/todo.md:排期与进度。