Files
everything-is-suitable/docs/superpowers/plans/2026-04-28-uniapp-i18n/plan.md
T
张翔 a39b4388f3 chore: 添加文档、资源与测试输出
- assets/ 静态资源
- docs/superpowers/ 技能文档
- dogfood-output/ 测试验证输出
2026-04-29 21:17:10 +08:00

19 KiB
Raw Blame History

UniApp 主应用国际化(i18n)实现计划

面向 AI 代理的工作者: 必需子技能:使用 superpowers:subagent-driven-development(推荐)或 superpowers:executing-plans 逐任务实现此计划。步骤使用复选框(- [ ])语法来跟踪进度。

目标: 为 UniApp 主应用引入 vue-i18n 国际化体系,支持 9 种语言,将所有硬编码中文 UI 文本替换为 $t() / t() 调用。

架构: 集中式翻译文件方案,所有翻译键值对按语言分文件存放于 src/locales/,通过 vue-i18n 实例注入 Vue 应用。领域术语保留中文原词不纳入翻译体系。

技术栈: vue-i18n@9, Vue 3 Composition API, UniApp, Vitest

设计规格: docs/superpowers/specs/2026-04-28-uniapp-i18n-design.md


整体架构流程

graph TD
    A[用户启动 App] --> B{localStorage 有 preferred-locale?}
    B -->|是| C[读取存储的 locale]
    B -->|否| D{读取系统语言}
    D -->|匹配支持语言| E[使用系统语言]
    D -->|不匹配| F[回退 zh-CN]
    C --> G[应用 vue-i18n locale]
    E --> G
    F --> G
    G --> H[渲染页面 - $t 替换硬编码文本]
    H --> I{用户切换系统语言?}
    I -->|是| J[重启 App 重新检测]
    I -->|否| H

组件改造流程

graph LR
    subgraph 改造前
        A1[模板硬编码中文] --> B1[Script 硬编码中文]
        B1 --> C1[pages.json 硬编码中文]
    end
    subgraph 改造后
        A2["模板: {{ $t('key') }}"] --> B2["Script: const { t } = useI18n(); t('key')"]
        B2 --> C2["onShow: uni.setNavigationBarTitle"]
    end
    A1 -.->|替换| A2
    B1 -.->|替换| B2
    C1 -.->|运行时覆盖| C2

Phase 依赖关系

graph TD
    P1["Phase 1: 基础设施<br/>安装 vue-i18n + 创建核心模块"] --> P2["Phase 2: 翻译文件<br/>创建 9 种语言翻译"]
    P2 --> P3["Phase 3: 页面改造<br/>3 个页面 + pages.json"]
    P2 --> P4["Phase 4: 组件改造<br/>10 个组件"]
    P3 --> P5["Phase 5: 测试与验证<br/>完整性 + 组件 + E2E"]
    P4 --> P5

文件结构

新建文件

文件路径 职责
src/locales/index.ts vue-i18n 实例创建、语言检测/切换/持久化
src/locales/zh-CN.ts 简体中文翻译(主翻译源)
src/locales/zh-TW.ts 繁體中文翻译
src/locales/en.ts English 翻译
src/locales/ja.ts 日本語翻译
src/locales/ko.ts 한국어 翻译
src/locales/de.ts Deutsch 翻译
src/locales/fr.ts Français 翻译
src/locales/es.ts Español 翻译
src/locales/pt.ts Português 翻译
src/locales/__tests__/completeness.test.ts 翻译完整性校验测试
src/locales/__tests__/interpolation.test.ts 插值格式校验测试

修改文件

文件路径 改动说明
package.json 添加 vue-i18n 依赖
src/main.ts 挂载 i18n 实例
src/pages/almanac-search/index.vue 替换硬编码中文为 $t() / t()
src/pages/ziwei/index.vue 替换硬编码中文为 $t() / t()
src/pages/fortune/index.vue 替换硬编码中文为 $t() / t()
src/components/BottomNavigation/BottomNavigation.vue 替换硬编码中文
src/components/EmptyState/index.vue 移除中文默认值
src/components/SearchConditionPanel/index.vue 替换硬编码中文
src/components/SearchConditionItem/index.vue 替换硬编码中文(领域术语保留)
src/components/SearchResultList/index.vue 替换硬编码中文
src/components/SearchResultCard/index.vue 替换硬编码中文
src/components/SortSwitcher/index.vue 替换硬编码中文
src/components/ExportPanel/index.vue 替换硬编码中文
src/components/SearchHistoryPanel/index.vue 替换硬编码中文
src/components/TemplatePanel/index.vue 替换硬编码中文

