Skip to content

国际化 ​

AI Chat UI 内置中英双语(zh-CN / en-US),默认 zh-CN,安装即用、零配置。内部基于 vue-i18n(legacy: false)的模块级单例 aiChatI18n——不要求宿主 app.use,与宿主自有的 vue-i18n 实例天然隔离;宿主也可以通过它注入任意语言或覆盖内置文案。

使用语言切换组件 ​

最简单的方式是直接放置语言切换组件。非可控模式下,用户在组件里选择语言即切换全局语言并持久化:

vue
<script setup lang="ts">
import { LanguageToggle } from '@toimc/vue'
</script>

<template>
  <LanguageToggle />
</template>

默认提供「简体中文 / English」两项。自定义语言列表、v-model 可控用法见 LanguageToggle 文档。

编程式切换 ​

不需要 UI 时,用 setAiChatLocale 直接切换:

ts
import { setAiChatLocale } from '@toimc/vue'

setAiChatLocale('en-US')

setAiChatLocale 一次完成三件事:

  1. 写入 aiChatI18n 实例的 locale;
  2. 同步 <html lang> 属性(无障碍 / 字体选择友好);
  3. 持久化到 localStorage(key 为 ai-chat-locale),刷新后保留。

不希望跨会话保留时传 { persist: false }:

ts
// 只切换当前会话,不写 localStorage
setAiChatLocale('en-US', { persist: false })

字典组织 ​

字典源码位于 packages/vue/src/locales/:

text
packages/vue/src/locales/
├── zh-CN.ts   # 中文字典(source of truth,类型由它推导)
├── en-US.ts   # 英文字典(satisfies MessageSchema)
└── index.ts   # aiChatI18n 单例 + setAiChatLocale / getInitialLocale

字典按组件域拆分命名空间,key 一律 camelCase:

命名空间覆盖文案
shared通用操作(关闭、复制、已复制)
promptInput输入区占位符、免责声明、附件上传
conversation空态标题/描述、未读滚动提示
message消息身份标签(你 / AI Chat UI)
toolCall工具调用面板(六态状态、参数、结果、错误)
citation引用来源(角标卡、来源计数、上一个/下一个)
attachments附件区空态
comparison对比消息标签与按钮
markdown图表渲染中 / 渲染失败
thinking思考过程(标题、已思考耗时、步骤状态)
welcome欢迎页标题与描述
prompts提示词面板标题
feedback点赞点踩与评论
confirmation工具审批卡(允许 / 拒绝)
branchPicker分支翻页(上一个/下一个版本、版本计数)
jsonDiffJSON 差异视图(修改前后标签、内容相同)
modelIcon未知模型兜底文案
messageActions消息操作(复制、重新生成、编辑)
suggestion输入建议无匹配项
providerProvider 设置对话框(服务类型、预设、表单校验)
imageLightbox图片预览(上一张/下一张)
codeBlock代码块展开 / 收起

类型安全由 MessageSchema 保证:zh-CN.ts 是 source of truth(export type MessageSchema = typeof zhCN),en-US.ts 用 satisfies MessageSchema 约束——新增中文 key 时英文缺 key 或写错 key 会在编译期报错,不会静默回退。

组件文案模式 ​

带文案的组件 props 遵循「props 优先、t() 兜底」:宿主显式传了 props 就用 props,没传则回退到当前语言的字典。这样单实例场景零配置拿到正确语言,多语言之外的定制(如特定文案 A/B)也不用动字典:

vue
<!-- 不传 placeholder:跟随当前语言,中文显示「给 AI Chat UI 发送消息...」,英文显示 "Send a message to AI Chat UI..." -->
<PromptInput>
  <PromptInputTextarea />
</PromptInput>

<!-- 传了 placeholder:props 优先,不进字典 -->
<PromptInput placeholder="问我任何关于订单的问题">
  <PromptInputTextarea />
</PromptInput>

组件内部统一通过库内单例取翻译函数:

ts
import { aiChatI18n } from '@toimc/vue'

const { t } = aiChatI18n.global
// props.placeholder ?? t('promptInput.placeholder')

宿主自定义语言 / 覆盖文案 ​

内置语言之外,宿主可注入任意语言。注意 setLocaleMessage 是整体替换——合并自定义内容时要带上 getLocaleMessage 返回的已有内容:

ts
import { aiChatI18n, setAiChatLocale } from '@toimc/vue'

aiChatI18n.global.setLocaleMessage('ja-JP', {
  ...aiChatI18n.global.getLocaleMessage('ja-JP'), // 已有内容(首次为空)
  myApp: { hello: 'こんにちは' },
})
setAiChatLocale('ja-JP')

新语言只需注入差异 key:命中不到的 key 会按 fallbackLocale: 'zh-CN' 回退,不必一次翻译整本字典。

覆盖内置文案同理(对已存在的 locale 做合并):

ts
aiChatI18n.global.setLocaleMessage('zh-CN', {
  ...aiChatI18n.global.getLocaleMessage('zh-CN'),
  promptInput: { placeholder: '有话直说…' },
})

配合 LanguageToggle 的 locales prop 自定义下拉列表,即可提供完整的第三方语言入口:

vue
<LanguageToggle
  :locales="[
    { value: 'zh-CN', label: '简体中文' },
    { value: 'ja-JP', label: '日本語' },
  ]"
/>

初始化顺序 ​

首次加载时,getInitialLocale() 按以下顺序决定初始语言:

  1. localStorage['ai-chat-locale'](用户上次的选择);
  2. navigator.language(浏览器语言,en* 前缀 → en-US);
  3. 兜底 zh-CN。

初始化只读不写(不会把浏览器语言回写进 localStorage),用户首次显式切换后才产生持久化记录。SSR 环境下固定返回 zh-CN,到客户端再按上述顺序校正。