{{ t('保存') }}
{{ t('保存') }}
{{ t('保存') }}
{t('保存')}
{{ t('语言包加载失败,请重试') }}
{{ t('目标语言:') }} {{ langLoadState.targetLang }} ``` **Vue Options** ```vue{{ t('语言包加载失败,请重试') }}
{{ t('目标语言:') }} {{ langLoadState.targetLang }} ``` **React** ```tsx import { useI18n } from 'virtual:ai-i18n'; export function LanguageButton() { const { isLangLoading, langLoadState, setLang, t } = useI18n(); async function switchToFrench() { try { await setLang('fr-FR'); } catch { // 仅在这里添加业务级恢复动作;通用错误展示直接读取 langLoadState.status。 } } return ( <> {langLoadState.status === 'error' ? ({t('语言包加载失败,请重试')}
) : null} {langLoadState.status === 'loading' ? ( {t('目标语言:')} {langLoadState.targetLang} ) : null} > ); } ``` **Vanilla JS** ```js import { getLangLoadState, setLang, subscribe, t } from 'virtual:ai-i18n'; const button = document.querySelector('#switch-language'); const status = document.querySelector('#language-status'); function render() { const state = getLangLoadState(); button.disabled = state.status === 'loading'; button.textContent = state.status === 'loading' ? t('正在加载语言包…') : t('切换到法语'); status.textContent = state.status === 'error' ? t('语言包加载失败,请重试') : ''; } button.addEventListener('click', () => { // 共享状态不会消费 rejected Promise,调用方仍需显式 catch。 void setLang('fr-FR').catch(() => {}); }); render(); const unsubscribe = subscribe(render); // 页面或视图销毁时调用 unsubscribe()。 ``` 加载失败时,Runtime 会保留当前语言并让 Promise reject。应用可以像上例一样捕获错误, 执行日志、重试计数等业务动作;只需要通用 UI 时可以直接使用内置状态。 普通 JavaScript / TypeScript 模块如果只需要当前值,可以读取一次快照: ```ts import { getLangLoadState } from 'virtual:ai-i18n'; const state = getLangLoadState(); ``` 需要持续响应变化时,应像 Vanilla 示例一样配合 `subscribe()` 重新读取。状态的完整类型与 并发语义见 [`getLangLoadState()`](/ai-i18n/api/runtime/functions/get-lang-load-state.md)。 ## 配置规则 - `preload` 与 `prefetch` 只能填写 `locales` 中的目标 locale,不能填写 `sourceLang`。 - 同一 locale 不能同时出现在两个列表中;同一列表内的重复值会自动去重。 - 非 source 的 `defaultLang` 会自动按 preload 处理。不要再把它填入 `prefetch`,否则配置会在启动时 报错。资源就绪前先渲染 source fallback,加载完成后再通知订阅者更新。 - 相同 locale 的并发调用会复用同一次底层语言包加载请求,不保证各次 `setLang()` 返回的 Promise 引用相等。不同 locale 的并发切换以最后一次调用为准。 - 缺失或值为 `null` 的译文始终回退到 source 文案。 完整字段类型与边界见 [`AiI18nLocaleLoadingOptions`](/ai-i18n/api/vite/interfaces/ai-i18n-locale-loading-options.md)。 --- url: https://bosens-china.github.io/ai-i18n/guide/basic/directory.md --- # 生成文件与 Git ai-i18n 默认在 Vite root 下创建 `i18n/` 目录,用来保存译文和本地构建产物: ```text i18n/ ├── translations/ # 默认 JSON 存储 │ ├── manifest.json │ └── 00.json ... ff.json ├── overrides.json ├── extracted/ ├── locales/ └── storage.json # 仅 SQLite 存储 ``` 你通常只需要关注两类文件: - `translations/`:默认的分片 JSON Translation Memory,保存自动翻译或 Agent 补齐的译文。 - `storage.json`:仅在选择 SQLite 时生成。缺少该文件表示使用默认 JSON;文件不包含本机数据库路径。 - `overrides.json`:人工确认过的最终译文。它优先于自动翻译结果。 `extracted/` 和 `locales/` 都是构建产物。插件会根据源码和上述译文重新生成它们,不要直接编辑。 ## Git 提交规则 将以下文件与源码一起提交: - `src/ai-i18n.d.ts`,或通过 `dts` 配置的声明文件; - Vue 自动导入模式生成的相邻 `.vue.d.ts` 声明文件; - `i18n/translations/**/*.json`(使用默认 JSON 存储时); - `i18n/storage.json`(使用 SQLite 存储时); - `i18n/overrides.json`。 将以下目录加入 `.gitignore`: ```text i18n/extracted/ i18n/locales/ logs/ *.log ``` `logs/` 与 `*.log` 是 OpenAI Provider 的本地审查日志,可能包含完整提示词、业务文案和模型输出, 不得提交。使用自定义日志目录时也要忽略该目录。详情见 [LLM 日志与排障](/ai-i18n/guide/advanced/llm-logs.md)。 默认的分片 JSON 适合团队协作。它可以随源码提交,也便于在 PR 中审查译文变化。团队成员与 CI 拉取 同一份仓库后,可以直接复用已经提交的自动译文和人工译文。 :::important 译文文件与引用它们的源码应在同一个 PR 中提交。这样其他开发者和 CI 才能得到一致的翻译结果。 ::: 选择 `translationMemory.storage: 'sqlite'` 时,全局数据库位于用户目录,不提交 Git;项目仍提交 `storage.json` 与 `overrides.json`。SQLite 是本机缓存,新机器和 CI 需要 Provider 重新生成自动 译文。因此,需要跨机器共享自动译文的团队应使用默认的分片 JSON。两种存储的选择见 [Translation Memory](/ai-i18n/guide/advanced/translation-memory.md)。 声明文件的作用和自定义路径见 [TypeScript 与生成声明](/ai-i18n/guide/quality/typescript.md)。 ## 什么时候运行完整 Build 开发服务器只处理浏览器实际访问过的模块。以下情况请运行一次完整 `vite build`: 1. 首次接入 ai-i18n; 2. 准备补译、审校或提交译文; 3. 切换分支后,或修改了源码、Vite 配置和提取相关配置; 4. `i18n/extracted/` 缺失、为空,或不确定它是否仍与当前源码一致。 完整 Build 会处理从应用入口可达的模块。未被应用引用的文件不会进入翻译结果。 ## Monorepo 中的目录归属 一个 Vite build 必须独占一个 i18n 目录。例如: ```text apps/ ├── web/ │ └── i18n/ └── admin/ └── i18n/ packages/ └── ui/ └── src/ ``` `web` 引用 `packages/ui` 的本地 ESM 源码时,完整 Build 会把 UI 文案纳入 `apps/web/i18n`。共享源码包不需要重复注册 ai-i18n,也不需要单独创建 i18n 目录,除非它 自己拥有独立的 Vite build。 不要让 Web、Admin 或包构建共用一个目录。完整 Build 会按当前应用的模块图重建 `extracted/` 和 `locales/`,不同构建会相互覆盖。补译或审校时也应分别选择每个应用。 ## 缺译时会发生什么 目标语言缺少译文时,页面会显示源码文案。你可以配置 [AI 翻译](/ai-i18n/guide/advanced/ai-translation.md),也可以按 [补译与审校](/ai-i18n/guide/basic/translations.md) 手动处理。 同一句原文在不同语境下需要不同译法时,为 `t()` 提供 `comment`: ```ts t('提交', { comment: '创建 Git 提交' }); t('提交', { comment: '表单按钮' }); ``` ## 处理合并冲突 合并冲突时保留 `translations/` 与 `overrides.json` 的有效内容,不要手工调整消息所属分片。同一人工 译文出现不同版本时,由负责人确认最终措辞。解决冲突后运行一次 Build,再检查页面效果。 如果同时使用 Agent 或 Provider 写入译文,避免在编辑器中并行手改同一份译文文件。先完成一方操作,再进行 另一方操作。 --- url: https://bosens-china.github.io/ai-i18n/guide/basic/translations.md --- # 补译与审校 ai-i18n 不会用空字符串代替缺失译文。缺译时页面会回退显示源码文案,因此可以先完成开发,再逐步处理翻译。 ## 推荐流程 1. 运行一次完整 `vite build`,让当前应用的可达文案进入翻译结果。 2. 选择一种补译方式:配置 [AI 翻译](/ai-i18n/guide/advanced/ai-translation.md),或使用 [Agent + MCP](/ai-i18n/guide/advanced/ai-tools.md)。 3. 检查关键页面和产品术语。 4. 对不满意或需要固定的译文进行人工审校。 5. 再运行一次 Build,并按当前存储模式提交源码、Translation Memory 标记与 `overrides.json`。 ## 自动翻译与人工译文 自动翻译默认写入 `i18n/translations/` 分片。人工确认的译文写入 `i18n/overrides.json`,并且始终优先 显示。也可以将自动译文放进用户级全局 SQLite,详见 [Translation Memory](/ai-i18n/guide/advanced/translation-memory.md)。 适合人工审校的情况包括: - 品牌名、产品术语和法律文案; - 同一原文在不同页面代表不同含义; - 需要符合团队既有的语言风格。 同一句原文有不同含义时,请为调用添加静态 `comment`,再按该语境分别审校: ```ts t('保存', { comment: '保存文件按钮' }); t('保存', { comment: '保存状态' }); ``` ## 直接编辑译文文件 Provider 或 Agent + MCP 会自动维护文件结构,适合批量补译和按语境审校。需要手工调整少量译文时, 也可以编辑现有 JSON 文件,但不要用下面的示例覆盖已经生成的内容。 默认存储下,`translations/*.json` 保存自动译文。先在分片中搜索目标 `source`,保留 `version`、消息 标识和源码信息,只修改目标消息 `translations` 下的语言值。不要修改 `manifest.json`,也不要手工把 消息移动到另一个分片。以下分片示例对应不带 `comment` 的 `t('保存')`: ```json { "version": 1, "messages": { "保存": { "source": "保存", "sourceLang": "zh-CN", "translations": { "en-US": "Save" } } } } ``` SQLite 模式不适合直接编辑数据库,请使用 Provider 或 Agent + MCP。少量已确认措辞仍建议写入 `overrides.json`,这样可以提交并在不同电脑间保持一致。 `overrides.json` 使用便于审查的扁平 `rules` 保存人工决定。只写 `source` 时,译文对当前 Vite 应用内的所有同源文案生效: ```json { "version": 2, "rules": [ { "source": "保存", "translations": { "en-US": "Save" } } ] } ``` 同一句话只需要在部分文件采用不同译法时,为规则增加 `files`。路径必须是相对 Vite `root` 的 标准化 POSIX 路径,并与列表工具返回的 `source_file` 完全一致;不接受绝对路径、路径片段或 glob。 一个规则可以列出多个文件,以复用完全相同的审校决定: ```json { "version": 2, "rules": [ { "source": "保存", "files": ["src/editor/actions.ts", "src/editor/toolbar.ts"], "translations": { "en-US": "Save file" } }, { "source": "保存", "comment": "保存状态", "files": ["src/status/panel.ts"], "translations": { "en-US": "Keep" } } ] } ``` `comment` 与 `files` 可以单独使用,也可以组合。最终优先级从高到低是:文件 + `comment`、全局 + `comment`、文件默认、全局默认、自动译文、源码回退。建议使用 [Agent + MCP](/ai-i18n/guide/advanced/ai-tools.md) 列出现有文案和精确路径,确认措辞后再写入;不要自行构造 语境标识。生成目录 `i18n/extracted/` 和 `i18n/locales/` 不接受人工编辑。 ## 提交前检查 - 切换每一种支持语言,确认关键页面没有意外回退到源码文案; - 确认占位符、代码和品牌名没有被误译; - 运行 `vite build`; - 遵循[生成文件与 Git](/ai-i18n/guide/basic/directory.md)的提交规则。 --- url: https://bosens-china.github.io/ai-i18n/guide/quality/typescript.md --- # TypeScript 与生成声明 本页只说明 ai-i18n 为 TypeScript 项目增加的内容。通过 Vite 模板创建的项目可以继续使用模板 自带的 TypeScript 配置,不需要为了接入 ai-i18n 重写 `tsconfig`。 ## 接入类型声明 首次启动 Vite Dev Server 或执行 Build 后,插件会在 Vite root 下生成声明文件。默认路径是: ```text src/ai-i18n.d.ts ``` 它位于 Vite 模板默认包含的 `src/` 中,因此通常不需要额外配置。业务源码也不应 import 这个 `.d.ts` 文件;正常导入 `virtual:ai-i18n`,或按需开启自动导入即可。 ```ts import { t, useI18n } from 'virtual:ai-i18n'; ``` 如果编辑器在文件生成后仍保留旧错误,先重启 TypeScript language service 或编辑器,再运行 项目已有的类型检查命令。 ## 生成文件各自负责什么 ### `ai-i18n.d.ts` 主声明适用于 Vanilla、Vue 和 React,除非显式设置 `dts: false`。它负责: - 声明 `virtual:ai-i18n` 及当前框架可用的 Runtime API; - 声明无需 import 的 `defineI18nMessages()` 编译宏; - 开启 `autoImport: true` 后,为脚本中的自动导入 API 提供全局类型。 这个文件解决的是 TypeScript 脚本作用域中的类型问题。 ### `ai-i18n.vue.d.ts` Vue 模式同时开启 `autoImport: true` 时,还会在主声明旁生成: ```text src/ai-i18n.d.ts src/ai-i18n.vue.d.ts ``` 第二个文件扩展 Vue 的组件类型,让 Vue language-tools(Volar)与 `vue-tsc` 识别 template 中的裸 `t()`。主声明会引用它,因此两个文件应保持相邻。 这个文件只是 template 的类型桥,不会向组件实例安装 method。即使编辑器能识别 `{{ t('保存') }}`,脚本中也不要改写成 `this.t()` 或 `this.$t()`。 生成声明由插件维护,不要手工修改。是否提交到 Git 以及其他生成文件的归属见 [生成文件与 Git](/ai-i18n/guide/basic/directory.md)。 ## 显式导入与自动导入 | 使用方式 | 脚本类型来源 | Vue template 类型来源 | | ---------------------- | --------- | -------------------------------------- | | 从 `virtual:ai-i18n` 导入 | 主声明中的模块声明 | ` ``` 开启 `autoImport: true` 后,可以只保留 template: ```vue {{ t('保存') }} ``` 插件生成的声明会让 Vue language-tools(Volar)与 `vue-tsc` 识别这个裸 `t`, 无需为了 IDE 添加 import。` ``` Options 的普通 ` {{ label }} ``` 需要完整签名和文案树示例时,查看 [`tRef()` API](/ai-i18n/api/runtime/vue/t-ref.md)。 ## 纯 Options API 如何预声明响应式文案? 使用 [`tComputed()`](/ai-i18n/api/runtime/vue/t-computed.md),并把返回的 getter 放入 Options `computed`: ```ts export default defineComponent({ computed: { saveLabel: tComputed('保存'), labels: tComputed({ save: '保存', cancel: '取消' }), }, }); ``` 不要把 `tComputed()` 放入 `data()`,也不要在 template 或 render 中调用。依赖 `this` 的动态插值应写成普通 computed,并在 getter 中调用 `t()`。 --- url: https://bosens-china.github.io/ai-i18n/guide/faq/react.md --- # React 常见问题 ## 为什么普通 JSX 文本没有被提取? ai-i18n 不猜测普通 UI 文本。把需要翻译的文本放入 `useI18n()` 返回的 `t()`: ```tsx import { useI18n } from 'virtual:ai-i18n'; function SaveButton() { const { t } = useI18n(); return ; } ``` 支持的静态表达式、文案树与限制见 [React 文案写法](/ai-i18n/guide/basic/static-analysis/react.md)。 ## 为什么切换语言后组件没有刷新? 组件渲染必须调用 `useI18n()` 返回的 `t`。从 `virtual:ai-i18n` 单独导入的顶层 `t` 只读取 当前语言,不会让组件订阅后续更新。 也不要把 `t('保存')` 的结果放入模块常量或长期 state。保留 source 文案,在每次渲染时调用 Hook 返回的 `t()`。 ## 非组件 TS 文件如何读取或切换语言? 普通模块、store action、路由和事件处理器不能调用 React Hook,应使用顶层 Runtime API。 开启 `autoImport: true` 后,可以直接调用 `setLang()`、`getLang()`、`getLangs()`、 `getLangLoadState()` 与 `subscribe()`。 其中 `getLang()` 与 `getLangLoadState()` 返回调用时快照。组件需要展示这些状态时仍应使用 `useI18n()`,否则语言变化不会触发重新渲染。 ## React Compiler 能否替代 `useI18n()`? 不能。React Compiler 可以缓存渲染计算,但不会为 Runtime 顶层 `t` 自动建立外部状态订阅。 `useI18n()` 内部使用 `useSyncExternalStore`,Runtime 更新时还会刷新 `t` 的函数引用,因此 无论是否启用 React Compiler,组件渲染都应使用 Hook 返回的 `t`。 ## 普通工具模块不能调用 Hook,应该怎么翻译? 普通 `.js` 或 `.ts` 工具模块可以导入 Runtime 顶层 `t`,但应在实际调用时翻译: ```ts import { t } from 'virtual:ai-i18n'; export const getRetryMessage = () => t('请重试'); ``` 不要导出 `const retryMessage = t('请重试')`,它只保存模块初始化时的译文快照。组件渲染仍 使用 `useI18n()`。 ## 本地 link 后为什么出现 Invalid Hook Call? 先确认应用只解析到一份 `react` 和 `react-dom`。本地工作区或 link 场景可在 Vite 中添加: ```ts export default defineConfig({ resolve: { dedupe: ['react', 'react-dom'], }, }); ``` 正常安装通常由 peer dependency 复用应用自己的 React,不需要额外配置。 --- url: https://bosens-china.github.io/ai-i18n/api/index.md --- # API 总览 需要完成安装、配置和业务接入时,从[快速上手](/ai-i18n/guide/getting-started/vue.md)与 [接入与使用](/ai-i18n/guide/basic/static-analysis/common.md)开始。本节只负责记录公开 API 的准确签名、 配置字段、默认值与行为边界,不重复教程流程。 API 参考按导入入口组织。选择入口后,再按函数、接口、类型别名或编译宏查找具体符号。 | 入口 | 用途 | | ---------------------- | -------------------------------- | | `@ai-i18n/vite` | 注册 Vite 插件,配置提取、翻译和自定义 Provider。 | | `@ai-i18n/vite/vitest` | 在 Vitest 中提供内存 Runtime 与编译宏转换。 | | `virtual:ai-i18n` | 在浏览器业务代码中翻译文案和切换语言。 | | `@ai-i18n/openai` | 创建 OpenAI-compatible Translator。 | ## 查找入口 - 配置插件:[`aiI18n()`](/ai-i18n/api/vite/functions/ai-i18n.md) - 查询全部插件选项:[`AiI18nOptions`](/ai-i18n/api/vite/interfaces/ai-i18n-options.md) - 翻译文案:[`t()`](/ai-i18n/api/runtime/functions/t.md) - 在 Vue setup 中创建响应式翻译值:[`tRef()`](/ai-i18n/api/runtime/vue/t-ref.md) - 读取语言资源加载状态:[`getLangLoadState()`](/ai-i18n/api/runtime/functions/get-lang-load-state.md) - 在 Vue 中读取响应式语言状态:[`useI18n()`](/ai-i18n/api/runtime/vue/use-i18n.md) - 在 React 中订阅语言变化:[`useI18n()`](/ai-i18n/api/runtime/react/use-i18n.md) - 配置 Vitest:[`aiI18nVitest()`](/ai-i18n/api/vitest/functions/ai-i18n-vitest.md) - 连接模型:[`openAI()`](/ai-i18n/api/openai/functions/open-ai.md) - 实现自定义翻译器:[`Translator`](/ai-i18n/api/vite/type-aliases/translator.md) ## 本节职责 本节记录应用接入所依赖的公开契约。Analyzer、文件 Schema、Translation Memory 事务和框架 适配器等低层基础设施不作为普通应用的稳定接入入口。除非文档明确列出,否则不要依赖包中 的其他导出。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/functions/ai-i18n.md --- # aiI18n() 从 `@ai-i18n/vite` 导入: ```ts import { aiI18n } from '@ai-i18n/vite'; ``` ## 签名 ```ts function aiI18n(options: AiI18nOptions): Plugin; ``` `aiI18n()` 返回一个 Vite 插件。每个 Vite build 只应注册一次。 ## 示例 ```ts import { aiI18n } from '@ai-i18n/vite'; import { defineConfig } from 'vite'; export default defineConfig({ plugins: [ aiI18n({ sourceLang: 'zh-CN', locales: [ { value: 'zh-CN', label: '中文' }, { value: 'en-US', label: 'English' }, ], }), ], }); ``` 配置完成后,业务代码从 `virtual:ai-i18n` 导入 Runtime API: ```ts import { setLang, t } from 'virtual:ai-i18n'; ``` ## 参数 | 参数 | 类型 | 说明 | | --------- | ------------------------------------------------------------------ | ------------ | | `options` | [`AiI18nOptions`](/ai-i18n/api/vite/interfaces/ai-i18n-options.md) | Vite 插件完整配置。 | ## 返回值 返回 Vite 的 `Plugin` 对象。插件负责静态提取、协议文件同步、可选 Provider 调度、虚拟 Runtime 和声明文件生成。 ## 相关内容 - [Vue 快速上手](/ai-i18n/guide/getting-started/vue.md) - [React 快速上手](/ai-i18n/guide/getting-started/react.md) - [Vanilla 快速上手](/ai-i18n/guide/getting-started/vanilla.md) - [通用文案写法](/ai-i18n/guide/basic/static-analysis/common.md) - [生成文件与 Git](/ai-i18n/guide/basic/directory.md) --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/ai-i18n-options.md --- # AiI18nOptions 从 `@ai-i18n/vite` 导入: ```ts import type { AiI18nOptions } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface AiI18nOptions { framework?: AiI18nFramework; autoImport?: boolean; dts?: string | false; sourceLang: string; defaultLang?: string; locales: readonly LangOption[]; persist?: boolean | AiI18nPersistOptions; loading?: AiI18nLocaleLoadingOptions; translationMemory?: AiI18nTranslationMemoryOptions; provider?: AiI18nProviderOptions; directory?: string; cleanup?: AiI18nCleanupOptions; html?: boolean | HtmlExtractorOptions; } ``` ## 字段 | 字段 | 类型 | 必填 | 默认值 | 作用 | | ------------------- | ------------------------------------------------------------------------------------------------------ | -- | -------------------- | -------------------------- | | `sourceLang` | `string` | 是 | 无 | 源码文案所属语言。 | | `locales` | [`readonly LangOption[]`](/ai-i18n/api/vite/interfaces/lang-option.md) | 是 | 无 | 项目支持的语言列表。 | | `defaultLang` | `string` | 否 | `sourceLang` | 没有有效持久化值时使用的初始语言。 | | `persist` | `boolean` 或 [`AiI18nPersistOptions`](/ai-i18n/api/vite/interfaces/ai-i18n-persist-options.md) | 否 | `false` | 使用 localStorage 保存语言偏好。 | | `loading` | [`AiI18nLocaleLoadingOptions`](/ai-i18n/api/vite/interfaces/ai-i18n-locale-loading-options.md) | 否 | 全语言注册 | 按 locale 拆分语言资产。 | | `framework` | [`AiI18nFramework`](/ai-i18n/api/vite/type-aliases/ai-i18n-framework.md) | 否 | 自动检测 | 指定 Vanilla、Vue 或 React 模式。 | | `autoImport` | `boolean` | 否 | `false` | 自动注入当前框架模式的 Runtime API。 | | `dts` | `string \| false` | 否 | `'src/ai-i18n.d.ts'` | 设置声明文件路径,或关闭生成。 | | `directory` | `string` | 否 | `'i18n'` | 设置协议目录;相对路径基于 Vite `root`。 | | `provider` | [`AiI18nProviderOptions`](/ai-i18n/api/vite/type-aliases/ai-i18n-provider-options.md) | 否 | 不调用模型 | 配置自动翻译函数、缓存与调度策略。 | | `html` | [`boolean \| HtmlExtractorOptions`](/ai-i18n/api/vite/interfaces/html-extractor-options.md) | 否 | `false` | 开启 `index.html` 文本和属性提取。 | | `translationMemory` | [`AiI18nTranslationMemoryOptions`](/ai-i18n/api/vite/interfaces/ai-i18n-translation-memory-options.md) | 否 | 分片 JSON | 选择存储方式,并按需限制历史译文容量。 | | `cleanup` | [`AiI18nCleanupOptions`](/ai-i18n/api/vite/interfaces/ai-i18n-cleanup-options.md) | 否 | 保留默认清理策略 | 控制失效提取文件和孤立消息的清理。 | ## 语言约束 `locales` 至少包含一项,且每一项的 `value` 必须唯一。`sourceLang` 与 `defaultLang` 必须匹配 某个 `value`。 目标语言缺译或值为 `null` 时,Runtime 返回 source 文案。插件不会为 `sourceLang` 生成重复的 目标语言文件。 初始语言按以下顺序选择: 1. localStorage 中有效的持久化值; 2. `defaultLang`; 3. 省略 `defaultLang` 时使用 `sourceLang`。 ## 框架与自动导入 省略 `framework` 时,插件读取 Vite 最终插件列表: | 检测结果 | 模式 | | ------------------------------ | --------- | | 存在 `vite:vue` 或 `vite:vue-jsx` | `vue` | | 存在 `vite:react*` | `react` | | 都不存在 | `vanilla` | 同一个 build 同时出现 Vue 与 React 插件时会报错。显式设置 `framework` 不会绕过这项检查。 显式值只能是 `'vanilla'`、`'vue'` 或 `'react'`;JavaScript 配置中的其他值也会在启动时被拒绝。 `autoImport: true` 注入的 API 取决于最终模式。三种模式都有 `t`、`setLang`、`getLang`、 `getLangs`、`getLangLoadState` 与 `subscribe`;Vue 额外注入 `useI18n`、`tRef`、 `i18nComputed`、`tComputed`,React 额外注入 `useI18n`。 完整接入方法见[自动导入](/ai-i18n/guide/basic/auto-import.md)。 ## 路径 `directory` 与 `dts` 的相对路径都基于 Vite `root` 解析;传入绝对路径时直接使用该路径。 ## 相关内容 - [`aiI18n()`](/ai-i18n/api/vite/functions/ai-i18n.md) - [语言分包与按需加载](/ai-i18n/guide/basic/locale-loading.md) - [生成文件与 Git](/ai-i18n/guide/basic/directory.md) - [TypeScript 与生成声明](/ai-i18n/guide/quality/typescript.md) - [Translation Memory](/ai-i18n/guide/advanced/translation-memory.md) - [ESLint](/ai-i18n/guide/quality/eslint.md) --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/ai-i18n-persist-options.md --- # AiI18nPersistOptions 从 `@ai-i18n/vite` 导入: ```ts import type { AiI18nPersistOptions } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface AiI18nPersistOptions { key: string; } ``` ## 字段 | 字段 | 类型 | 必填 | 作用 | | ----- | -------- | -- | ------------------------- | | `key` | `string` | 是 | 保存当前语言的 localStorage key。 | `key` 去除首尾空白后不能为空。 ## 用法 [`AiI18nOptions.persist`](/ai-i18n/api/vite/interfaces/ai-i18n-options.md) 支持三种写法: | 写法 | 行为 | | ------------------------- | ------------------ | | `false` 或省略 | 不读写 localStorage。 | | `true` | 使用 `ai-i18n:lang`。 | | `{ key: 'app-language' }` | 使用指定 key。 | 存储不可用或保存值不在 `locales` 中时,Runtime 会忽略该值。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/ai-i18n-locale-loading-options.md --- # AiI18nLocaleLoadingOptions 从 `@ai-i18n/vite` 导入: ```ts import type { AiI18nLocaleLoadingOptions } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface AiI18nLocaleLoadingOptions { preload?: readonly string[]; prefetch?: readonly string[]; } ``` ## 字段 | 字段 | 类型 | 默认值 | 作用 | | ---------- | ------------------- | ---- | ---------------------------- | | `preload` | `readonly string[]` | `[]` | 通过 `modulepreload` 尽早准备语言模块。 | | `prefetch` | `readonly string[]` | `[]` | 通过 `prefetch` 提示浏览器低优先级缓存。 | ## 行为 设置 `loading` 后,每个目标 locale 会生成独立 Vite chunk。省略 `loading` 时,插件继续使用 全语言注册模式;`loading: {}` 则会启用分包,并在首次 `setLang()` 时加载目标语言。 列表必须满足以下约束: - 只能引用 `locales` 中的目标 locale; - 不能包含 `sourceLang`; - 同一 locale 不能同时出现在两个列表中; - 单个列表中的重复值会自动去重。 非 source 的 `defaultLang` 会自动加入 `preload`,因此不能再把它列入 `prefetch`;该组合会在启动时 报错。相同 locale 的并发调用复用底层加载请求;不同 locale 的并发切换以最后一次 `setLang()` 调用为准。 ## 示例 ```ts aiI18n({ sourceLang: 'zh-CN', defaultLang: 'en-US', locales, loading: { preload: ['en-US'], prefetch: ['ja-JP'], }, }); ``` 完整使用流程见[语言分包与按需加载](/ai-i18n/guide/basic/locale-loading.md)。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/ai-i18n-translation-memory-capacity-options.md --- # AiI18nTranslationMemoryCapacityOptions 从 `@ai-i18n/vite` 导入: ```ts import type { AiI18nTranslationMemoryCapacityOptions } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface AiI18nTranslationMemoryCapacityOptions { maxMessages?: number; maxBytes?: number; } ``` ## 字段 | 字段 | 类型 | 默认值 | 作用 | | ------------- | -------- | --- | ----------------------------- | | `maxMessages` | `number` | 不限制 | 最多保留的 Translation Memory 消息数。 | | `maxBytes` | `number` | 不限制 | Memory 快照稳定序列化后的 UTF-8 字节软上限。 | 两个字段都必须是正整数。两项同时存在时,Memory 需要同时满足两个限制。容量统计包含当前项目的 Translation Memory 元数据与消息,不包含 `overrides`、`extracted` 或 `locales`。JSON 与 SQLite 使用相同的逻辑快照计算方式。 插件只淘汰当前源码不再引用的消息。活动消息始终保留;活动消息自身超限时,插件输出 warning,因此 这两个字段是保护数据安全的软上限。`cleanup.orphanMessages: true` 会先删除全部非活跃消息。 ## 用法 ```ts aiI18n({ sourceLang: 'zh-CN', locales, translationMemory: { storage: 'json', capacity: { maxMessages: 20_000, maxBytes: 10 * 1024 * 1024, }, }, }); ``` --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/ai-i18n-cleanup-options.md --- # AiI18nCleanupOptions 从 `@ai-i18n/vite` 导入: ```ts import type { AiI18nCleanupOptions } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface AiI18nCleanupOptions { missingSourceFiles?: boolean; orphanMessages?: boolean; } ``` ## 字段 | 字段 | 默认值 | 作用 | | -------------------- | ------- | --------------------------------- | | `missingSourceFiles` | `true` | 删除源文件不存在时对应的 `extracted` 文件。 | | `orphanMessages` | `false` | 删除当前源码不再引用的历史 Translation Memory。 | `orphanMessages: true` 会先删除当前项目的全部非活跃消息,再执行容量淘汰。它不会删除 `overrides.json`。SQLite 模式只影响当前项目的数据,不会删除其他项目的共享候选。 首次启用或修改清理策略后,运行一次完整 Build,确认当前入口可达模块已完成提取。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/ai-i18n-translation-memory-options.md --- # AiI18nTranslationMemoryOptions 从 `@ai-i18n/vite` 导入: ```ts import type { AiI18nTranslationMemoryOptions } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface AiI18nTranslationMemoryOptions { storage?: 'json' | 'sqlite'; capacity?: AiI18nTranslationMemoryCapacityOptions; } ``` ## 字段 | 字段 | 类型 | 默认值 | 作用 | | ---------- | ----------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------- | | `storage` | `'json' \| 'sqlite'` | `'json'` | 使用项目内可提交的分片 JSON,或用户级全局 SQLite。 | | `capacity` | [`AiI18nTranslationMemoryCapacityOptions`](/ai-i18n/api/vite/interfaces/ai-i18n-translation-memory-capacity-options.md) | 不限制 | 限制当前项目保留的历史译文容量。 | `storage: 'sqlite'` 使用用户目录中的同一个本地数据库,在不同项目间复用唯一译文候选。数据库不在 项目目录内,也不应提交 Git;`overrides.json` 仍保留在项目内并拥有最高优先级。 Provider 的进程级刷新通过 `provider.cache` 配置,不属于存储选项,也不影响 MCP。完整行为和选型建议见 [Translation Memory](/ai-i18n/guide/advanced/translation-memory.md)。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/html-extractor-options.md --- # HtmlExtractorOptions 从 `@ai-i18n/vite` 导入: ```ts import type { HtmlExtractorOptions } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface HtmlExtractorOptions { attributes?: readonly string[]; } ``` ## 字段 | 字段 | 类型 | 默认值 | 作用 | | ------------ | ------------------- | ---------------------------------------- | ------------ | | `attributes` | `readonly string[]` | `alt`、`aria-label`、`placeholder`、`title` | 替换默认属性提取白名单。 | 属性名必须由小写字母开头,后续只能包含小写字母、数字和连词线。重复属性会自动去重。 ## 用法 | `AiI18nOptions.html` 写法 | 行为 | | ----------------------- | ------------------------ | | `false` 或省略 | 不处理 HTML。 | | `true` | 提取完整的静态 `t()` 文本节点与默认属性。 | | `{ attributes }` | 提取完整的静态 `t()`,并替换属性白名单。 | 普通 HTML 文本、混合文本、内联脚本和非白名单属性不会自动翻译。HTML 提取与 `framework` 模式 相互独立。完整写法见[通用文案写法](/ai-i18n/guide/basic/static-analysis/common.md#html)。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/lang-option.md --- # LangOption 从 `@ai-i18n/vite` 导入: ```ts import type { LangOption } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface LangOption { value: string; label: string; } ``` ## 字段 | 字段 | 类型 | 必填 | 作用 | | ------- | -------- | -- | ----------------------------- | | `value` | `string` | 是 | 语言标识,用于 `setLang()` 和目标语言文件名。 | | `label` | `string` | 是 | 面向用户的语言名称,由 `getLangs()` 返回。 | `AiI18nOptions.locales` 至少包含一项,且所有 `value` 必须唯一。 ```ts const locales: readonly LangOption[] = [ { value: 'zh-CN', label: '中文' }, { value: 'en-US', label: 'English' }, ]; ``` --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/translation-options.md --- # TranslationOptions 该类型从 `@ai-i18n/vite` 导出,并用于 `virtual:ai-i18n` 的 `t()` 签名: ```ts import type { TranslationOptions } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface TranslationOptions { comment?: string; } ``` ## 字段 | 字段 | 类型 | 必填 | 作用 | | --------- | -------- | -- | -------------- | | `comment` | `string` | 否 | 向翻译器说明文案的业务语境。 | `comment` 必须能在构建期确定。插件会去除首尾空白;非空 `comment` 会参与消息身份与 Translation Memory。相同原文使用不同的 `comment` 时属于不同翻译单元,不会共享译文。 ```ts t('保存', { comment: '按钮' }); t('保存', { comment: '文件状态' }); ``` 模型只翻译 source,comment 只用于理解语境,不会进入最终译文。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/translation-message.md --- # TranslationMessage 从 `@ai-i18n/vite` 导入: ```ts import type { TranslationMessage } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface TranslationMessage { source: string; comment?: string; } ``` ## 字段 | 字段 | 类型 | 必填 | 作用 | | --------- | -------- | -- | --------------- | | `source` | `string` | 是 | 需要翻译的源文案。 | | `comment` | `string` | 否 | 用于理解业务语境,不进入译文。 | Vite 不会把 message ID、文件路径或源码位置交给 Translator。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/translation-batch.md --- # TranslationBatch 从 `@ai-i18n/vite` 导入: ```ts import type { TranslationBatch } from '@ai-i18n/vite'; ``` ## 定义 ```ts interface TranslationBatch { batchId?: string; logging?: TranslationLogging; locales: readonly string[]; messages: readonly TranslationMessage[]; } ``` ## 字段 | 字段 | 类型 | 必填 | 作用 | | ---------- | -------------------------------------------------------------------------------------- | -- | --------------------- | | `batchId` | `string` | 否 | 本批诊断 ID;由 Vite 调度器生成。 | | `logging` | [`TranslationLogging`](/ai-i18n/api/vite/type-aliases/translation-logging.md) | 否 | 关闭日志,或给出已解析日志目录。 | | `locales` | `readonly string[]` | 是 | 本批所有消息共同缺失的语言。 | | `messages` | [`readonly TranslationMessage[]`](/ai-i18n/api/vite/interfaces/translation-message.md) | 是 | 按固定下标排列的消息。 | Vite 按缺失 locale 集合分组,再根据 `AiI18nProviderOptions.batchLength` 切分批次。 `batchId` 只用于把调度、模型日志、状态应用和持久化事件关联起来,不发送给模型,也不参与 message ID、缓存键或 Translation Memory 文件格式。直接调用 Translator 时,Translator 可以为缺失的 `batchId` 生成本地诊断 ID。 Vite 根据 `provider.logging` 传入 `logging`。启用时,字符串是基于 Vite root 解析后的绝对目录; 关闭时为 `false`。自定义 Translator 可以忽略该可选字段;官方 OpenAI Provider 在值为 `false` 时 仍执行翻译,但不创建或追加日志。实现 `reportBatchEvent` 的 Translator 仍会收到生命周期事件。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/interfaces/translation-batch-event.md --- # TranslationBatchEvent 从 `@ai-i18n/vite` 导入: ```ts import type { TranslationBatchEvent } from '@ai-i18n/vite'; ``` ## 定义 ```ts type TranslationBatchEvent = | { batchId: string; logging: false | string; stage: 'scheduled'; locales: readonly string[]; messageCount: number; } | { batchId: string; logging: false | string; stage: 'state-applied'; resultCount: number; affectedModules: number; } | { batchId: string; logging: false | string; stage: 'persisted' } | { batchId: string; logging: false | string; stage: 'failed'; locales: readonly string[]; messageCount: number; reason: string; }; ``` `logging` 与对应 [`TranslationBatch`](/ai-i18n/api/vite/interfaces/translation-batch.md) 一致。启用时是基于 Vite root 解析后的绝对日志目录;关闭时为 `false`。实现了 `reportBatchEvent` 的 Translator 始终接收 事件;日志关闭只表示不应写入日志文件。该字段不进入持久化协议。 ## 阶段 | `stage` | 必有字段 | 含义 | | --------------- | --------------------------------- | ------------------------------------ | | `scheduled` | `locales`、`messageCount` | Vite 已形成实际 Translator 批次。 | | `state-applied` | `resultCount`、`affectedModules` | Provider 结果已通过校验并应用到当前项目状态。 | | `persisted` | 无 | 包含该批结果的文件和 Translation Memory 已写入成功。 | | `failed` | `locales`、`messageCount`、`reason` | Translator、结果校验或后续批次处理失败。 | 事件接收器只用于观察,不能依赖它改变翻译流程。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/type-aliases/ai-i18n-provider-options.md --- # AiI18nProviderOptions 从 `@ai-i18n/vite` 导入: ```ts import type { AiI18nProviderOptions } from '@ai-i18n/vite'; ``` ## 定义 ```ts type AiI18nProviderOptions = { translator: Translator; cache?: 'reuse' | 'fresh'; debounceMs?: number; batchLength?: number; maxConcurrency?: number; strict?: boolean; logging?: boolean | string; }; ``` ## 字段 | 字段 | 类型 | 必填 | 默认值 | 作用 | | ---------------- | ------------------------------------------------------------ | -- | --------- | ------------------------------ | | `translator` | [`Translator`](/ai-i18n/api/vite/type-aliases/translator.md) | 是 | 无 | 执行自动翻译。 | | `cache` | `'reuse' \| 'fresh'` | 否 | `'reuse'` | 复用历史结果,或在本次进程中刷新一次。 | | `debounceMs` | `number` | 否 | `100` | Dev 中合并连续请求的等待时间,单位为毫秒。 | | `batchLength` | `number` | 否 | `12_000` | 单批序列化请求的字符长度上限,不是 token 数。 | | `maxConcurrency` | `number` | 否 | `5` | 同时执行的翻译批次数。 | | `strict` | `boolean` | 否 | `false` | 在 flush 时抛出翻译失败或仍有 `null` 的错误。 | | `logging` | `boolean \| string` | 否 | `false` | 关闭日志,或启用并选择日志目录。 | `debounceMs` 必须大于或等于 `0`。`batchLength` 和 `maxConcurrency` 必须是正整数。 Vite 按消息的“缺失 locale 集合”分组,再按 `batchLength` 切分。一个批次失败时,其他成功 批次仍会写入。Dev 中的模型调用不阻塞首次模块响应;Build 会在结束前等待必要批次。 日志默认关闭。`logging: true` 使用 Vite root 下的 `logs/`;字符串指定目录,相对路径基于 Vite root,绝对路径保持不变。空字符串无效。开启后,Vite 会把解析后的目录传给 Translator 和批次 生命周期事件。官方 OpenAI Provider 会据此记录 REQUEST、RESPONSE、VALIDATION 等日志;省略或设为 `false` 时不创建或追加日志,但翻译、状态应用和持久化继续执行。自定义 Translator 可以选择支持该 诊断字段。完整说明见 [LLM 日志与排障](/ai-i18n/guide/advanced/llm-logs.md)。 `cache: 'fresh'` 只影响当前 Vite 进程发起的 Provider 调用。已有译文仍可供 Runtime 使用;本进程 生成的新结果会立即缓存,普通 HMR 不会重复请求。该选项不传给 Translator,也不影响 MCP 或 AI Agent 读写 Translation Memory。它与 `translationMemory.capacity` 无关:前者控制一次 Provider 刷新,后者 控制历史 Translation Memory 的容量。 ## 示例 ```ts aiI18n({ sourceLang: 'zh-CN', locales, provider: { translator, batchLength: 12_000, maxConcurrency: 5, strict: true, logging: 'diagnostics/llm', }, }); ``` Provider 的完整接入流程见 [AI 翻译](/ai-i18n/guide/advanced/ai-translation.md)。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/type-aliases/ai-i18n-framework.md --- # AiI18nFramework 从 `@ai-i18n/vite` 导入: ```ts import type { AiI18nFramework } from '@ai-i18n/vite'; ``` ## 定义 ```ts type AiI18nFramework = 'vanilla' | 'vue' | 'react'; ``` ## 值 三种模式都提供 `t()`、`setLang()`、`getLang()`、`getLangs()`、`getLangLoadState()` 与 `subscribe()`。框架模式决定 `virtual:ai-i18n` 额外提供的适配 API: | 值 | 额外导出 | | ----------- | --------------------------------------------------- | | `'vanilla'` | 无 | | `'vue'` | `useI18n()`、`tRef()`、`i18nComputed()`、`tComputed()` | | `'react'` | React `useI18n()` | 省略 [`AiI18nOptions.framework`](/ai-i18n/api/vite/interfaces/ai-i18n-options.md) 时,插件根据最终 Vite 插件列表自动检测。一个 build 同时包含 Vue 与 React 插件时会报错。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/type-aliases/lang-load-state.md --- # LangLoadState 从 `@ai-i18n/vite` 导入类型: ```ts import type { LangLoadState } from '@ai-i18n/vite'; ``` ## 定义 ```ts type LangLoadState = | Readonly<{ status: 'idle'; targetLang: null; error: null }> | Readonly<{ status: 'loading'; targetLang: string; error: null }> | Readonly<{ status: 'error'; targetLang: string; error: unknown }>; ``` ## 语义 | `status` | `targetLang` | `error` | 含义 | | --------- | ------------ | --------- | -------------- | | `idle` | `null` | `null` | 当前没有语言资源等待或错误。 | | `loading` | `string` | `null` | 正在加载指定目标语言。 | | `error` | `string` | `unknown` | 指定目标语言加载失败。 | 快照及其字段只读。`error` 保留 loader reject 的原始值,可能是 falsy;判断失败必须使用 `status === 'error'`。应用应在展示前把详情映射为自己的用户文案。 读取方式见 [`getLangLoadState()`](/ai-i18n/api/runtime/functions/get-lang-load-state.md),Vue / React 的 响应式派生值分别见 [Vue `useI18n()`](/ai-i18n/api/runtime/vue/use-i18n.md) 和 [React `useI18n()`](/ai-i18n/api/runtime/react/use-i18n.md)。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/type-aliases/message-tree.md --- # MessageTree 从 `@ai-i18n/vite` 导入类型: ```ts import type { MessageTree, MessageTreeValue } from '@ai-i18n/vite'; ``` ## 定义 ```ts type MessageTreeValue = | string | number | boolean | bigint | null | undefined | readonly MessageTreeValue[] | { readonly [key: string]: MessageTreeValue }; type MessageTree = readonly MessageTreeValue[] | { readonly [key: string]: MessageTreeValue }; ``` 每个字符串叶子都是待翻译文案;其他基础类型原样保留。运行时只接受普通对象和数组,不支持 `Map`、`Set`、函数、getter 或循环引用。调用 `t(messages)` 或 Vue `tRef(messages)` 时, 静态本地或导入对象不要求显式标注该类型,也不要求 `as const`。 --- url: https://bosens-china.github.io/ai-i18n/api/vite/type-aliases/translated-message-tree.md --- # TranslatedMessageTree 从 `@ai-i18n/vite` 导入类型: ```ts import type { TranslatedMessageTree } from '@ai-i18n/vite'; ``` ## 定义 ```ts type TranslatedMessageTree{{ t('语言包加载失败,请重试') }}
``` 建议在 `{{ greeting }}
``` 在脚本中读取 `.value`;模板会自动解包 Ref。 ## 响应式对象与数组 需要在 setup 中复用一组会随语言切换更新的文案时,可以直接把静态文案树交给 `tRef()`: ```vue {{ labels.states[0] }} ``` 静态本地对象和导入对象都支持,不要求 `as const` 或 `defineI18nMessages()`。每个字符串叶子 都会翻译,其他基础类型原样保留。输入必须是纯文案的普通对象或数组;不支持 `Map`、`Set`、 函数、循环引用、getter、运行时生成的集合,也不能为单个叶子设置 `comment` 或插值。 ## 与 `t()` 的分工 - 模板或渲染函数当场展示:直接使用 [`t()`](/ai-i18n/api/runtime/functions/t.md)。 - Vue setup / composable 需要预先声明响应式字符串、对象或数组:使用 `tRef()`。 - 纯 Options API 的 computed:使用 [`tComputed()`](/ai-i18n/api/runtime/vue/t-computed.md)。 - 事件、日志或普通工具函数需要即时字符串:使用 `t()`。 不要在 template 或渲染函数中直接调用 `tRef()`: ```vue {{ tRef('保存') }} ``` 应在 setup 中创建一次,再把返回的 Ref 用于模板。对应生命周期问题由 [`ai-i18n/no-unsubscribed-t`](/ai-i18n/guide/quality/eslint-rules.md) 提示。静态提取规则见 [Vue 文案写法](/ai-i18n/guide/basic/static-analysis/vue.md)。 --- url: https://bosens-china.github.io/ai-i18n/api/runtime/vue/i18n-computed.md --- # i18nComputed() `i18nComputed()` 是 Vue 模式专用的 Options API 配置工厂: ```ts import { i18nComputed } from 'virtual:ai-i18n'; ``` 它不创建组件,也不要求 `setup()`。把返回值展开到组件的 `computed`,Vue 会为每个组件 实例创建和清理对应的 computed watcher。 ## 签名 ```ts function i18nComputed(): { currentLang(): string; langs(): readonly LangOption[]; langLoadState(): LangLoadState; isLangLoading(): boolean; langLoadError(): unknown | null; }; ``` 返回值与 [`useI18n()`](/ai-i18n/api/runtime/vue/use-i18n.md) 表示同一份 Runtime 状态,但 Options computed 中读取的是 已经解包的值,不需要 `.value`。 ## 基本用法 ```vue{{ currentLanguageLabel }}
正在加载
语言包加载失败
``` Options `watch` 由 Vue 管理生命周期,组件卸载时会自动清理。组件外的长期监听仍使用 [`subscribe()`](/ai-i18n/api/runtime/functions/subscribe.md)。 ## TypeScript 与 IDE 提示 TypeScript 组件使用 `defineComponent()`。Vue 自身的 Options `watch` 类型不会根据被监听 的 key 推断回调参数,因此应像上例一样显式标注 `next` 和 `previous`。自动导入的声明文件、 组件实例类型和常见错误统一见 [TypeScript 与生成声明](/ai-i18n/guide/quality/typescript.md)。 ## 同名 computed 展开后声明的同名字段会覆盖默认 getter: ```ts computed: { ...i18nComputed(), currentLang() { return 'custom'; }, }, ``` 除非组件确实需要替换产品语义,否则不要覆盖这些字段。 `langLoadError` 保留 loader reject 的原始值。判断加载是否失败时,以 `langLoadState.status === 'error'` 为准;展示前应转换为应用自己的用户文案。 --- url: https://bosens-china.github.io/ai-i18n/api/runtime/vue/t-computed.md --- # tComputed() `tComputed()` 是 Vue 模式专用的 Options API 翻译 getter 工厂: ```ts import { tComputed } from 'virtual:ai-i18n'; ``` 它与 [`tRef()`](/ai-i18n/api/runtime/vue/t-ref.md) 支持相同的静态文案输入,但返回 Options `computed` 接受的 getter, 而不是 `ComputedRef`。 ## 签名 ```ts function tComputed(source: string, options?: TranslationOptions): () => string; function tComputed( strings: TemplateStringsArray, ...values: unknown[] ): () => string; function tComputed{t('语言包加载失败,请重试')}
) : null} > ); } ``` React 中必须遵守 Hook 调用规则。 React 适配器使用 `useSyncExternalStore` 订阅 Runtime revision。revision 改变时,Hook 返回的 `t` 也会获得新的函数引用,因此 React Compiler 可以使依赖该引用的缓存失效。直接 导入 Runtime 顶层 `t` 没有这个订阅边界;`"use memo"` 或 `"use no memo"` 都不能替代 `useI18n()`。 文案写法见 [React 文案写法](/ai-i18n/guide/basic/static-analysis/react.md)。 --- url: https://bosens-china.github.io/ai-i18n/api/runtime/macros/define-i18n-messages.md --- # defineI18nMessages() `defineI18nMessages()` 是全局编译宏,不是 `virtual:ai-i18n` 的 Runtime 导出,因此无需 import。 ## 签名 ```ts function defineI18nMessages