Phase 1:基础设施 — 安装 vue-i18n + 创建核心模块

文件:

  • 修改:package.json
  • 创建:src/locales/index.ts
  • 创建:src/locales/zh-CN.ts
  • 修改:src/main.ts

任务 1.1:安装 vue-i18n 依赖

  • 步骤 1:安装 vue-i18n

运行:cd everything-is-suitable-uniapp && npm install vue-i18n@9

预期:package.json 中出现 "vue-i18n": "^9.x.x" 依赖

  • 步骤 2:验证安装

运行:cd everything-is-suitable-uniapp && node -e "const v = require('vue-i18n/package.json'); console.log(v.version)"

预期:输出 9.x.x 版本号

  • 步骤 3Commit

cd everything-is-suitable-uniapp && git add package.json package-lock.json && git commit -m "chore: 安装 vue-i18n@9 依赖"

任务 1.2:创建 zh-CN 主翻译源文件

  • 步骤 1:创建 src/locales/zh-CN.ts — 包含 common/nav/almanac/ziwei/fortune/search/template/export/history 共 9 个命名空间,约 80 个翻译键

  • 步骤 2Commit

cd everything-is-suitable-uniapp && git add src/locales/zh-CN.ts && git commit -m "feat(i18n): 创建简体中文主翻译源 zh-CN.ts"

任务 1.3:创建 locales/index.ts 核心模块

  • 步骤 1:创建 src/locales/index.ts — 包含 createI18n 实例、detectLocale 语言检测、setLocale 切换持久化、getLocale 获取当前语言、SUPPORTED_LOCALES 常量、localeNames 映射

  • 步骤 2Commit

cd everything-is-suitable-uniapp && git add src/locales/index.ts && git commit -m "feat(i18n): 创建 vue-i18n 实例与语言检测/切换核心模块"

任务 1.4:改造 main.ts 挂载 i18n

  • 步骤 1:修改 src/main.ts — 添加 import { i18n } from './locales'app.use(i18n)

  • 步骤 2:验证构建无报错

运行:cd everything-is-suitable-uniapp && npx vite build --mode development 2>&1 | head -20

预期:构建成功,无模块解析错误

  • 步骤 3Commit

cd everything-is-suitable-uniapp && git add src/main.ts && git commit -m "feat(i18n): 在 main.ts 中挂载 vue-i18n 实例"


Phase 2:翻译文件 — 创建 8 种非中文翻译

依赖: Phase 1

每个任务结构相同:创建翻译文件 → Commit。翻译键结构必须与 zh-CN.ts 完全一致。

任务 2.1:创建繁體中文翻译 zh-TW.ts

  • 步骤 1:创建 src/locales/zh-TW.ts — 简转繁,保持相同键结构
  • 步骤 2Commit

