跳转到内容

国际化集成指南

RTC Agent 基于 @lit/localize 构建完整的国际化系统,支持运行时语言切换,无需重新加载页面。

组件启动时按以下优先级确定初始语言:

  1. HTML attribute:<rtc-agent lang="en-US"> 设置的 lang 属性(最高优先级)
  2. localStorage:键 rtc-agent-locale 中保存的用户选择
  3. 浏览器语言:navigator.language,若在支持列表中则采用
  4. 默认值:回退到源语言 zh-CN

组件启动时调用 initLocale() 初始化语言环境:

import { initLocale } from '@rtc-agent/component';
// 在应用启动时调用
await initLocale();

初始化逻辑:

  1. 检查 localStorage(键:rtc-agent-locale)中是否有保存的语言
  2. 检查浏览器语言 navigator.language 是否在支持列表中
  3. 回退到源语言 zh-CN
  4. 同步 document.documentElement.lang 属性(屏幕阅读器发音规则)

lit-localize.json 定义语言配置:

{
"sourceLocale": "zh-CN",
"targetLocales": ["en-US"],
"tsConfig": "tsconfig.json",
"output": {
"mode": "runtime",
"localeCodesModule": "src/.generated/locale-codes.ts"
}
}

运行时切换语言:

import { switchLocale, type SupportedLocale } from '@rtc-agent/component';
// 切换到英文
await switchLocale('en-US');
// 切换回中文
await switchLocale('zh-CN');

switchLocale() 行为:

步骤操作
1调用 @lit/localize 的 setLocale() 加载语言包
2保存到 localStorage(键:rtc-agent-locale)
3更新 document.documentElement.lang 属性
4所有 @localized() 组件自动重新渲染

获取当前激活的语言(同步):

import { getLocale } from '@rtc-agent/component';
const current = getLocale(); // 'zh-CN' | 'en-US'

仅持久化语言偏好到 localStorage,不触发语言切换。适用于在组件挂载前保存用户选择:

import { persistLocale } from '@rtc-agent/component';
persistLocale('en-US');
语言代码语言类型
zh-CN简体中文源语言
en-USEnglish目标语言
// 类型安全
type SupportedLocale = 'zh-CN' | 'en-US';
// 类型守卫
import { isValidLocale } from '@rtc-agent/component';
if (isValidLocale(userInput)) {
await switchLocale(userInput);
}

需要注意的是,组件中存在两类文本:用户界面文本(受 i18n 系统控制,随 switchLocale() 切换)和 Agent-Facing 消息(始终为英文,不受 UI 语言影响)。

Agent-Facing 消息指写入虚拟文件系统、供 LLM 读取的文本,例如:

  • 参数校验错误信息(/functions/INDEX.md 中引用的错误提示)
  • 自动生成的函数文档(AGENT.md、/functions/*.md)
  • 场景索引(/scenarios/INDEX.md)

这些消息统一使用英文,因为 Agent 提示和工具调用协议均为英文,混用中文会导致 LLM 解析不一致。宿主应用集成时无需为这些消息做翻译处理。

使用 @localized() 装饰器标记需要响应语言变化的组件:

import { LitElement, html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { localized, msg } from '@lit/localize';
import { consume } from '@lit/context';
import { localeContext, type LocaleContextValue } from '@rtc-agent/component';
@localized()
@customElement('my-component')
export class MyComponent extends LitElement {
@consume({ context: localeContext, subscribe: true })
@state()
private _localeCtx: LocaleContextValue = { /* ... */ };
render() {
// 引用 locale 确保语言切换时重新渲染
void this._localeCtx.locale;
return html`
<div>${msg('欢迎使用 RTC Agent')}</div>
<p>${msg('这是一个国际化组件')}</p>
`;
}
}

msg() 标记需要翻译的文本:

import { msg, str } from '@lit/localize';
// 简单文本
msg('你好世界')
// 带变量的文本
const name = '用户';
msg(str`你好,${name}!`)
// 带 HTML 的文本(需转义)
msg(html`点击 <a href="/help">${msg('帮助')}</a>`)

通过 @lit/context 获取语言上下文:

import { consume } from '@lit/context';
import { localeContext, type LocaleContextValue } from '@rtc-agent/component';
@consume({ context: localeContext, subscribe: true })
@state()
private _localeCtx: LocaleContextValue = {
locale: 'zh-CN',
setLocale: async () => {},
locales: ['zh-CN', 'en-US'],
};

在组件中使用 msg() 包裹需要翻译的文本:

render() {
return html`
<h1>${msg('设置')}</h1>
<p>${msg('选择界面语言')}</p>
`;
}

运行提取命令生成 XLIFF 文件:

终端窗口
npm run localize:extract

这会在 xliff/en-US.xlf 中生成翻译条目:

<trans-unit id="s8ef06a6080e58381">
<source>设置</source>
<target state="new">设置</target>
<note from="lit-localize">Settings panel title</note>
</trans-unit>

编辑 xliff/en-US.xlf,将 <target> 替换为翻译后的文本:

<trans-unit id="s8ef06a6080e58381">
<source>设置</source>
<target>Settings</target>
</trans-unit>

运行构建命令生成编译后的语言包:

终端窗口
npm run localize:build

这会在 src/locales/en-US.ts 中生成优化后的翻译映射。

RTC Agent 提供基于 --rtc-font-size-user 的等比缩放字号体系。

rtc-agent {
/* 设置基础字号(12-24px) */
--rtc-font-size-user: 16px;
}

所有字号 token 按基础字号等比缩放:

Token计算公式12px14px (默认)16px18px20px
--rtc-font-size-xsbase * 0.85710px12px14px15px17px
--rtc-font-size-smbase * 0.92911px13px15px17px19px
--rtc-font-size-basebase12px14px16px18px20px
--rtc-font-size-mdbase * 1.14314px16px18px21px23px
--rtc-font-size-lgbase * 1.28615px18px21px23px26px
--rtc-font-size-xlbase * 1.42917px20px23px26px29px
--rtc-font-size-2xlbase * 1.71421px24px27px31px34px

设置面板中提供字号调节控件:

// 在 rtc-settings-layout 中
private _renderAppearance() {
return html`
<div class="setting-row">
<label for="font-size-input">${msg('字体大小')}</label>
<input
type="number"
id="font-size-input"
min="12"
max="24"
step="1"
.value=${String(this._settingsCtx.state.appearance.fontSize)}
@change=${(e: Event) => {
const size = Number((e.target as HTMLInputElement).value);
this._updateSetting('appearance', { fontSize: size });
}}
/>
<span>px</span>
</div>
`;
}

SettingsController 自动将字号应用到文档根节点:

// SettingsController._applyFontSize()
document.documentElement.style.setProperty(
'--rtc-font-size-user',
`${clamped}px`
);

这确保所有 Shadow DOM 中的组件都能继承字号设置。

实践说明
✅ 始终使用 msg()所有用户可见文本都应包裹在 msg() 中
✅ 引用 locale在 render() 中引用 this._localeCtx.locale 确保重渲染
✅ 使用 @localized()需要响应语言变化的组件必须添加此装饰器
✅ 类型安全使用 SupportedLocale 类型和 isValidLocale() 守卫
❌ 不要硬编码避免在 msg() 外硬编码用户可见文本
❌ 不要直接调用 _setLocale使用 switchLocale() 确保持久化和 DOM 同步