Lovable 从三个地方读取 i18n 规则:工作区和项目 Knowledge,始终在上下文中;Skill,只在提示与其描述匹配时加载;以及已连接仓库中的指令文件,其中根目录的 AGENTS.md 无论对话进行了多久都会被读取。规则放错地方,你上周刚翻译好的应用,下一个功能就会以英文上线。globalize.now 是 AI 驱动的本地化基础设施,我们在大量 Lovable 仓库里见过这类错误的后果;解决办法主要就是搞清楚每个位置是在什么时候被读取的。

为什么已翻译的 Lovable 应用会变回英文?

因为让应用支持多语言的那条指令,在 agent 编写下一个组件时并不在它眼前。Lovable 只解决屏幕上这条提示。如果提示是“添加一个用户评价区块”,而上下文中没有任何内容说明“所有用户可见字符串都要经过 <Trans>”,标题就会以字面量的形式写进去,和全新项目里一模一样。

这和翻译目录落后于代码不是同一个问题,后者是同步失败,详见为什么每次发布,Lovable 应用的翻译都会出问题。同步只能把已包装的字符串搬进语言文件,搬不了从未被包装的字符串。上游的问题是:Lovable 写代码的那一刻读到了什么。对此,Lovable 的文档说得格外具体。

Lovable 在修改代码之前到底读取了什么?

根据其 Knowledge 文档,项目 Knowledge、工作区 Knowledge,以及 Git 仓库中的指令文件(如 AGENTS.md 或 CLAUDE.md),都会与项目代码一起指导 agent。Skill 则是独立的,按需加载。

它们在三个方面有所不同,对 i18n 都很关键。

读取时机。 Knowledge 随每条消息一起发送。Skill 只在请求与其描述匹配时才会加载。按 Lovable 的说法,根目录的 AGENTS.md 无论会话多长都会被读取。

在长对话中的持久性。 Lovable 文档明确提醒:在上下文很多的超长对话中,Knowledge 里的指令可能无法被一致地遵循。同一页面对根目录的 AGENTS.md 则给出了相反的说法。这种不对称,正是本文存在的全部原因。

谁能编辑。 工作区 Knowledge 仅限所有者和管理员编辑。项目 Knowledge 可由任何拥有该项目编辑权限的人修改。仓库文件则由任何有推送权限的人编辑,Lovable agent 自己也包括在内。

每一级 Knowledge 最多容纳 10,000 个字符。放一段指引绰绰有余,但如果还要塞进架构说明、数据库 schema 和品牌语气,完整的规则集就远远放不下了。

那么,i18n 规则到底该放在哪里?

放在仓库里,再在 Knowledge 中留一段简短的指引。理由可以从上面的对比中得出。

仓库根目录的 AGENTS.md 承载完整规则。 无论会话多长,它都会随每条消息被读取;它存放在 Git 中,所以新开对话、新增协作者、换用其他 agent 都不会丢失;而且它没有字符上限,不会和项目的其他上下文争抢空间。lovable-i18n Skill 执行初始化时,第三阶段写入的正是这个文件:在 <!-- lovable-i18n:rules:start --> 和 <!-- lovable-i18n:rules:end --> 标记之间放一段 Lingui 规则块,文件不存在就创建,已存在就追加,重复运行时只替换标记之间的内容,不会产生重复。

项目 Knowledge 里放一段两行的指引。 大致如下:

Localization
- This app is localized with Lingui. Every user-visible string is wrapped
  (<Trans>, t``, msg``) and new strings are appended to src/locales/*/messages.po.
- The full rules are in AGENTS.md at the repo root. Follow them on every edit.

这段指引是为文档警告的那种情况准备的。如果长对话稀释了 Knowledge,agent 仍能读到仓库文件;如果仓库文件因故不在上下文中,这段指引也会点明约束。两处入口,同一条规则。

只有所有项目都用同一个库时,才写进工作区 Knowledge。 工作区 Knowledge 作用于工作区内所有项目,而且只有一份。如果你一半项目用 Lingui,另一半用别的方案,那么工作区级别的 Lingui 规则对其中一半就是错的;况且冲突时 Lovable 本来就会优先采用项目 Knowledge。工作区 Knowledge 留给放之四海而皆准的规则:按钮使用句首大写、不使用 console.log、代码注释用英文。

Skill 不是存放规则的地方。 刚导入它的人常常对此感到意外。Skill 在提示与其描述匹配时才会加载,所以你请求设置 i18n 时 lovable-i18n 在上下文里,而你请求做结账页时它就不在。这是有意为之的设计;如果 Skill 在每条消息中都加载,那它就只是 Knowledge 了。Skill 的任务是把持久规则一次性写入仓库,然后功成身退。

AGENTS.md 里的规则都写了什么?

它们回答的,正是 agent 在只被告知“使用 i18n”时会答错的那些问题。Skill 写入的规则块包含六个部分。

用哪个宏。 一份决策清单:随数字变化的文本使用 <Plural> 或 ICU 复数;JSX 文本使用 <Trans>;属性值和事件处理函数里的字符串(如 toast)使用 useLingui() 返回的 t;模块作用域的常量使用 msg,并在组件内部解析。规则还会写明每个宏对应的导入路径,因为导入错误的 t 会绑定到应用从未加载的全局实例上。

插值。 只有裸变量才会在提取出的消息中拥有自己的占位名。其他任何表达式都会被提取为 {0},译者无从处理,所以规则要求用 ph() 为其命名。

复数。 other 始终必填,类别遵循 CLDR,并且禁止在两个字符串之间用三元表达式,因为这会把英语的复数规则硬编码进组件。如果想了解背景,什么是 ICU MessageFormat 介绍了复数形式所编译成的语法。

数字和日期。 使用 i18n.number() 和 i18n.date(),绝不使用 toFixed(),也不要把货币符号拼接在数值上。Lovable 自己的工作区 Knowledge 示例里就有一个本地化小节,设定了日期格式和欧洲数字格式,思路是对的,但那是格式化规则,不是包装规则。应用可以完美遵守它,却照样把每个标题都以英文发布。

译者注释。 含多种解读的短字符串、单独的操作标签和领域术语,要加上 comment= 说明该字符串出现的位置。context= 仅用于同一文本在不同位置需要不同译法的情况。

目录维护。 每个新字符串都要先包装,再以空的 msgstr 追加到每个 src/locales/*/messages.po 中,这样在译文到位之前,Lingui 会回退到源文本。agent 永远不要运行 lingui extract,因为 Lovable 里没有终端;同步之后由 GitHub Action 来运行。它也不要改动现有条目上的 #. 和 #: 注释行,因为提取时会重新生成它们。

