测试(Vitest)

vitest.config.ts 中使用 aiI18nVitest(),即可测试导入 virtual:ai-i18n 的业务模块,无需 手写 alias 或 mock。测试环境不执行自动翻译,也不会修改项目中的翻译文件。

如果 Vitest 输出“仅支持浏览器 Runtime,已跳过 SSR 转换/注入”,说明测试配置加载了生产用的 aiI18n()。不要忽略或静默过滤该提示;从 @ai-i18n/vite/vitest 改用 aiI18nVitest(),并确保同一测试配置只注册其中一个插件。

它支持 t()useI18n()、Vue tRef()、纯 Options 的 i18nComputed() / tComputed()、消息集合宏和自动导入。测试配置的 autoImport 应与正式 Vite 配置保持一致。 Jest 或直接 Node.js 执行不会处理消息集合宏,请改用 Vitest 配置或避免执行包含宏的源码。

快速开始

React
Vue
Vanilla JS
// vitest.config.ts
import { aiI18nVitest } from '@ai-i18n/vite/vitest';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vitest/config';

export default defineConfig({
  plugins: [
    aiI18nVitest({
      sourceLang: 'zh-CN', // 测试 Runtime 固定回退的源码语言
      // value 是语言标识,label 是组件中展示的名称。
      locales: [
        { value: 'zh-CN', label: '中文' },
        { value: 'en-US', label: 'English' },
      ],
      autoImport: true, // 仅当正式 Vite 配置也开启自动导入时保持一致
    }),
    react(), // 提供 React 转换,并让测试插件自动识别 React 模式
  ],
});

保留项目原有的 Vue 或 React Vite 插件。大多数项目不需要设置 framework;只有自定义构建环境 无法识别框架时,才显式传入该选项。

与正式配置共享 options

AiI18nVitestOptionsAiI18nOptions 的子集,只保留 sourceLangdefaultLanglocalesframeworkpersistautoImport。把这部分抽成共享文件,vite.config.tsvitest.config.ts 各自引用,语言列表和运行时策略只需要改一处:

// ai-i18n.options.ts
export const aiI18nOptions = {
  sourceLang: 'zh-CN', // 源码文案使用的语言
  defaultLang: 'zh-CN', // 没有有效持久化值时的初始语言
  // value 是语言标识,label 是组件中展示的名称。
  locales: [
    { value: 'zh-CN', label: '中文' },
    { value: 'en-US', label: 'English' },
  ],
  persist: { key: 'app-lang' }, // 使用指定 localStorage key 保存语言偏好
  autoImport: true, // 两种环境使用同一模式化自动导入契约
} as const;
// vite.config.ts
import { aiI18n } from '@ai-i18n/vite';
import { aiI18nOptions } from './ai-i18n.options';

export default defineConfig({
  plugins: [
    aiI18n(aiI18nOptions),
    react(), // 保留宿主 React 转换
  ],
});
// vitest.config.ts
import { aiI18nVitest } from '@ai-i18n/vite/vitest';
import { aiI18nOptions } from './ai-i18n.options';

export default defineConfig({
  plugins: [
    aiI18nVitest(aiI18nOptions),
    react(), // 保留宿主 React 转换
  ],
});

htmlloadingcacheproviderdirectorydts 等构建期字段不属于 AiI18nVitestOptions;直接把完整的 aiI18n() 配置对象传给 aiI18nVitest() 会被 TypeScript 拒绝多余字段,按需只挑测试需要的子集传入即可。

测试环境的能力范围

能力测试环境行为
t(source) / t`...`可用。测试 Runtime 没有加载任何目标语言译文,因此固定返回 source 文案。
setLang(value)可用,可用于测试语言切换触发的重渲染,以及 persist 写入 localStorage。
useI18n()Vue / React 模式下可用;字段契约一致,但测试 Runtime 的语言加载状态固定为 idle
tRef()仅 Vue 模式可用;返回响应式 source fallback Ref,与生产环境保持相同 API 形状。
i18nComputed()仅 Vue 模式可用;返回与生产一致的 Options computed 配置。
tComputed()仅 Vue 模式可用;返回 source fallback 的 Options computed getter。
自动导入仅在 autoImport: true 时注入,API 集合与同一框架模式的生产插件一致。
翻译文件与自动翻译不会读取、修改或调用。
Provider / AI 自动翻译不会调用;provider 不属于 AiI18nVitestOptions

由于没有加载任何目标语言译文,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 或存在 Translation Memory 吗? 不需要。测试插件不依赖项目中的翻译文件,也能正常解析 virtual:ai-i18n

能不能在同一个 vitest.config.ts 里同时注册 aiI18n()aiI18nVitest() 不要这样做。两者都会尝试解析 virtual:ai-i18n,只注册 aiI18nVitest() 即可。

端到端测试(Playwright 等)呢? aiI18nVitest() 只覆盖 Vitest 场景。端到端测试应运行真实的 vite devvite build, 以覆盖实际的语言切换和翻译结果。