任务 2.2:创建英文翻译 en.ts

  • 步骤 1:创建 src/locales/en.ts — 领域术语保留拼音(如 Zi Wei Dou Shu
  • 步骤 2Commit

任务 2.3:创建日文翻译 ja.ts

  • 步骤 1:创建 src/locales/ja.ts — 命理术语保留汉字(如 紫微斗数、三方四正)
  • 步骤 2Commit

任务 2.4:创建韩文翻译 ko.ts

  • 步骤 1:创建 src/locales/ko.ts — 命理术语保留汉字(如 자미두수)
  • 步骤 2Commit

任务 2.5:创建德文翻译 de.ts

  • 步骤 1:创建 src/locales/de.ts — 领域术语保留拼音
  • 步骤 2Commit

任务 2.6:创建法文翻译 fr.ts

  • 步骤 1:创建 src/locales/fr.ts — 领域术语保留拼音
  • 步骤 2Commit

任务 2.7:创建西班牙文翻译 es.ts

  • 步骤 1:创建 src/locales/es.ts — 领域术语保留拼音
  • 步骤 2Commit

任务 2.8:创建葡萄牙文翻译 pt.ts

  • 步骤 1:创建 src/locales/pt.ts — 领域术语保留拼音
  • 步骤 2Commit

Phase 3:页面改造 — 3 个页面 + pages.json

依赖: Phase 1, Phase 2

graph TD
    P3A["任务 3.1: almanac-search"] --> P3D["任务 3.4: pages.json 确认"]
    P3B["任务 3.2: ziwei"] --> P3D
    P3C["任务 3.3: fortune"] --> P3D

任务 3.1:改造黄历搜索页 almanac-search/index.vue

文件: 修改 src/pages/almanac-search/index.vue

  • 步骤 1:在 <script setup> 中添加 i18n 导入import { useI18n } from 'vue-i18n' + const { t } = useI18n()
  • 步骤 2:替换模板硬编码中文黄历搜索{{ $t('almanac.pageTitle') }}搜索中...{{ $t('almanac.searching') }}重试{{ $t('common.retry') }}
  • 步骤 3:替换 script 硬编码中文error.value = t('almanac.keywordHint')error.value = t('almanac.noResult')error.value = t('search.addConditionHint')error.value = t('almanac.searchFailed')
  • 步骤 4:添加 onShow 动态设置导航栏标题import { onShow } from '@dcloudio/uni-app' + onShow(() => { uni.setNavigationBarTitle({ title: t('almanac.pageTitle') }) })
  • 步骤 5:验证构建
  • 步骤 6Commit

任务 3.2:改造紫微斗数页 ziwei/index.vue

文件: 修改 src/pages/ziwei/index.vue

  • 步骤 1:添加 i18n 导入
  • 步骤 2:替换模板硬编码中文出生信息{{ $t('ziwei.birthInfo') }}出生日期{{ $t('ziwei.birthDate') }}请选择{{ $t('ziwei.pleaseSelect') }}出生时辰{{ $t('ziwei.birthHour') }}性别{{ $t('ziwei.gender') }}{{ $t('common.male') }}{{ $t('common.female') }}排盘中...{{ $t('ziwei.generating') }}排盘{{ $t('ziwei.generate') }}紫微斗数盘{{ $t('ziwei.chartTitle') }}三方四正分析{{ $t('ziwei.sanFangAnalysis') }}三方得分{{ $t('ziwei.sanFangScore') }}四正得分{{ $t('ziwei.siZhengScore') }}综合评价{{ $t('ziwei.overallEval') }}盘面概述{{ $t('ziwei.summary') }}{{ $t('ziwei.scoreUnit') }}
  • 步骤 3:添加 onShow 动态设置导航栏标题
  • 步骤 4:验证构建
  • 步骤 5Commit

任务 3.3:改造运势分析页 fortune/index.vue

文件: 修改 src/pages/fortune/index.vue

  • 步骤 1:添加 i18n 导入
  • 步骤 2:替换模板硬编码中文日运{{ $t('fortune.daily') }}月运{{ $t('fortune.monthly') }}选择日期{{ $t('fortune.selectDate') }}选择月份{{ $t('fortune.selectMonth') }}综合运势:{{ $t('fortune.overallFortune') }}{{ $t('ziwei.scoreUnit') }}事业:{{ $t('fortune.career') }}财运:{{ $t('fortune.wealth') }}感情:{{ $t('fortune.relationship') }}健康:{{ $t('fortune.health') }}幸运色:{{ $t('fortune.luckyColor') }}幸运数字:{{ $t('fortune.luckyNumber') }}幸运方位:{{ $t('fortune.luckyDirection') }}请先在紫微斗数页面完成排盘{{ $t('fortune.noChart') }}
  • 步骤 3:添加 onShow 动态设置导航栏标题
  • 步骤 4:验证构建
  • 步骤 5Commit

任务 3.4pages.json 保持中文初始值

文件: src/pages.json(无需修改)

pages.json 中的 navigationBarTitleText 保持现有中文值作为首次渲染前的兜底,运行时由各页面 onShow 生命周期动态覆盖。


Phase 4:组件改造 — 10 个组件

依赖: Phase 1, Phase 2

graph TD
    C1["BottomNavigation"] --> CV["验证构建"]
    C2["EmptyState"] --> CV
    C3["SearchConditionPanel"] --> CV
    C4["SearchConditionItem"] --> CV
    C5["SearchResultList"] --> CV
    C6["SearchResultCard"] --> CV
    C7["SortSwitcher"] --> CV
    C8["ExportPanel"] --> CV
    C9["SearchHistoryPanel"] --> CV
    C10["TemplatePanel"] --> CV

任务 4.1:改造 BottomNavigation

文件: 修改 src/components/BottomNavigation/BottomNavigation.vue

  • 步骤 1:添加 i18n 导入import { useI18n } from 'vue-i18n' + const { t } = useI18n()
  • 步骤 2:将 tabs 数组中的 label 改为 computedlabel: t('nav.almanac')label: t('nav.ziwei')label: t('nav.fortune')
  • 步骤 3Commit

任务 4.2:改造 EmptyState

文件: 修改 src/components/EmptyState/index.vue

  • 步骤 1:移除 withDefaults 中的中文默认值 — 移除 titledescriptionactionText 的默认值,由调用方通过 $t() 传入
  • 步骤 2Commit

任务 4.3:改造 SearchConditionPanel

文件: 修改 src/components/SearchConditionPanel/index.vue

  • 步骤 1:添加 i18n 导入并替换硬编码中文搜索条件{{ $t('search.conditions') }}添加条件{{ $t('search.addCondition') }}请添加搜索条件{{ $t('search.addConditionEmpty') }}搜索天数{{ $t('search.days') }}{{ $t('search.dayUnit') }}搜索{{ $t('common.search') }}
  • 步骤 2Commit

任务 4.4:改造 SearchConditionItem

文件: 修改 src/components/SearchConditionItem/index.vue

  • 步骤 1:添加 i18n 导入并替换硬编码中文事项{{ $t('search.items') }}逻辑运算符{{ $t('search.operator') }}排除条件{{ $t('search.excludeCondition') }}
  • 步骤 2:将 typeOptions 和 operatorOptions 改为 computed{ label: t('search.typeSuitable'), value: 'suitable' }{ label: t('search.typeUnsuitable'), value: 'unsuitable' }{ label: t('search.operatorAnd'), value: 'and' }{ label: t('search.operatorOr'), value: 'or' }
  • 步骤 3Commit — 注意:suitableActivitiesavoidActivities 数组保持中文硬编码(领域术语策略)

任务 4.5:改造 SearchResultList

文件: 修改 src/components/SearchResultList/index.vue

  • 步骤 1:添加 i18n 导入并替换硬编码中文搜索结果{{ $t('search.searchResult') }}共{results.length}条结果{{ $t('search.resultCount', { count: results.length }) }}加载中...{{ $t('common.loading') }}
  • 步骤 2Commit

任务 4.6:改造 SearchResultCard

文件: 修改 src/components/SearchResultCard/index.vue

  • 步骤 1:添加 i18n 导入并替换硬编码中文{{ $t('search.typeSuitable') }}{{ $t('search.typeUnsuitable') }}匹配度:{{ $t('search.matchCount', { count: result.matchCount }) }}
  • 步骤 2Commit

任务 4.7:改造 SortSwitcher

文件: 修改 src/components/SortSwitcher/index.vue

  • 步骤 1:添加 i18n 导入并替换硬编码中文排序{{ $t('search.sort') }}日期{{ $t('search.sortByDate') }}匹配度{{ $t('search.sortByMatch') }}
  • 步骤 2Commit

任务 4.8:改造 ExportPanel

文件: 修改 src/components/ExportPanel/index.vue

  • 步骤 1:添加 i18n 导入并替换硬编码中文导出搜索结果{{ $t('export.title') }}选择导出格式{{ $t('export.selectFormat') }}选择导出内容{{ $t('export.selectContent') }}取消{{ $t('common.cancel') }}导出{{ $t('common.confirm') }}
  • 步骤 2:将 contentOptions 改为 computed{ label: t('export.date'), value: 'date' }{ label: t('export.lunarDate'), value: 'lunarDate' }{ label: t('export.weekday'), value: 'weekday' }{ label: t('export.matchedItems'), value: 'matchedItems' }{ label: t('export.matchCount'), value: 'matchCount' }
  • 步骤 3Commit

任务 4.9:改造 SearchHistoryPanel

文件: 修改 src/components/SearchHistoryPanel/index.vue

  • 步骤 1:添加 i18n 导入并替换硬编码中文搜索历史{{ $t('history.title') }}清除历史{{ $t('history.clear') }}确认清除{{ $t('history.clearConfirm') }}确定要清除所有搜索历史吗?{{ $t('history.clearConfirmMsg') }}暂无搜索历史{{ $t('history.empty') }}执行搜索后,搜索条件将显示在这里{{ $t('history.emptyDesc') }}
  • 步骤 2:将 formatTime 函数中的中文改为 t() 调用刚刚t('history.justNow')小时前t('history.hoursAgo', { count })天前t('history.daysAgo', { count })
  • 步骤 3Commit

任务 4.10:改造 TemplatePanel

文件: 修改 src/components/TemplatePanel/index.vue

  • 步骤 1:添加 i18n 导入并替换硬编码中文搜索模板{{ $t('template.title') }}、搜索框占位 → {{ $t('template.searchPlaceholder') }}暂无模板{{ $t('template.empty') }}没有找到符合条件的模板{{ $t('template.emptyDesc') }}全部{{ $t('template.all') }}
  • 步骤 2Commit

Phase 5:测试与验证

依赖: Phase 3, Phase 4

graph TD
    T1["任务 5.1: 翻译完整性测试"] --> T4["任务 5.4: 全量构建验证"]
    T2["任务 5.2: 插值格式测试"] --> T4
    T3["任务 5.3: 组件 i18n 集成测试"] --> T4
    T4 --> T5["任务 5.5: 运行全量测试"]
    T5 --> T6["任务 5.6: 最终 Commit"]

任务 5.1:创建翻译完整性测试

文件: 创建 src/locales/__tests__/completeness.test.ts

  • 步骤 1:编写测试 — 校验所有 9 种语言的翻译键与 zh-CN 完全一致(嵌套 key 逐层比对)
  • 步骤 2:运行测试验证通过

运行:cd everything-is-suitable-uniapp && npx vitest run src/locales/__tests__/completeness.test.ts

预期:PASS

  • 步骤 3Commit

任务 5.2:创建插值格式测试

文件: 创建 src/locales/__tests__/interpolation.test.ts

  • 步骤 1:编写测试 — 校验所有语言的插值变量名一致(如 {count} 在所有语言中均存在)
  • 步骤 2:运行测试验证通过
  • 步骤 3Commit

任务 5.3:创建组件 i18n 集成测试

文件: 修改现有组件测试文件

  • 步骤 1:在 vitest 配置中添加 vue-i18n 插件 — 确保 @vue/test-utilsmount 能正确注入 i18n
  • 步骤 2:为 BottomNavigation 编写 i18n 测试 — 验证渲染文本来自翻译键
  • 步骤 3:运行测试验证通过
  • 步骤 4Commit

任务 5.4:全量构建验证

  • 步骤 1:运行 vite build

运行:cd everything-is-suitable-uniapp && npx vite build 2>&1 | tail -10

预期:构建成功,无错误

  • 步骤 2:运行 H5 开发服务器验证页面渲染

运行:cd everything-is-suitable-uniapp && npm run dev:h5

预期:页面正常渲染,导航栏标题为中文(默认 locale),底部导航显示中文

任务 5.5:运行全量测试

  • 步骤 1:运行所有测试

运行:cd everything-is-suitable-uniapp && npx vitest run

预期:所有测试通过

任务 5.6:最终 Commit

  • 步骤 1Commit

cd everything-is-suitable-uniapp && git add -A && git commit -m "feat(i18n): 完成 UniApp 国际化改造 — 9 种语言支持"


自检清单

  1. 规格覆盖度: 设计规格中的 9 种语言 、集中式翻译文件 、vue-i18n 、领域术语保留 、pages.json 运行时覆盖 、3 个页面改造 、10 个组件改造 、翻译完整性测试
  2. 占位符扫描: 无 TODO/待定/后续实现
  3. 类型一致性: 所有翻译键名在 zh-CN.ts 定义,其他语言文件保持一致