最后这一部分,正是这套规则专属于 Lovable 的地方。Cursor 或 Claude Code 的规则文件可以用“运行 linter”收尾,而 Lovable 的规则文件不行,所以它必须写明哪些要手动完成,哪些留给 CI。

Lovable 什么都运行不了时,靠什么来强制执行规则?

靠 GitHub 工作流,也只能靠 GitHub 工作流。Lovable 没有终端,所以从 agent 写出字面量到变更同步进仓库之间,没有任何 lint 步骤。这是它与 IDE agent 的结构性差异;在 IDE 里,CI 中的 lint 规则会让构建失败,从而拦住硬编码字符串。

如果你在初始化时选择启用,Skill 会添加一个 GitHub Actions 工作流,它在推送到默认分支时运行(Lovable 的同步正好落在这里),把已包装的字符串提取到翻译目录,并把目录同步结果提交回仓库。如果 GitHub app 缺少 workflows 权限,Skill 会提示你在 GitHub 上手动添加该文件。对于 agent 已包装的内容,这就形成了闭环;对于 agent 没有包装的字符串则无能为力,因为提取只认宏。

所以实际情况是:AGENTS.md 中的规则降低了未包装字面量出现的频率,Knowledge 里的指引在长对话中提供兜底,其余的漏网之鱼则要靠 GitHub 上的 diff 来发现。如果想让机器来抓这些漏网之鱼,就把 eslint-plugin-i18next 的 no-literal-string 规则作为一个步骤加进同一个工作流。它运行在仓库上,而仓库是 Lovable 项目里唯一能运行任何东西的地方。

那些确实被包装的字符串后来怎么样了?

它们需要翻译,而这正是值得自动化而不是反复重新提示的部分。转换是一次性的,在应用内完成:连接仓库后,globalize.now 对代码库做一次转换,并以 PR 的形式交付翻译目录供你审查。此后,推送任务会在新目录条目出现时自动翻译,所以 Lovable 周二写下的 <Trans>,周三就会有包含其译文的 PR。没有仪表盘操作,不用导出,也没有审批队列;这种方案的更完整论述见不用仪表盘,本地化 Lovable 应用,包括 GitHub 连接和 globalize 连接器在内的具体配置路径,见 Lovable 集成页面。

补充一点背景,因为它能解释为什么这个问题对一些 Lovable 开发者来说像是新问题。Lovalingo 在浏览器中以运行时方式翻译 Lovable 应用,所以新生成的英文组件加载时直接被重新翻译,这个问题就从未暴露出来。它已于 2026 年 8 月 31 日停止服务,而通过迁移指南 迁移到提交式翻译目录的应用,是第一次碰到这个上游问题。目录模式是正确的取舍,因为翻译后的标记归你所有、可被索引,但它要求 agent 写出可翻译的代码,这意味着你得告诉它规则在哪里。

把规则放在 Lovable 会读的地方

运行一次 Skill,让 AGENTS.md 带上完整的规则块,把那段两行指引粘贴进项目 Knowledge,再让 GitHub 工作流去完成编辑器做不到的提取。如果你在用 Lovable 开发,希望进入翻译目录的所有内容都由系统代为翻译而不是自己维护,vibe coder 页面 是总览,定价 则单独成页。

globalize.now 把硬编码的应用文案转换为可直接翻译的语言文件,并在你持续发布时保持同步更新。

免费试用 globalize.now