前言

Rime 本身是一套高度可定制的输入法框架。除了常规的拼音输入、词库管理和候选排序之外,还可以通过 Lua 扩展实现动态内容生成。

一个比较实用的例子,是输入特定拼音后直接生成当前日期、当前时间、星期等内容。例如:

riqi
xianzai
shijian
xingqi

可以分别得到类似:

2026-08-23
2026/08/23
20260823

2026-08-23 21:10:35

21:10:35

星期日

这些内容不是提前写进词典的静态词条,而是在输入时调用系统时间动态产生。

这一功能最初在 Linux 环境下完成并稳定使用。之后需要将同样的能力迁移到 Windows 上的 Rime,也就是小狼毫 Weasel。

实际迁移过程并不是简单复制一个文件即可完成。Linux 与 Windows 的 Rime 前端、用户目录以及部署行为都存在差异,尤其是在 Windows 上还遇到了重新部署后 build 内容没有正确刷新的情况。

经过多轮检查和最小化修改,最终成功在 Windows 上完整复现了 Linux 下的动态日期时间输入功能。


一、Linux 下的实现结构

Linux 环境使用 Fcitx5 + Rime。

实际生效的 Rime 用户目录位于:

~/.local/share/fcitx5/rime/

动态日期时间功能主要由三个部分构成:

rime.lua
lua/date_time.lua
luna_pinyin_simp.custom.yaml

完整调用链可以概括为:

用户输入关键字
        ↓
Rime Schema Translator
        ↓
lua_translator@date_time_translator
        ↓
rime.lua
        ↓
require("date_time")
        ↓
lua/date_time.lua
        ↓
os.date(...)
        ↓
动态生成候选

这说明该功能本质上是一个 Rime Lua Translator


二、rime.lua:注册 Lua 模块

Rime 会通过用户目录中的 rime.lua 加载 Lua 扩展。

核心逻辑类似:

local ok, date_time = pcall(require, "date_time")

if ok then
    date_time_translator = date_time
end

这里完成两个动作:

  1. 加载 date_time Lua 模块;
  2. 将模块暴露为 date_time_translator

之后 Schema 就可以通过:

lua_translator@date_time_translator

调用这个模块。

使用 pcall() 的好处是,即使模块加载失败,也不至于直接因为 Lua 异常破坏整个 Rime 初始化流程。


三、date_time.lua:真正生成日期和时间

主要逻辑位于:

lua/date_time.lua

这个 Lua Translator 会检查用户当前输入的字符串。

例如:

riqi
date

可以映射到当前日期。

Lua 中通常使用:

os.date(...)

获取系统当前时间。

例如:

os.date("%Y-%m-%d")

产生:

2026-08-23

而:

os.date("%Y/%m/%d")

产生:

2026/08/23

还可以进一步组合不同格式。


四、支持的动态关键字

实际实现中包含几组常用关键字。

日期

例如:

riqi
date

可以产生:

2026-08-23
2026/08/23
20260823

也可以生成中文日期以及星期信息。

当前日期时间

例如:

xianzai
riqishijian
datetime

可以产生:

2026-08-23 21:10:35

以及中文日期时间等格式。

时间

例如:

shijian
time

可以产生当前时间。

星期

例如:

xingqi
week

可以产生:

星期日

最大的优势在于,这些值不是词库里的固定文本。

每次调用:

os.date(...)

读取的都是系统当前时间。


五、Schema 才是让 Lua Translator 真正生效的关键

仅仅存在 rime.lua 和 Lua 文件还不够。

还必须让当前输入方案的 engine/translators 调用 Lua Translator。

对应的自定义配置文件为:

luna_pinyin_simp.custom.yaml

其核心逻辑是:

patch:
  "engine/translators/@before 3": lua_translator@date_time_translator

也就是说,在原有 Translator 列表中插入:

lua_translator@date_time_translator

因此真正的运行链是:

Schema
→ lua_translator
→ rime.lua
→ date_time.lua

缺少任何一环,功能都不会工作。


六、Linux 下如何确认功能确实来自 Lua

排查过程中,一个重要问题是:

riqixianzai 究竟是词库里的静态词条,还是 Lua 动态生成的?

不能只看到候选结果就下结论。

可以从几个层面确认。

首先搜索:

riqi
xianzai
date_time
os.date
lua_translator

如果关键字只存在于 Lua 代码而不是词典文件,已经是很强的证据。

其次检查编译后的 Schema:

build/luna_pinyin_simp.schema.yaml

其中应存在:

lua_translator@date_time_translator

最后,如果 Rime Lua 日志能够看到类似:

translator called: xianzai

以及动态生成的当前时间候选,则基本可以确认完整链路。

