测试(Vitest)
在 vitest.config.ts 中使用 aiI18nVitest(),即可测试导入 virtual:ai-i18n 的业务模块,无需
手写 alias 或 mock。测试环境不执行自动翻译,也不会修改项目中的翻译文件。
如果项目曾为 virtual:ai-i18n 添加 alias 或 vi.mock(),请先删除。手写 mock 会替换
aiI18nVitest() 提供的整个测试 Runtime;即使配置文件已经注册插件,测试实际调用的仍可能是
mock。数组被拼成字符串、对象结构丢失或数组下标只返回一个字符时,应优先检查测试 setup 中的
vi.mock('virtual:ai-i18n')。
如果 Vitest 输出“仅支持浏览器 Runtime,已跳过 SSR 转换/注入”,说明测试配置加载了生产用的
aiI18n()。不要忽略或静默过滤该提示;从 @ai-i18n/vite/vitest 改用
aiI18nVitest(),并确保同一测试配置只注册其中一个插件。
它支持 t()、useI18n()、Vue tRef()、纯 Options 的 i18nComputed() /
tComputed()、消息集合宏和自动导入。测试配置的 autoImport 应与正式 Vite 配置保持一致。
Jest 或直接 Node.js 执行不会处理消息集合宏,请改用 Vitest 配置或避免执行包含宏的源码。
快速开始
大多数项目不需要设置 framework;只有自定义构建环境无法识别框架时,才显式传入该选项。
与正式配置共享 options
AiI18nVitestOptions 是 AiI18nOptions 的子集,只保留 sourceLang、defaultLang、
locales、framework、persist、autoImport。把这部分抽成共享文件,vite.config.ts
与 vitest.config.ts 各自引用,语言列表和运行时策略只需要改一处:
html、loading、cache、provider、directory、dts 等构建期字段不属于
AiI18nVitestOptions;直接把完整的 aiI18n() 配置对象传给 aiI18nVitest() 会被 TypeScript
拒绝多余字段,按需只挑测试需要的子集传入即可。
测试环境的能力范围
由于没有加载任何目标语言译文,t('保存') 始终返回 "保存",即使调用过
await setLang('en-US') 之后也是如此。可以把这类测试理解为契约测试——只断言组件确实调用了
t() 并渲染出结果,不断言具体译文内容。
文案树遵循同一规则,但不会退化为字符串:
loading 不属于 AiI18nVitestOptions,测试 Runtime 不创建语言 chunk loader。
getLangLoadState() 以及 useI18n() 的 loading/error 字段仍存在,但固定为 idle;真实
loading/error 变化应由应用自己的抽象单测或生产 Vite 集成测试覆盖。
单元测试不应断言某个语言一定翻译为特定字词。译文质量通过人工校对或
AI 翻译流程确认;CI 可以额外运行一次真实的 vite build。
常见问题
测试环境需要先跑过 vite build 或存在翻译记忆吗?
不需要。测试插件不依赖项目中的翻译文件,也能正常解析 virtual:ai-i18n。
能不能在同一个 vitest.config.ts 里同时注册 aiI18n() 和 aiI18nVitest()?
不要这样做。两者都会尝试解析 virtual:ai-i18n,只注册 aiI18nVitest() 即可。
为什么 t(messages) 返回了字符串,数组下标只剩一个字符?
官方测试 Runtime 会保持数组和对象结构。请搜索测试 setup、共享测试工具和 Vitest alias,删除对
virtual:ai-i18n 的手写替换。只保留 aiI18nVitest() 后再运行最小文案树用例。
端到端测试(Playwright 等)呢?
aiI18nVitest() 只覆盖 Vitest 场景。端到端测试应运行真实的 vite dev 或 vite build,
以覆盖实际的语言切换和翻译结果。