Files
zn-ai/i18n-implementation-reference.md
duanshuwen 6615d11dd6 chore: restructure project and add i18n support
- Reorganize project structure with new electron and shared directories
- Add comprehensive i18n support with Chinese, English, and Japanese locales
- Update build configurations and TypeScript paths for new structure
- Add various UI components including chat interface and task management
- Include Windows release binaries and localization files
- Update dependencies and fix import paths throughout the codebase
2026-04-06 14:39:06 +08:00

21 KiB
Raw Blame History

ClawX 项目国际化 (i18n) 实现参考

本文档分析了 ClawX 项目的国际化实现架构,为 zn-ai 项目的国际化改进提供参考和开发计划。

概述

ClawX 使用 React + i18next 框架实现国际化,具有以下特点:

  • 模块化语言文件:按功能模块组织翻译内容
  • 多语言支持:支持英文 (en)、中文 (zh)、日文 (ja)
  • 智能语言检测:自动根据系统语言和用户偏好选择语言
  • 状态管理集成:与 Zustand 状态存储深度集成,支持持久化
  • 类型安全:完整的 TypeScript 类型支持

架构设计

核心文件结构

src/
├── i18n/
│   ├── locales/
│   │   ├── en/          # 英文翻译
│   │   │   ├── common.json      # 通用翻译
│   │   │   ├── settings.json    # 设置页面翻译
│   │   │   ├── dashboard.json   # 仪表盘翻译
│   │   │   ├── chat.json        # 聊天页面翻译
│   │   │   ├── channels.json    # 频道页面翻译
│   │   │   ├── agents.json      # 代理页面翻译
│   │   │   ├── skills.json      # 技能页面翻译
│   │   │   ├── cron.json        # 定时任务翻译
│   │   │   └── setup.json       # 设置向导翻译
│   │   ├── zh/          # 中文翻译 (同上结构)
│   │   └── ja/          # 日文翻译 (同上结构)
│   └── index.ts         # i18n 配置入口
├── shared/
│   └── language.ts      # 语言解析工具
└── stores/
    └── settings.ts      # 语言状态管理

技术栈

{
  "dependencies": {
    "i18next": "^25.8.11",
    "react-i18next": "^16.5.4"
  }
}

核心代码解析

1. 语言解析工具 (shared/language.ts)

export const SUPPORTED_LANGUAGE_CODES = ['en', 'zh', 'ja'] as const;
export type LanguageCode = (typeof SUPPORTED_LANGUAGE_CODES)[number];

// 标准化语言代码(处理 zh-CN、zh_TW 等变体)
function normalizeLocale(locale: string | null | undefined): string {
  return locale?.trim().toLowerCase().replaceAll('_', '-') ?? '';
}

// 解析支持的语言代码
export function resolveSupportedLanguage(
  locale: string | null | undefined,
  fallback: LanguageCode = 'en',
): LanguageCode {
  const normalizedLocale = normalizeLocale(locale);
  if (!normalizedLocale) return fallback;

  const [baseLanguage] = normalizedLocale.split('-');
  return SUPPORTED_LANGUAGE_CODE_SET.has(baseLanguage)
    ? (baseLanguage as LanguageCode)
    : fallback;
}