这比单纯看到输入结果更加可靠。


七、迁移到 Windows

Windows 使用的是小狼毫 Weasel。

其用户 Rime 目录通常位于:

%APPDATA%\Rime

展开后类似:

C:\Users\<USER>\AppData\Roaming\Rime

迁移时并没有复制整个 Linux Rime 用户目录。

这是非常重要的一点。

Linux 与 Windows 之间存在:

  • 前端差异;
  • 部署环境差异;
  • 默认配置差异;
  • 用户目录差异;
  • 编译产物差异。

因此最安全的方式是:

只迁移实现目标功能所需要的最小文件。


八、Windows 需要迁移的文件

最终只需要复制或创建:

Rime\rime.lua
Rime\lua\date_time.lua
Rime\luna_pinyin_simp.custom.yaml

结构如下:

Rime
├── rime.lua
├── luna_pinyin_simp.custom.yaml
└── lua
    └── date_time.lua

其中:

  • rime.lua 负责加载 Lua 模块;
  • date_time.lua 负责生成动态内容;
  • luna_pinyin_simp.custom.yaml 负责把 Lua Translator 插进 Schema。

这是整个功能最核心的最小集合。


九、第一次遇到的问题:Weasel 部署没有刷新 build

按正常逻辑,在修改用户配置后执行 Rime 部署,应该重新生成:

Rime\build\

Windows 下也尝试调用了 Weasel 的部署程序。

然而实际出现了一个比较特殊的情况:

部署命令虽然执行了,但编译后的 Schema 并没有真正刷新。

检查:

build\luna_pinyin_simp.schema.yaml

之后发现其中仍然没有:

lua_translator@date_time_translator

这意味着:

用户 custom.yaml 已正确

并不等于:

当前运行中的 build schema 已正确

这是整个 Windows 迁移过程中最关键的排查点之一。


十、为什么一定要检查 build Schema

Rime 的用户配置与实际运行配置之间存在编译过程。

可以简单理解成:

用户配置
    ↓
部署
    ↓
build
    ↓
Rime 实际运行

因此:

luna_pinyin_simp.custom.yaml

只是配置来源。

真正需要确认的是:

build\luna_pinyin_simp.schema.yaml

其中最终是否已经出现:

lua_translator@date_time_translator

如果没有,那么即使源配置写得完全正确,也可能依然没有生效。


十一、最终采用的最小修复方式

由于正常部署没有刷新对应 build 文件,最终采用了非常有限的手动修复。

首先备份:

build\luna_pinyin_simp.schema.yaml

备份命名可以采用:

原文件名.YYYYMMDD-HHMMSS

例如:

luna_pinyin_simp.schema.yaml.20260823-211000

随后发现目标 build 文件带有 Windows 的只读属性。

因此操作顺序是:

备份
↓
临时去掉 Read-only
↓
进行最小修改
↓
加入 lua_translator@date_time_translator
↓
恢复 Read-only 属性

没有改动其他 Schema 内容。

最终在:

build\luna_pinyin_simp.schema.yaml

中确认:

lua_translator@date_time_translator

已经存在。


十二、重新加载 Weasel

修改完成之后,需要重新启动 Weasel 服务进程。

这样可以让当前桌面输入法重新读取已经修正的配置。

验证至少包括:

riqi
xianzai

并可以进一步验证:

shijian
xingqi

最终桌面环境中确认:

  • riqi 可以动态生成当前日期;
  • xianzai 可以动态生成当前日期时间;
  • Lua Translator 工作正常。

至此,Windows 端复现成功。


十三、随后复制到另一套 Windows 系统

在第一套 Windows 环境成功之后,另一套 Windows 系统也需要部署相同功能。

这次就不再需要重新分析 Linux 实现。

已经验证成功的 Windows 环境可以直接作为标准源。

迁移关系因此变为:

已验证 Windows
        ↓
另一套 Windows

而不是:

Linux
 ↓
重新研究
 ↓
Windows

这极大降低了不确定性。

需要复制的依然只是:

rime.lua
lua\date_time.lua
luna_pinyin_simp.custom.yaml

之后检查:

build\luna_pinyin_simp.schema.yaml

如果正常部署没有正确生成 Lua Translator,则按照前一次已经验证的方法进行相同的最小修复。

最终第二套 Windows 环境也成功实现了:

riqi
xianzai
shijian
xingqi

等动态输入。


十四、为什么不应该直接复制整个 Rime 目录

跨系统迁移输入法配置时,很容易想到:

把整个 Rime 目录复制过去

但这种方式风险较高。

