Text(文本与本地化)
Text 把剧本中的文本按当前语言解析成可显示的文本段,并负责逐字显示、字体选择与缺失词条提示。它是文本呈现的统一入口,但不推进剧本。
顶部信息表
| 项 | 内容 |
|---|---|
| 契约版本 | text@1 |
| 当前状态 | 测试中 |
| 源码目录 | src/core/text |
| 页面定位 | 面向小插件作者与外壳集成者,说明可用服务、插槽、实现位与逐字显示边界 |
职责
负责:
- 按当前语言解析台词,把 IR 文本转成文本段;
- 把台词渲染到容器,支持字重、语义色与换行;
- 逐字显示、中止与速度控制;
- 语言表查询、缺失词条记录与语言切换通知;
- 台词字体登记,以及按章、按语言选择子集字体。
不负责:
- 剧本推进、选项、历史与自动播放,见 ScriptPlay;
- 资源的读取、解码、缓存与字体子集化,见 Asset;
- 舞台、立绘与镜头,见 Stage;
- 对话框的推进节奏与存档;内置对话框只消费
text:view。
对外接口
名称与 policy 以 src/core/text/contract.ts 为准。
| 名称 | 类别 | policy | 说明 |
|---|---|---|---|
text:view | 服务 | trusted | 渲染台词、控制逐字速度 |
text:style | 服务 | trusted | 只声明,当前不提供 |
i18n:runtime | 服务 | trusted | 语言、查表、台词解析与缺失词条通知 |
text:resolve-style | 机制插槽 | public | 只声明,当前不提供 |
text:compute-measure | 机制插槽 | trusted | 只声明,当前不提供 |
text:on-advance | 通知 | — | 只声明 |
text:on-history-push | 通知 | — | 只声明 |
text:fonts | registry | public | 数据包登记台词字体 |
text:shaper@1 | 实现位(single) | public | 逐字显示与排版;内置条目 builtin,卸载后回落 |
i18n:resolver@1 | 实现位(single) | public | 语言选择规则;当前空缺 |
text:view
render(text, container, { reveal? }):把 IR 文本渲染到容器。reveal.cps为每秒字数,必须是非负数;reveal.signal中止后兑现,不再继续显示。- 粗体按字重呈现,语义色使用设计系统的同名 CSS 变量,
\n为换行。 - 只写纯文本节点,不把文本当 HTML 解释。
- 同一容器上先发后至的旧渲染结果不覆盖新结果。
speed()读取逐字速度,setSpeed(cps)写入;范围 0–120,缺省 40,0 表示立即显示。
i18n:runtime
language()/setLanguage(tag):读取与切换当前语言标签。subscribe(listener):订阅语言变化,返回取消订阅函数。lookup("<ns>:<键>"):异步查表,查不到返回undefined。resolve(台词):异步把 IR 文本解析成文本段。notices():返回缺失词条记录。
关键语义
渲染顺序
- 解析当前语言下的文本段。
- 取得本章、本语言对应的字体族。
- 写入文本节点与字体族。
- 若带
reveal,交给当前text:shaper@1逐字显示。
渲染开始时会取得容器的最新请求标记;等待解析期间若有更新的渲染请求,旧请求直接放弃,避免慢请求覆盖新台词。
语言表与回退
- 语言表位于资源包的
assets/<ns>/lang/<语言标签>.json,是扁平的「键 → 文本」对象,经asset:acquire取用。 - 初始语言取宿主报告的界面语言。
- 查表按语言标签逐级去掉末尾子标签回退,例如
zh-Hans-CN→zh-Hans→zh。 - 查表或字体子集等待期间如果语言发生切换,旧语言的异步结果作废并按新语言重新查找,不把过期文本写回。
- 查不到时原样显示
<ns>:<键>,并记入notices();剧本照常推进。 - 收到
asset:on-invalidate后释放命中的语言表;资源包遮住原表后,下次查表即生效。
逐字显示边界
- 内置 shaper 先排好全文,再按字素簇显示;有
Intl.Segmenter时使用平台分段,没有时回退最小字素算法,合并组合标记、变体选择、肤色修饰、ZWJ 链、区旗、标签序列及 CRLF,不拆组合字符或 emoji 序列。 - 排版宽度不随显示进度变化,避免逐字时发生回流跳动。
cps为 0 或快进中立即显示全文。- 内置对话框的正文按当前速度逐字显示;逐字过程中第一下点击(或点舞台)显示全文,第二下才推进;自动模式在显示完毕后再开始计等待。
text:shaper@1是 single 实现位;插件条目卸载后回落内置builtin。
台词子集字体
- 数据包在
data/text/fonts/<ns>/<名>.json登记{ asset, languages? }。 - 未写
languages即通用;写了则按语言标签或其前缀匹配,取第一条匹配项。 - 该章第一次渲染台词时,从本章入口图出发,沿跨图出边收集可达各图的台词、说话人、选项与提示文本。
- 按当前语言取词、去重后,经
asset:acquire(<asset>, { as: 'font', variant: { subset } })取得只含这些字符的子集字体并装入文档。 - 台词容器的字体族写成「子集字体, 原有字体族」,子集里没有的字由原有字体族补上。
- 同章同语言复用;换章或换语言即装入新字体、撤下并释放旧字体;不在章节里播放时不装。
- 取用失败只告警,台词继续使用原有字体族显示。
- 界面语言和字体安装由
platform:host提供;宿主无法报告语言时使用und,没有字体安装能力时跳过章节子集字体并继续使用原有字体。Text 不直接读取浏览器全局对象。 - 字体条目的
asset与 Asset 共用同一套安全 VPath 判定,拒绝路径穿越、空段与过深路径;文本段清洗只接受对象自身的text、bold与color字段,不采纳原型链上的同名属性。
当前实现范围
- 已完成:
text:view的渲染、逐字显示与速度控制;i18n:runtime;text:fonts登记与语言匹配;text:shaper@1的内置builtin条目。 - 测试中:插件整体。Node 与系统 Edge 的用例已覆盖数据部分、逐字显示与子集字体,但 Phase 2 的出口核验尚未全部完成,因此不记为「已完成」。
- 未实现:
text:style、text:resolve-style、text:compute-measure仅在契约中声明,当前不提供;i18n:resolver@1实现位空缺。 - 未覆盖:Windows WebView2 与 Android 上的真实内容复跑尚未进行。
相关链接
- 插槽与实现位:
text:shaper@1的回落规则与 single 实现位语义。 - policy 与写边:
trusted服务与publicregistry 的差别。 - 装载管线与 guard:小插件登记实现位前的准入流程。
- ScriptPlay:对话框与历史记录如何消费文本服务。
- Asset:语言表与字体资源的取用、缓存与失效。