先添加运行时 i18n 库,再转换 Copilot 已经写下的字符串,最后杜绝新的硬编码。大多数团队在最后一步出错,因为仓库指令文件并不能覆盖 Copilot 写代码的所有场景:聊天和 coding agent 会读取它,内联自动补全不会。globalize.now 是 AI 驱动的本地化基础设施,一次性转换代码库,并生成 i18n 库所读取的键和语言文件。
为什么添加了指令文件后,Copilot 仍然硬编码字符串?
因为指令文件没有接入最快的那条路径。VS Code 的文档明确指出,自定义指令不会作用于你边输入边出现的内联建议,而这恰恰是大多数人一天中用得最多的模式。
所以,你写的规则是有效的:在聊天中向 Copilot 提问,或把任务交给 coding agent 时,它会生效;但当你敲出一个 JSX 标签、按 Tab 接受灰色补全时,它就不起作用。这两种方式产出的都是会被提交的代码,却只有其中一种读过你的规则。
哪些 Copilot 场景会读取你的指令?
有三个场景会向你的仓库写入代码,它们的行为并不相同。
| 场景 | 是否读取指令? | 输出落点 |
|---|---|---|
| 内联补全 | 不能 | 直接写入你正在编辑的文件 |
| 聊天和 agent 模式 | 能 | 在编辑器中审阅的修改 |
| Coding agent | 能 | 待你审阅的草稿 PR |
对这个问题来说,coding agent 是三者中最友好的。你把 issue 分配给它,它在后台工作并打开一个草稿 PR,因此它的输出会落在审阅者本来就会查看的地方。而内联补全的输出没有任何关卡。
如何在 Copilot 项目中配置 i18n?
先选定框架对应的运行时库。Next.js App Router 用 next-intl,其他 React 应用用 react-i18next,想要编译期提取和 PO 目录就用 Lingui。我们在 next-intl vs react-i18next vs Lingui 中对比过这三者。
Copilot 不像 Lovable 或 Bolt 那样绑定特定框架,技术栈和库的选择完全由你决定。但顺序不能乱:先安装库,转换现有字符串,最后再考虑如何防止问题再次出现。如果代码库里仍有 90% 是硬编码的英文,这时写预防规则,根本无从衡量效果。
.github/copilot-instructions.md 里该写什么?
该路径下的仓库指令文件会被自动识别,并应用于工作区中的聊天请求。GitHub 官方的建议是:每条指令简短且自包含,说明背后的理由,并跳过 linter 已经强制执行的内容。按这个思路写的 i18n 部分篇幅很小:
## User-facing text
- User-facing text belongs in the message catalog, never in a component literal.
- Use the translation function from our i18n library for every visible string.
- Reason: a literal cannot be translated and does not show up as a missing key,
so it ships silently in one language.
- Add new English values to the source catalog only. Never hand-edit other locales.
- Not user-facing: test names, log lines, error codes, internal constants.
最后一行比看上去重要得多。过度适用的规则会被忽略,如果规则要求 agent 包装日志消息,它就会认定整段规则都是噪音。如果你还没有指令文件,VS Code 可以在聊天中用 init 命令根据代码库生成草稿,这比从空白文件开始更好。
路径级指令文件能做得更好吗?
能。这是 Copilot 独有的能力,其他编辑器的规则文件都做不到。以 .instructions.md 结尾、存放在 .github/instructions 下的文件,会在 frontmatter 中声明 applyTo glob,只有 Agent 操作匹配的文件时才会加载。
---
name: 'UI strings'
description: 'String handling rules for components'
applyTo: '**/*.{jsx,tsx}'
---
Every visible string in this file must come from the catalog.
Key format is feature.element.state, lowerCamelCase.
If you add a key here, add its English value to the source catalog in the same change.
把规则限定在组件文件上,才能让它保持可信。它只在存放用户可见文本的地方生效,在 API 路由和迁移脚本中保持安静。如果仓库根目录已有 AGENTS.md 或 CLAUDE.md,Copilot 也会把它们当作常驻指令读取,所以同时使用多个 agent 的团队不必为每个工具单独维护一份文件。
指令漏掉的字符串由什么兜底?
CI 中的 lint 规则,因为这是整套方案里唯一能让构建失败的一层。指令只能改变概率,而检查失败会直接改变结果。我们在 为什么 AI agent 总在添加硬编码字符串 中详细讲过这一层强制措施,这套配置可以原样用于 Copilot 仓库。
Copilot 特有的补充点是 PR。仓库指令既作用于聊天,也作用于 Copilot 代码审查,所以同一份文件既约束代码生成,也约束针对 coding agent 草稿 PR 的审查评论。这样就有了一道内联自动补全绕不过去的关卡,也最接近解决本文开头所说的缺口。
这些都无法清偿仓库里已有的技术债,也不会填充任何语言文件。审查时发现一个字面量,只说明有字符串缺失。接下来仍需有人为它建键、翻译,并避免其他语言 逐渐失去同步。
globalize.now 在哪个环节发挥作用?
在生成翻译目录的那一层,这恰恰是 i18n 库和指令文件都不负责的部分。在应用中连接仓库后,它会一次性转换整个代码库,用翻译键替换硬编码字符串并生成语言文件。这次一次性转换完成后,每次推送都会触发任务,翻译你的提交带来的新增目录单元。
输出格式为 JSON 或 PO,目录直接落成运行时库本来就能读取的结构。同样的方式也适用于其他 agent 式编辑器:Claude Code 和 Cursor 从另一个方向撞上了同一堵墙。针对 Next.js 代码库的分步教程见 为 AI 构建的 Next.js 应用添加 i18n。转换流程的更多细节见开发者文档,套餐信息见定价页面。
一句话总结
写好指令文件,为组件文件配置路径级规则,再在 CI 里加一条 lint 规则,这样 Copilot 被告知的和实际写出的之间出现偏差时,得到的是一次红色构建,而不是一个上线的英文字符串。然后一次性转换积压的字符串,让规则有一套一致的基线可守。
globalize.now 把硬编码的应用文案转换为可直接翻译的语言文件,并在你持续发布时保持同步更新。
免费试用 globalize.now