一个完整 Rime 用户目录中可能同时存在:

  • 输入方案;
  • 用户词典;
  • 编译后的 build;
  • OpenCC 数据;
  • 缓存;
  • 用户同步数据;
  • 前端相关设置;
  • Lua 扩展;
  • 操作系统特定配置。

Linux 与 Windows 的运行环境并不完全相同。

直接整体覆盖可能导致:

为了复制一个小功能
→ 连带覆盖大量无关配置
→ 引入新的问题

因此这次实践采用的原则是:

先找到功能的真正依赖链,再只迁移依赖链。

最终确认真正需要的是:

rime.lua
        ↓
date_time.lua
        ↓
lua_translator
        ↓
schema patch

其他配置都不需要碰。


十五、这次排查中最有价值的方法

1. 不通过文件名猜实现

发现一个叫:

date_time.lua

的文件,并不能证明它真的被调用。

必须继续检查:

谁 require 它?

然后检查:

谁调用这个 Lua Translator?

最后再检查:

编译后的 Schema 中是否真正存在?

这才是一条完整证据链。


2. 区分源配置和运行配置

Rime 中尤其要注意:

custom.yaml

和:

build/*.schema.yaml

不是同一个层级。

前者代表:

希望 Rime 如何配置

后者代表:

当前实际编译出了什么

排查“配置明明写了为什么不生效”时,检查 build 往往非常关键。


3. 动态功能不要写进静态词库

日期和时间本质上是动态数据。

如果使用词典硬编码:

riqi    2026-08-23

第二天就会失效。

Lua Translator 的优势就在于:

os.date(...)

每次输入时实时生成。

因此特别适合:

  • 日期;
  • 时间;
  • 星期;
  • 时间戳;
  • 格式化年月日;
  • 其他根据当前环境计算的内容。

4. Windows 和 Linux 不必完全配置一致

跨平台配置的目标不应该是:

两边目录中的每一个文件都相同。

真正应该追求的是:

两边实现相同的用户功能。

只要最终都能形成:

Schema
→ lua_translator
→ Lua 模块
→ 动态候选

那么底层文件组织存在少量平台差异是完全可以接受的。


十六、推荐的迁移流程

如果以后需要迁移类似 Rime Lua 功能,可以按照下面的顺序处理。

第一步:在源系统建立完整证据链

确认:

触发关键字
↓
Schema
↓
Lua Translator
↓
Lua 模块
↓
动态生成函数

第二步:找出最小依赖文件

不要复制整个 Rime 用户目录。

第三步:检查目标系统已有配置

尤其避免覆盖已有:

*.custom.yaml
rime.lua
lua/

第四步:修改前备份

尤其是已有文件。

第五步:正常重新部署

优先让 Rime 自己生成 build。

第六步:检查 build

不要只检查源配置。

第七步:必要时才修改 build

只有在正常部署明确失败,并且已经知道应该生成什么内容时,才考虑这种方式。

第八步:重载输入法前端

例如重启 Weasel。

第九步:桌面实际输入验证

最终验证应当发生在真实输入环境,而不只是文件层面。


十七、最终结构

整个功能最终可以抽象为一个非常简单的结构:

输入:
riqi
xianzai
shijian
xingqi

        ↓

luna_pinyin_simp
        ↓
lua_translator@date_time_translator
        ↓
rime.lua
        ↓
lua/date_time.lua
        ↓
os.date(...)
        ↓
动态候选

最初这一方案只存在于 Linux。

经过逐层确认调用关系、识别最小依赖、处理 Windows Rime 部署差异,并验证编译后的 Schema,最终在多套 Windows 环境中成功复现。


总结

这次 Rime 日期时间功能迁移最有价值的地方,并不是复制了几个配置文件,而是完整理清了 Rime 一个扩展功能从源代码到最终候选之间的运行链。

最终得到的几个关键结论是:

  1. 动态日期和时间适合通过 Lua Translator 实现。
  2. rime.lua 负责加载模块。
  3. date_time.lua 负责通过 os.date() 动态生成内容。
  4. Schema 必须显式加载 lua_translator
  5. custom.yaml 正确不代表部署后的 build 一定正确。
  6. Windows 上遇到异常时,应检查最终编译出的 Schema。
  7. 跨平台迁移应采用最小依赖复制,而不是整个用户目录覆盖。
  8. 第一套 Windows 验证成功后,可以将其作为后续 Windows 系统的标准模板。
  9. 文件层验证完成后,最终仍应通过真实桌面输入进行端到端确认。

最终结果是,一套最初在 Linux 环境构建的 Rime Lua 动态输入方案,被完整、稳定地复现在 Windows 环境中,同时保留了原有输入法配置,并且没有为了实现一个小功能而进行不必要的整体迁移或重构。

Leave a Reply

Your email address will not be published. Required fields are marked *