关键特性:

  • 自动处理语言变体(如 zh-CNzh, en-USen
  • 安全的默认值回退机制
  • 类型安全的语言代码枚举

2. i18n 配置入口 (src/i18n/index.ts)

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import { SUPPORTED_LANGUAGE_CODES, resolveSupportedLanguage } from '../../shared/language';

// 导入所有语言文件(按模块)
import enCommon from './locales/en/common.json';
import enSettings from './locales/en/settings.json';
// ... 其他模块导入

// 定义支持的语言列表(包含显示标签)
export const SUPPORTED_LANGUAGES = [
  { code: 'en', label: 'English' },
  { code: 'zh', label: '中文' },
  { code: 'ja', label: '日本語' },
] as const;

// 构建 i18next 资源结构
const resources = {
  en: {
    common: enCommon,
    settings: enSettings,
    // ... 其他命名空间
  },
  zh: { /* 同上结构 */ },
  ja: { /* 同上结构 */ },
};

// 初始化 i18next
i18n
  .use(initReactI18next)
  .init({
    resources,
    lng: resolveSupportedLanguage(
      typeof navigator !== 'undefined' ? navigator.language : undefined
    ),
    fallbackLng: 'en',
    supportedLngs: [...SUPPORTED_LANGUAGE_CODES],
    defaultNS: 'common',            // 默认命名空间
    ns: ['common', 'settings', 'dashboard', 'chat', 'channels', 'agents', 'skills', 'cron', 'setup'],
    interpolation: { escapeValue: false }, // React 已处理转义
    react: { useSuspense: false },
  });

export default i18n;

配置亮点:

  • 多命名空间:按功能模块分离,避免单个文件过大
  • 智能语言检测:自动根据浏览器语言选择
  • 安全的回退机制:确保始终有可用的翻译
  • React 优化:禁用 Suspense 避免渲染问题

3. 状态管理集成 (src/stores/settings.ts)

import i18n from '@/i18n';
import { resolveSupportedLanguage } from '../../shared/language';

interface SettingsState {
  language: string;
  // ... 其他设置
}

const defaultSettings = {
  language: resolveSupportedLanguage(
    typeof navigator !== 'undefined' ? navigator.language : undefined
  ),
  // ... 其他默认值
};

export const useSettingsStore = create<SettingsState>()(
  persist(
    (set) => ({
      ...defaultSettings,
      
      // 初始化时加载远程设置并同步 i18n
      init: async () => {
        try {
          const settings = await hostApiFetch<Partial<typeof defaultSettings>>('/api/settings');
          const resolvedLanguage = settings.language
            ? resolveSupportedLanguage(settings.language)
            : undefined;
          set((state) => ({
            ...state,
            ...settings,
            ...(resolvedLanguage ? { language: resolvedLanguage } : {}),
          }));
          if (resolvedLanguage) {
            i18n.changeLanguage(resolvedLanguage); // 同步 i18n 实例
          }
        } catch { /* 降级处理 */ }
      },

      // 设置语言时同步更新 i18n 和远程存储
      setLanguage: (language) => {
        const resolvedLanguage = resolveSupportedLanguage(language);
        i18n.changeLanguage(resolvedLanguage);      // 1. 更新 i18n 实例
        set({ language: resolvedLanguage });        // 2. 更新本地状态
        void hostApiFetch('/api/settings/language', { // 3. 同步到主进程
          method: 'PUT',
          body: JSON.stringify({ value: resolvedLanguage }),
        }).catch(() => { });
      },
    }),
    { name: 'clawx-settings' } // Zustand 持久化配置
  )
);

集成特点:

  • 三级同步i18n 实例 ↔ 本地状态 ↔ 主进程存储
  • 持久化:使用 localStorage 持久化用户偏好
  • 错误处理:网络失败时降级到本地存储

4. 应用集成 (src/App.tsx)

import i18n from './i18n';
import { useSettingsStore } from './stores/settings';

function App() {
  const language = useSettingsStore((state) => state.language);

  // 挂载时同步 i18n 语言与持久化设置
  useEffect(() => {
    if (language && language !== i18n.language) {
      i18n.changeLanguage(language);
    }
  }, [language]);

  return <>{/* 应用内容 */}</>;
}

5. 组件使用示例 (src/pages/Setup/index.tsx)

import { useTranslation } from 'react-i18next';
import type { TFunction } from 'i18next';
import { SUPPORTED_LANGUAGES } from '@/i18n';

export function Setup() {
  // 使用多个命名空间
  const { t, i18n } = useTranslation(['setup', 'channels']);
  
  // 获取语言设置操作
  const { language, setLanguage } = useSettingsStore();

  // 动态翻译函数(用于生成动态内容)
  const getSteps = (t: TFunction): SetupStep[] => [
    {
      id: 'welcome',
      title: t('steps.welcome.title'),        // setup 命名空间
      description: t('steps.welcome.description'),
    },
    // ...
  ];

  return (
    <div>
      {/* 直接翻译 */}
      <h1>{t(`steps.${step.id}.title`)}</h1>
      
      {/* 语言选择器 */}
      <div className="flex justify-center gap-2 py-2">
        {SUPPORTED_LANGUAGES.map((lang) => (
          <Button
            key={lang.code}
            variant={language === lang.code ? 'secondary' : 'ghost'}
            onClick={() => setLanguage(lang.code)}
          >
            {lang.label}
          </Button>
        ))}
      </div>
      
      {/* 带参数的翻译 */}
      <p>{t('runtime.status.gatewayRunning', { port: gatewayStatus.port })}</p>
    </div>
  );
}

使用模式:

  • 命名空间useTranslation(['setup', 'channels']) 加载多个模块
  • 动态键t(steps.${step.id}.title) 支持动态翻译键
  • 参数插值t('key', { param: value }) 支持动态内容
  • 类型安全:通过 TFunction 类型提供类型提示

语言文件结构

模块化设计

// locales/zh/common.json
{
  "sidebar": {
    "chat": "聊天",
    "newChat": "新对话",
    "cronTasks": "定时任务",
    "skills": "技能",
    "agents": "Agents",
    "channels": "频道",
    "dashboard": "仪表盘",
    "settings": "设置",
    "devConsole": "开发者控制台",
    "models": "模型",
    "deleteSessionConfirm": "确定要删除对话 \"{{label}}\" 吗?",
    "openClawPage": "OpenClaw 页面"
  },
  "actions": {
    "save": "保存",
    "cancel": "取消",
    "delete": "删除",
    "edit": "编辑",
    "refresh": "刷新",
    "close": "关闭",
    "copy": "复制",
    "search": "搜索",
    "confirm": "确认",
    "dismiss": "忽略"
  },
  "status": {
    "running": "运行中",
    "stopped": "已停止",
    "error": "错误",
    "connected": "已连接",
    "disconnected": "已断开"
  }
}

// locales/zh/setup.json (设置向导专用)
{
  "steps": {
    "welcome": {
      "title": "欢迎使用 ClawX",
      "description": "让我们快速完成初始设置"
    },
    "runtime": {
      "title": "运行环境检查",
      "description": "确保所有依赖项已就绪"
    }
  },
  "welcome": {
    "title": "欢迎!",
    "description": "ClawX 是一个基于 OpenClaw 的图形化 AI 助手...",
    "features": {
      "noCommand": "无需命令行经验",
      "modernUI": "现代化的图形界面",
      "bundles": "预置技能包",
      "crossPlatform": "跨平台支持"
    }
  }
}

组织原则:

  1. 按功能模块分离:避免单个文件过大
  2. 嵌套结构:使用对象嵌套提高可读性
  3. 参数化:支持 {{variable}} 插值
  4. 上下文清晰:键名反映使用场景

构建配置

package.json 依赖

{
  "devDependencies": {
    "i18next": "^25.8.11",
    "react-i18next": "^16.5.4"
  }
}

Vite 配置

无需特殊配置i18next 与构建工具无关。

为 zn-ai 项目的改进建议

当前 zn-ai i18n 状态分析

zn-ai 项目目前使用 Vue 3 + vue-i18n但实现较为简单

优势:

  • 已集成 vue-i18n 基础框架
  • 基本的中英文翻译已就绪
  • 目录结构已优化 (src/i18n/)

不足:

  • 缺少模块化语言文件组织
  • 缺乏智能语言检测和解析
  • 未与状态管理集成(持久化)
  • 没有类型安全的语言代码
  • 缺少多命名空间支持

推荐架构迁移

鉴于 zn-ai 使用 Vue 3建议采用以下架构

src/i18n/
├── locales/
│   ├── en/                    # 英文模块
│   │   ├── common.json        # 通用翻译
│   │   ├── login.json         # 登录页面
│   │   ├── dashboard.json     # 仪表盘
│   │   ├── task.json          # 任务管理
│   │   ├── rate.json          # 费率管理
│   │   ├── knowledge.json     # 知识库
│   │   ├── setting.json       # 设置页面
│   │   └── component.json     # 组件翻译
│   ├── zh/                    # 中文模块(同上结构)
│   └── ja/                    # 日文模块(可选)
├── constants.ts               # 语言常量定义
├── resolver.ts                # 语言解析工具
├── store.ts                   # 语言状态管理
└── index.ts                   # vue-i18n 配置

技术选择

  1. 核心库:继续使用 vue-i18n@9.x(与 Vue 3 兼容)
  2. 状态管理:集成到现有的 Pinia store
  3. 类型安全:使用 TypeScript 增强类型提示
  4. 持久化:通过 electron-storelocalStorage

当前进展

语言选择器 UI 试点实现

已在设置页面的版本信息组件 (src/pages/setting/components/Version/index.vue) 中实现语言选择器 UI作为国际化改进的试点。

实现内容:

  • 添加了语言设置区域包含三个按钮中文、English、日本語
  • 默认语言为中文,当前选中语言高亮显示
  • 集成了现有的 vue-i18n 实例,使用 setLanguage/getLanguage API
  • 支持日语语言文件占位 (ja.json)

技术细节:

  • 使用 Element Plus 按钮组件 (el-button)
  • 响应式当前语言状态管理
  • 类型安全的语言代码 (LanguageType)
  • 遵循 ClawX 项目的 UI 设计模式

下一步:

  • 将语言选择器集成到全局设置页面
  • 添加语言状态持久化Pinia Store
  • 完善日语翻译内容
  • 推广到其他组件

开发计划

第一阶段:基础架构升级 (预计: 2-3 天)

目标:建立模块化、类型安全的 i18n 基础架构

  1. 语言文件重组

    • 创建模块化目录结构 (src/i18n/locales/en/, src/i18n/locales/zh/)
    • 按功能拆分现有翻译:common, login, dashboard, task, rate, knowledge, setting, component
    • 保持向后兼容,逐步迁移
  2. 核心工具开发

    • 创建 src/i18n/constants.ts:定义 SUPPORTED_LANGUAGES 等常量
    • 创建 src/i18n/resolver.ts:语言检测和解析工具
    • 增强类型定义:LanguageCode, NamespaceKey
  3. vue-i18n 配置升级

    • 重写 src/i18n/index.ts:支持多命名空间、智能语言检测
    • 配置回退链:zh-CNzhen
    • 添加开发调试工具

第二阶段:状态管理集成 (预计: 1-2 天)

目标:实现语言设置的持久化和全应用同步

  1. Pinia Store 创建

    • 创建 src/store/locale.ts:管理语言状态
    • 集成语言解析工具
    • 实现与 vue-i18n 实例的同步
  2. 持久化机制

    • 集成 electron-store 或使用 localStorage
    • 实现设置保存/加载
    • 添加错误处理和降级方案
  3. 主进程同步(可选)

    • 通过 IPC 与主进程设置同步
    • 系统语言变化监听

第三阶段:组件集成优化 (预计: 2-3 天)

目标:更新所有组件使用新的 i18n 架构

  1. 工具函数创建

    • 创建 useLocale() composable提供类型安全的翻译函数
    • 添加 t() 函数的 TypeScript 增强
    • 开发批量翻译更新脚本
  2. 组件迁移

    • 按页面逐步更新组件Login, Dashboard, Task, Rate, Knowledge, Setting
    • 更新路由和菜单的国际化
    • 验证所有动态插值功能
  3. 开发体验优化

    • 添加 VSCode 扩展建议 (i18n-ally)
    • 配置提取工具
    • 添加缺失翻译标记

第四阶段:高级功能与测试 (预计: 1-2 天)

目标:添加高级功能和确保质量

  1. 语言切换界面

    • 在设置页面添加语言选择器
    • 实时预览功能
    • 语言包元信息显示(作者、版本)
  2. 测试与验证

    • 单元测试:语言解析工具
    • 集成测试:语言切换流程
    • E2E 测试:多语言场景
  3. 构建优化

    • 按需加载语言包
    • 构建时提取和验证
    • 生产环境优化

第五阶段:维护与扩展 (持续)

目标:建立可持续的国际化工作流

  1. 工作流建立

    • 翻译提取脚本
    • 与翻译平台集成方案
    • 版本控制和协作流程
  2. 扩展准备

    • 支持 RTL 语言(阿拉伯语等)
    • 日期、数字、货币格式化
    • 复数规则支持
  3. 文档完善

    • 开发者指南
    • 翻译贡献指南
    • 最佳实践文档

实施优先级

高优先级(立即执行)

  1. 模块化语言文件重组
  2. 语言解析工具开发
  3. vue-i18n 配置升级
  4. Pinia store 集成

中优先级(本周内)

  1. 组件迁移(按页面)
  2. 语言切换界面
  3. 持久化实现

低优先级(后续迭代)

  1. 主进程同步
  2. 高级格式化功能
  3. 自动化翻译流程

预期收益

  1. 可维护性:模块化结构使翻译更易管理
  2. 开发者体验:类型安全、智能提示、调试工具
  3. 用户体验:智能语言检测、无缝切换、持久化偏好
  4. 扩展性:轻松添加新语言、支持高级 i18n 功能
  5. 代码质量:统一模式、减少硬编码、便于测试

具体实施任务清单(第一阶段)

任务 0语言选择器 UI 试点(已完成)

  • 在设置页面版本组件中添加语言选择器 UI (src/pages/setting/components/Version/index.vue)
  • 实现三个语言按钮中文、English、日本語默认选中中文
  • 集成现有 vue-i18n API (setLanguage/getLanguage)
  • 添加日语语言文件占位 (src/i18n/locales/ja.json)
  • 导出 LanguageType 类型供组件使用

任务 1语言文件重组

  • 创建目录结构:src/i18n/locales/en/src/i18n/locales/zh/
  • 分析现有翻译内容,按功能模块拆分:
    • common.json:通用翻译(按钮、状态、提示)
    • login.json:登录页面相关
    • dashboard.json:仪表盘相关
    • task.json:任务管理相关
    • rate.json:费率管理相关
    • knowledge.json:知识库相关
    • setting.json:设置页面相关
    • component.json:组件专用翻译
  • 迁移现有翻译内容到新结构
  • 验证 JSON 格式正确性

任务 2核心工具开发

  • 创建 src/i18n/constants.ts
    export const SUPPORTED_LANGUAGE_CODES = ['en', 'zh', 'ja'] as const;
    export type LanguageCode = (typeof SUPPORTED_LANGUAGE_CODES)[number];
    export const SUPPORTED_LANGUAGES = [
      { code: 'en', label: 'English' },
      { code: 'zh', label: '中文' },
      { code: 'ja', label: '日本語' },
    ] as const;
    
  • 创建 src/i18n/resolver.ts
    • normalizeLocale():标准化语言代码
    • resolveSupportedLanguage():解析支持的语言
    • 处理 zh-CNzh-TWen-US 等变体
  • 添加类型定义:LanguageCodeNamespaceTranslationKey

任务 3vue-i18n 配置升级

  • 重写 src/i18n/index.ts
    • 支持多命名空间导入
    • 集成语言解析工具
    • 配置智能回退链:zh-CNzhen
    • 添加开发调试选项
  • 验证配置正确性:
    • 运行 npm run typecheck 检查类型
    • 运行 npm run build:vite 验证构建
    • 启动开发服务器测试基础功能

任务 4Pinia Store 集成

  • 创建 src/store/locale.ts
    • 状态:language: LanguageCode
    • 动作:setLanguage(lang: LanguageCode)
    • 持久化:集成 localStorageelectron-store
  • 实现与 vue-i18n 实例的同步:
    • Store 初始化时读取持久化设置
    • 语言切换时更新 i18n 实例
    • 监听 i18n 语言变化更新 Store
  • src/main.ts 中集成 Store

任务 5基础组件迁移试点

  • 创建 src/composables/useLocale.ts
    • 提供类型安全的 t() 函数
    • 集成命名空间支持
    • 添加语言切换功能
  • 迁移登录页面 (src/pages/login/index.vue)
    • 使用新的 useLocale() composable
    • 更新所有静态文本为翻译键
    • 验证动态插值功能
  • 迁移侧边栏菜单:
    • 更新菜单项文本
    • 验证语言切换实时生效

验收标准

  • 类型检查通过 (npm run typecheck)
  • 生产构建通过 (npm run build:vite)
  • 开发服务器正常启动 (npm run dev)
  • 中英文切换功能正常
  • 语言设置持久化生效
  • 控制台无 i18n 相关错误

第一阶段完成状态

任务完成情况

  • 任务 0语言选择器 UI 试点 - 已完成(设置页面版本组件)
  • 任务 1语言文件重组 - 已完成(创建模块化目录结构,拆分现有翻译)
  • 任务 2核心工具开发 - 已完成(创建 constants.ts 和 resolver.ts
  • 任务 3vue-i18n配置升级 - 已完成(重写 index.ts支持多命名空间
  • 任务 4Pinia Store集成 - 已完成(创建 locale.ts实现状态管理
  • 任务 5基础组件迁移试点 - 已完成(创建 useLocale composable迁移登录页面

验证结果

  • 类型检查通过 (npm run typecheck)
  • 生产构建通过 (npm run build:vite)
  • 无代码缺失,保持向后兼容

下一步建议

第一阶段基础架构已成功建立,建议继续推进第二阶段(状态管理集成优化)和第三阶段(组件集成优化),逐步将新的国际化架构推广到全应用。

结论

ClawX 的 i18n 实现提供了一个优秀的参考架构,其核心思想——模块化、类型安全、状态集成、智能解析——完全适用于 zn-ai 项目。通过分阶段实施上述开发计划zn-ai 可以在 1-2 周内建立专业级的国际化系统,为多语言用户提供更好的体验,同时提高代码的可维护性和开发效率。

建议立即开始第二阶段实施,逐步推广到全应用。