chore: 添加文档、资源与测试输出
- assets/ 静态资源 - docs/superpowers/ 技能文档 - dogfood-output/ 测试验证输出
This commit is contained in:
@@ -0,0 +1,374 @@
|
||||
# 纯客户端转型设计规格
|
||||
|
||||
> 日期: 2026-04-27
|
||||
> 状态: 已批准
|
||||
> 作者: Zhang Xiang
|
||||
|
||||
## 1. 概述
|
||||
|
||||
将 Everything Is Suitable 从 C/S 架构(UniApp + Java Spring Boot + PostgreSQL)转型为纯客户端 App,通过 App Store、Google Play、华为/OPPO/小米等应用商店进行买断制付费分发,完全移除服务端。
|
||||
|
||||
产品定位:**中国传统文化研究工具**。
|
||||
|
||||
## 2. 决策记录
|
||||
|
||||
| 决策项 | 选择 | 理由 |
|
||||
|-------|------|------|
|
||||
| 架构方案 | UniApp 继续演进 | 复用现有 UI,跨平台覆盖最广,风险最低 |
|
||||
| 目标平台 | iOS + Android (Google Play) + 国内安卓商店 | 最大化覆盖面 |
|
||||
| 付费模式 | 买断制付费下载 | 纯客户端最简变现方式 |
|
||||
| 功能范围 | 第一版包含全部核心功能 | 黄历+紫微+运势全部移植 |
|
||||
| 后端处理 | 完全删除 | 不再需要服务端 |
|
||||
| 数据存储 | 纯本地存储 + 可选 iCloud 同步 | 无服务端,数据在设备本地 |
|
||||
| CI/CD | Jenkins | 团队现有基础设施 |
|
||||
|
||||
## 3. 整体架构
|
||||
|
||||
### 3.1 转型后架构
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────┐
|
||||
│ 纯客户端 App (UniApp) │
|
||||
│ │
|
||||
│ ┌──────────────────────────────────────────────┐ │
|
||||
│ │ 表现层 (Pages / Components) │ │
|
||||
│ │ 黄历查询页 | 紫微排盘页 | 运势分析页 | 搜索页 │ │
|
||||
│ └───────────────────┬──────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────▼──────────────────────────┐ │
|
||||
│ │ 服务层 (Local Services) │ │
|
||||
│ │ AlmanacService | ZiweiService | FortuneService│ │
|
||||
│ │ SearchService | TemplateService │ │
|
||||
│ └───────────────────┬──────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────▼──────────────────────────┐ │
|
||||
│ │ 算法层 (Core Algorithms) │ │
|
||||
│ │ lunar.ts | almanac.ts | ziwei.ts | fortune.ts│ │
|
||||
│ │ sanFangSiZheng.ts | heavenlyStems.ts │ │
|
||||
│ └───────────────────┬──────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ┌───────────────────▼──────────────────────────┐ │
|
||||
│ │ 基础设施层 (Infrastructure) │ │
|
||||
│ │ LRUCache | PerformanceMonitor | Storage │ │
|
||||
│ │ ExportImport | CloudSync(iCloud/GDrive) │ │
|
||||
│ └──────────────────────────────────────────────┘ │
|
||||
└─────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 3.2 核心模块映射 (Java → TypeScript)
|
||||
|
||||
| Java 模块 | TypeScript 目标 | 关键类/方法 |
|
||||
|-----------|----------------|------------|
|
||||
| `AlmanacServiceImpl` | `almanac.ts` | getAlmanacByDate, getAlmanacsByRange |
|
||||
| `AlmanacSearchHandler` | `searchService.ts` (重写) | search, searchByKeyword |
|
||||
| `ZiweiChartServiceImpl` | `ziwei.ts` | generateChart, getPalaceInfo |
|
||||
| `ZiweiAlgorithmUtil` (1025行) | `ziweiAlgorithm.ts` | 排盘核心算法 |
|
||||
| `SanFangSiZhengUtil` (249行) | `sanFangSiZheng.ts` | 三方四正计算 |
|
||||
| `FortuneAnalysisServiceImpl` | `fortune.ts` | daily/monthly/yearly/overall |
|
||||
| `DailyFortuneStrategy` (229行) | `fortuneStrategy.ts` | 日运策略 |
|
||||
| `MonthlyFortuneStrategy` (404行) | `fortuneStrategy.ts` | 月运策略 |
|
||||
| `LunarCalendarServiceImpl` | 已有 `lunar.ts` | 无需移植 |
|
||||
| `CalendarServiceImpl` | `calendar.ts` | 日历相关 |
|
||||
|
||||
### 3.3 转型后目录结构
|
||||
|
||||
```
|
||||
everything-is-suitable/
|
||||
├── everything-is-suitable-uniapp/ # 唯一保留的项目
|
||||
│ ├── src/
|
||||
│ │ ├── algorithms/ # 新增:核心算法层
|
||||
│ │ │ ├── almanac.ts
|
||||
│ │ │ ├── ziwei.ts
|
||||
│ │ │ ├── ziweiAlgorithm.ts
|
||||
│ │ │ ├── sanFangSiZheng.ts
|
||||
│ │ │ ├── fortune.ts
|
||||
│ │ │ ├── fortuneStrategy.ts
|
||||
│ │ │ ├── calendar.ts
|
||||
│ │ │ └── types.ts # 算法层共享类型
|
||||
│ │ ├── services/ # 重写:本地服务层
|
||||
│ │ │ ├── almanacService.ts
|
||||
│ │ │ ├── ziweiService.ts
|
||||
│ │ │ ├── fortuneService.ts
|
||||
│ │ │ ├── searchService.ts
|
||||
│ │ │ └── templateService.ts
|
||||
│ │ ├── utils/ # 保留+增强
|
||||
│ │ │ ├── lunar.ts # 已有
|
||||
│ │ │ ├── lruCache.ts # 已有
|
||||
│ │ │ ├── searchOptimizer.ts # 已有
|
||||
│ │ │ ├── performanceMonitor.ts # 已有
|
||||
│ │ │ ├── storage.ts # 新增:统一本地存储
|
||||
│ │ │ ├── exportImport.ts # 新增:数据导出导入
|
||||
│ │ │ └── errorHandler.ts # 已有
|
||||
│ │ ├── components/ # 保留
|
||||
│ │ ├── pages/ # 保留+新增
|
||||
│ │ │ ├── almanac-search/ # 已有
|
||||
│ │ │ ├── ziwei/ # 新增:紫微排盘页
|
||||
│ │ │ └── fortune/ # 新增:运势分析页
|
||||
│ │ └── types/ # 保留+扩展
|
||||
│ ├── package.json
|
||||
│ ├── Jenkinsfile # 新增:Jenkins CI
|
||||
│ └── ...
|
||||
└── (其他目录全部删除)
|
||||
```
|
||||
|
||||
## 4. 核心算法移植策略
|
||||
|
||||
### 4.1 移植原则
|
||||
|
||||
1. **算法逻辑 1:1 移植**:不重构算法,保持与 Java 代码逻辑一致,便于交叉验证
|
||||
2. **类型先行**:先移植枚举和领域模型,再移植算法
|
||||
3. **测试驱动**:每个算法移植后,用 Java 端的现有测试用例做交叉验证
|
||||
|
||||
### 4.2 移植分层顺序
|
||||
|
||||
**Step 1: 枚举与常量 (Enums)**
|
||||
- HeavenlyStem (天干)
|
||||
- EarthlyBranch (地支)
|
||||
- MajorStar (主星)
|
||||
- PalaceType (宫位类型)
|
||||
- StarNature (星性)
|
||||
- TransformationType (四化类型)
|
||||
- FortuneType (运势类型)
|
||||
- StarBrightness (星曜亮度)
|
||||
|
||||
**Step 2: 领域模型 (Domain Models)**
|
||||
- BirthInfo (出生信息)
|
||||
- ZiweiChart (命盘)
|
||||
- Palace (宫位)
|
||||
- StarInfo (星曜信息)
|
||||
- DailyFortune (日运)
|
||||
- MonthlyFortune (月运)
|
||||
- Almanac (黄历)
|
||||
- LunarDate (农历日期 - 已有)
|
||||
|
||||
**Step 3: 核心算法 (Algorithms)**
|
||||
- ZiweiAlgorithmUtil → ziweiAlgorithm.ts (排盘核心)
|
||||
- SanFangSiZhengUtil → sanFangSiZheng.ts (三方四正)
|
||||
- FortuneStrategy → fortuneStrategy.ts (运势策略)
|
||||
- AlmanacService → almanac.ts (黄历计算)
|
||||
|
||||
**Step 4: 服务层 (Services)**
|
||||
- ZiweiChartService → ziweiService.ts
|
||||
- FortuneAnalysisService → fortuneService.ts
|
||||
- AlmanacService → almanacService.ts
|
||||
- SearchService → searchService.ts (重写为本地搜索)
|
||||
|
||||
### 4.3 Java → TypeScript 关键差异处理
|
||||
|
||||
| Java 特性 | TypeScript 对应 | 注意事项 |
|
||||
|-----------|----------------|---------|
|
||||
| `int` 除法自动截断 | `Math.floor()` | 必须显式处理 |
|
||||
| `enum` | `enum` + 辅助方法 | fromIndex/fromName 等 |
|
||||
| `List<T>` | `T[]` | 数组操作 |
|
||||
| `Map<K,V>` | `Map<K,V>` | 保持一致 |
|
||||
| Caffeine Cache | LRUCache (已有) | 已有实现 |
|
||||
| `Optional<T>` | `T \| null` | 空值处理 |
|
||||
| `record` | `interface` | 不可变用 readonly |
|
||||
| `switch` 表达式 | `switch` 语句 | 无表达式形式 |
|
||||
|
||||
### 4.4 交叉验证策略
|
||||
|
||||
每个算法移植后,使用 Java 端现有测试用例生成黄金数据集:
|
||||
|
||||
1. 从 Java 测试用例中提取输入/输出对
|
||||
2. 在 TypeScript 中用相同输入执行
|
||||
3. 比对输出,允许浮点误差 < 0.001
|
||||
4. 100% 通过才算移植成功
|
||||
|
||||
## 5. 后端依赖移除与本地服务替换
|
||||
|
||||
### 5.1 需要删除的目录和文件
|
||||
|
||||
| 目标 | 处理方式 |
|
||||
|------|---------|
|
||||
| `everything-is-suitable-api/` | 整个目录删除 |
|
||||
| `everything-is-suitable-admin/` | 整个目录删除 |
|
||||
| `everything-is-suitable-test/` | 整个目录删除 |
|
||||
| `docker-compose.yml` | 删除 |
|
||||
| `docker-compose.*.yml` | 删除 |
|
||||
| `Dockerfile*` | 删除 |
|
||||
| `.woodpecker.yml` | 删除,替换为 Jenkinsfile |
|
||||
| `DEPLOYMENT.md` | 删除 |
|
||||
| `WOODPECKER_CI.md` | 删除 |
|
||||
| `STARTUP_GUIDE.md` | 删除 |
|
||||
| `config/` (根目录) | 删除 |
|
||||
|
||||
### 5.2 需要从 UniApp 中移除的文件
|
||||
|
||||
| 文件 | 替代方案 |
|
||||
|------|---------|
|
||||
| `src/utils/httpClient.ts` | 删除,本地服务直接调用 |
|
||||
| `src/utils/tokenManager.ts` | 删除,无需认证 |
|
||||
| `src/types/api.ts` | 删除,无远程 API |
|
||||
| `config/` (baseURL 等) | 删除,无远程端点 |
|
||||
|
||||
### 5.3 本地服务替换映射
|
||||
|
||||
| 远程 API 调用 | 本地服务调用 |
|
||||
|--------------|------------|
|
||||
| `httpClient.get('/almanac/{date}')` | `almanacService.getByDate(date)` |
|
||||
| `httpClient.get('/almanac/range')` | `almanacService.getByRange(start, end)` |
|
||||
| `httpClient.post('/almanac/search')` | `searchService.search(request)` |
|
||||
| `httpClient.post('/fortune/daily')` | `fortuneService.getDaily(birthInfo, date)` |
|
||||
| `httpClient.post('/fortune/monthly')` | `fortuneService.getMonthly(birthInfo, month)` |
|
||||
| `httpClient.post('/fortune/yearly')` | `fortuneService.getYearly(birthInfo, year)` |
|
||||
| `httpClient.post('/fortune/overall')` | `fortuneService.getOverall(birthInfo)` |
|
||||
| `httpClient.post('/ziwei/chart')` | `ziweiService.generateChart(birthInfo)` |
|
||||
|
||||
### 5.4 统一本地存储层
|
||||
|
||||
新增 `utils/storage.ts`,封装 `uni.storage`:
|
||||
|
||||
- `get<T>(key: string): T | null`
|
||||
- `set<T>(key: string, value: T): void`
|
||||
- `remove(key: string): void`
|
||||
- `clear(): void`
|
||||
- `enableCloudSync(): void` (后续版本:iCloud/Google Drive)
|
||||
- `syncToCloud(): Promise<void>` (后续版本)
|
||||
- `syncFromCloud(): Promise<void>` (后续版本)
|
||||
|
||||
第一版仅实现纯本地存储,云同步功能在后续版本中添加。
|
||||
|
||||
## 6. 付费分发与商店适配
|
||||
|
||||
### 6.1 付费模式
|
||||
|
||||
买断制付费下载,一次性购买永久使用。
|
||||
|
||||
| 平台 | 实现方式 | 费用 |
|
||||
|------|---------|------|
|
||||
| App Store | Paid Application | Apple Developer $99/年 |
|
||||
| Google Play | Paid App | Google Play Developer $25 一次性 |
|
||||
| 华为应用市场 | 付费下载 | 华为开发者账号 |
|
||||
| OPPO/小米 | 付费下载 | 各自开发者账号 |
|
||||
|
||||
### 6.2 内容合规:传统文化定位策略
|
||||
|
||||
所有文案和 UI 必须遵循"传统文化研究工具"定位。
|
||||
|
||||
**禁用词替换表:**
|
||||
|
||||
| 禁用词 | 替代词 |
|
||||
|-------|-------|
|
||||
| 算命 | 命理研究 |
|
||||
| 预测 | 参考分析 |
|
||||
| 占卜 | 传统卜筮文化研究 |
|
||||
| 运势 | 时令参考 |
|
||||
| 吉凶 | 传统宜忌参考 |
|
||||
| 风水 | 传统堪舆文化 |
|
||||
|
||||
**App 描述模板:**
|
||||
|
||||
> 本应用是一款中国传统文化研究工具,基于传统历法学、紫微斗数学等传统文化体系,提供黄历查询、命盘排布、时令参考等功能。所有内容仅供传统文化学术研究参考,不构成任何决策建议。
|
||||
|
||||
### 6.3 各平台审核要点
|
||||
|
||||
| 平台 | 关键审核点 | 应对策略 |
|
||||
|------|-----------|---------|
|
||||
| App Store | 2.5.2 功能完整 | 确保离线可用、无空白页 |
|
||||
| App Store | 命理类需标注"娱乐" | 描述中标注"传统文化研究,仅供学术参考" |
|
||||
| Google Play | 无特殊命理限制 | 正常提交 |
|
||||
| 华为 | 对"迷信"内容敏感 | 强调"传统文化""学术研究"定位 |
|
||||
| OPPO/小米 | 类似华为 | 同上 + 提供免责声明 |
|
||||
|
||||
## 7. 测试策略与质量保障
|
||||
|
||||
### 7.1 分层测试策略
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────┐
|
||||
│ E2E 测试 (Playwright) │ 关键用户流程
|
||||
├─────────────────────────────────────┤
|
||||
│ 集成测试 (Vitest) │ 服务层 + 算法层联动
|
||||
├─────────────────────────────────────┤
|
||||
│ 单元测试 (Vitest) │ 算法正确性
|
||||
├─────────────────────────────────────┤
|
||||
│ 交叉验证测试 (Vitest) │ Java vs TS 结果比对
|
||||
└─────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 7.2 交叉验证测试
|
||||
|
||||
从 Java 端测试用例中提取黄金数据,确保 TypeScript 移植结果与 Java 完全一致。
|
||||
|
||||
测试用例来源:
|
||||
- `ZiweiAlgorithmUtilTest.java` (494行)
|
||||
- `ComprehensiveAlmanacServiceTest.java`
|
||||
- `DailyFortuneTest.java` (334行)
|
||||
- `AlmanacSearchHandlerTest.java` (490行)
|
||||
|
||||
### 7.3 质量门禁
|
||||
|
||||
| 指标 | 标准 |
|
||||
|------|------|
|
||||
| 算法层单元测试覆盖率 | >= 90% |
|
||||
| 服务层单元测试覆盖率 | >= 80% |
|
||||
| 交叉验证通过率 | 100% |
|
||||
| E2E 关键路径通过率 | 100% |
|
||||
| Lint 错误 | 0 |
|
||||
| TypeScript 严格模式 | 开启 |
|
||||
|
||||
## 8. CI/CD (Jenkins)
|
||||
|
||||
```groovy
|
||||
pipeline {
|
||||
agent any
|
||||
environment {
|
||||
NODE_VERSION = '20'
|
||||
PROJECT_DIR = 'everything-is-suitable-uniapp'
|
||||
}
|
||||
stages {
|
||||
stage('Install') {
|
||||
steps {
|
||||
dir(env.PROJECT_DIR) { sh 'npm ci' }
|
||||
}
|
||||
}
|
||||
stage('Lint') {
|
||||
steps {
|
||||
dir(env.PROJECT_DIR) { sh 'npm run lint' }
|
||||
}
|
||||
}
|
||||
stage('Unit Test') {
|
||||
steps {
|
||||
dir(env.PROJECT_DIR) { sh 'npm run test' }
|
||||
}
|
||||
post {
|
||||
always { junit "${env.PROJECT_DIR}/test-results/*.xml" }
|
||||
}
|
||||
}
|
||||
stage('Build H5') {
|
||||
steps {
|
||||
dir(env.PROJECT_DIR) { sh 'npm run build:h5' }
|
||||
}
|
||||
}
|
||||
stage('Build Android') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
dir(env.PROJECT_DIR) { sh 'npm run build:app-android' }
|
||||
}
|
||||
}
|
||||
stage('Build iOS') {
|
||||
when { branch 'main' }
|
||||
steps {
|
||||
dir(env.PROJECT_DIR) { sh 'npm run build:app-ios' }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 9. ICP 备案说明
|
||||
|
||||
纯客户端 App(无后端服务)不需要 ICP 备案。这不是"绕过",而是法律上的"不适用"——ICP 备案规制的是"互联网信息服务提供者",纯客户端 App 没有服务端,不构成信息服务提供者。
|
||||
|
||||
国内应用商店(华为/OPPO/小米)可能要求声明"本应用为纯客户端应用,无后端服务,不涉及互联网信息服务"。
|
||||
|
||||
## 10. 风险与缓解
|
||||
|
||||
| 风险 | 影响 | 缓解措施 |
|
||||
|------|------|---------|
|
||||
| 算法移植正确性 | 高 | 交叉验证测试 + 黄金数据集 |
|
||||
| 命理类内容审核 | 高 | 传统文化定位 + 合规文案 |
|
||||
| App 体积过大 | 中 | 按需加载 + 数据压缩 |
|
||||
| 算法性能瓶颈 | 低 | Web Worker 隔离 + LRUCache |
|
||||
| 越狱盗版 | 低 | 可接受风险,商店内购保护 |
|
||||
@@ -0,0 +1,310 @@
|
||||
# UniApp 主应用国际化(i18n)设计规格
|
||||
|
||||
## 概述
|
||||
|
||||
为 `everything-is-suitable-uniapp` 引入 vue-i18n 国际化体系,支持 9 种语言,与落地页语言覆盖对齐。领域术语(天干地支、星曜名、宫位名等)保留中文原词,仅翻译 UI 文本。
|
||||
|
||||
## 决策记录
|
||||
|
||||
| 决策项 | 选择 | 理由 |
|
||||
|--------|------|------|
|
||||
| 语言范围 | 9 种(zh-CN, zh-TW, en, ja, ko, de, fr, es, pt) | 与落地页对齐 |
|
||||
| 领域术语策略 | 保留中文原词 | 命理术语缺乏行业标准翻译,多数命理 App 的做法 |
|
||||
| i18n 库 | vue-i18n | Vue 生态最成熟,功能完善 |
|
||||
| 架构方案 | 集中式翻译文件(方案 A) | 项目规模适中,集中式便于审查覆盖率 |
|
||||
| 语言切换 | 跟随系统语言,不提供 App 内切换 UI | 与落地页行为一致 |
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
everything-is-suitable-uniapp/src/
|
||||
├── locales/
|
||||
│ ├── index.ts # vue-i18n 实例创建、语言检测/切换/持久化
|
||||
│ ├── zh-CN.ts # 简体中文(主翻译源)
|
||||
│ ├── zh-TW.ts # 繁體中文
|
||||
│ ├── en.ts # English
|
||||
│ ├── ja.ts # 日本語
|
||||
│ ├── ko.ts # 한국어
|
||||
│ ├── de.ts # Deutsch
|
||||
│ ├── fr.ts # Français
|
||||
│ ├── es.ts # Español
|
||||
│ └── pt.ts # Português
|
||||
├── main.ts # 挂载 i18n 实例
|
||||
└── ...
|
||||
```
|
||||
|
||||
## locales/index.ts 核心职责
|
||||
|
||||
1. 创建 vue-i18n 实例,注入所有 9 种语言的翻译
|
||||
2. 语言检测优先级:`uni.getStorageSync('preferred-locale')` → `uni.getSystemInfoSync().language` → 默认 `zh-CN`
|
||||
3. 暴露切换函数 `setLocale(locale)`,同步更新 `uni.setStorageSync` + vue-i18n 的 `locale`
|
||||
4. 暴露当前语言 `getLocale()`
|
||||
5. 回退机制:目标语言缺失某 key 时,回退到 `zh-CN`
|
||||
|
||||
## main.ts 改造
|
||||
|
||||
```ts
|
||||
import { createSSRApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import { i18n } from './locales'
|
||||
|
||||
export function createApp() {
|
||||
const app = createSSRApp(App)
|
||||
app.use(i18n)
|
||||
return { app }
|
||||
}
|
||||
```
|
||||
|
||||
## 翻译键命名空间
|
||||
|
||||
按功能模块划分,扁平 key 结构(与落地页 i18n.js 一致):
|
||||
|
||||
| 命名空间 | 覆盖范围 | 示例 key |
|
||||
|---------|---------|---------|
|
||||
| `nav.*` | 底部导航栏 | `nav.almanac`、`nav.ziwei`、`nav.fortune` |
|
||||
| `almanac.*` | 黄历搜索页及相关组件 | `almanac.pageTitle`、`almanac.searching` |
|
||||
| `ziwei.*` | 紫微斗数页 | `ziwei.birthInfo`、`ziwei.generating` |
|
||||
| `fortune.*` | 运势分析页 | `fortune.daily`、`fortune.monthly` |
|
||||
| `search.*` | 搜索相关组件 | `search.conditions`、`search.addCondition` |
|
||||
| `export.*` | 导出面板 | `export.title`、`export.format` |
|
||||
| `history.*` | 搜索历史 | `history.title`、`history.clear` |
|
||||
| `template.*` | 搜索模板 | `template.title`、`template.search` |
|
||||
| `common.*` | 通用文本 | `common.retry`、`common.cancel` |
|
||||
|
||||
## 领域术语策略
|
||||
|
||||
保留中文原词,不纳入翻译体系:
|
||||
|
||||
- `enums.ts` 中的 `HeavenlyStem.name()`、`EarthlyBranch.name()`、`MajorStar.name()`、`PalaceType.name()` 等保持不变
|
||||
- `SearchConditionItem` 中的黄历活动列表(`suitableActivities`、`avoidActivities`)保持中文硬编码
|
||||
- `templateService.ts` 中的模板名/描述/分类保持中文
|
||||
- 这些领域数据未来如需国际化,可作为独立增量迭代
|
||||
|
||||
## 组件改造模式
|
||||
|
||||
### 模式 1:模板中的静态文本
|
||||
|
||||
```html
|
||||
<!-- 改造前 -->
|
||||
<text class="section-title">出生信息</text>
|
||||
|
||||
<!-- 改造后 -->
|
||||
<text class="section-title">{{ $t('ziwei.birthInfo') }}</text>
|
||||
```
|
||||
|
||||
### 模式 2:动态拼接文本(插值)
|
||||
|
||||
```html
|
||||
<!-- 改造前 -->
|
||||
<Typography variant="caption">共{{ results.length }}条结果</Typography>
|
||||
|
||||
<!-- 改造后 -->
|
||||
<Typography variant="caption">{{ $t('search.resultCount', { count: results.length }) }}</Typography>
|
||||
```
|
||||
|
||||
翻译文件:
|
||||
```ts
|
||||
// zh-CN
|
||||
'search.resultCount': '共{count}条结果',
|
||||
// en
|
||||
'search.resultCount': '{count} results',
|
||||
```
|
||||
|
||||
### 模式 3:Script 中的中文文本
|
||||
|
||||
```ts
|
||||
// 改造前
|
||||
error.value = '请至少添加一个搜索条件'
|
||||
|
||||
// 改造后
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
error.value = t('search.addConditionHint')
|
||||
```
|
||||
|
||||
## pages.json 国际化
|
||||
|
||||
`navigationBarTitleText` 不支持 vue-i18n 动态翻译,改用运行时设置。`pages.json` 中保留中文初始值(作为首次渲染前的兜底),由 `onShow` 生命周期动态覆盖为当前语言文本:
|
||||
|
||||
```json
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/almanac-search/index",
|
||||
"style": { "navigationBarTitleText": "黄历搜索" }
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
各页面 `onShow` 生命周期中动态设置:
|
||||
|
||||
```ts
|
||||
import { useI18n } from 'vue-i18n'
|
||||
const { t } = useI18n()
|
||||
|
||||
onShow(() => {
|
||||
uni.setNavigationBarTitle({ title: t('almanac.pageTitle') })
|
||||
})
|
||||
```
|
||||
|
||||
## EmptyState 组件默认值处理
|
||||
|
||||
移除中文默认值,由调用方显式传入翻译文本:
|
||||
|
||||
```ts
|
||||
// 改造前
|
||||
withDefaults(defineProps<Props>(), {
|
||||
title: '暂无数据',
|
||||
description: '没有找到相关结果',
|
||||
actionText: '重新搜索',
|
||||
})
|
||||
|
||||
// 改造后
|
||||
withDefaults(defineProps<Props>(), {
|
||||
icon: 'empty',
|
||||
showAction: true,
|
||||
size: 'medium'
|
||||
})
|
||||
```
|
||||
|
||||
调用方:
|
||||
```html
|
||||
<EmptyState
|
||||
:title="$t('common.noData')"
|
||||
:description="$t('common.noResult')"
|
||||
:actionText="$t('common.retry')"
|
||||
:showAction="hasSearched"
|
||||
@action="performSearch"
|
||||
/>
|
||||
```
|
||||
|
||||
## 翻译键全量清单(约 80 条)
|
||||
|
||||
```
|
||||
common.retry = 重试
|
||||
common.cancel = 取消
|
||||
common.confirm = 确认
|
||||
common.loading = 加载中...
|
||||
common.noData = 暂无数据
|
||||
common.noResult = 没有找到相关结果
|
||||
common.search = 搜索
|
||||
common.male = 男
|
||||
common.female = 女
|
||||
|
||||
nav.almanac = 黄历
|
||||
nav.ziwei = 紫微
|
||||
nav.fortune = 运势
|
||||
|
||||
almanac.pageTitle = 黄历搜索
|
||||
almanac.searching = 搜索中...
|
||||
almanac.searchFailed = 搜索失败,请稍后重试
|
||||
almanac.noResult = 没有找到符合条件的结果
|
||||
almanac.keywordHint = 请输入搜索关键词
|
||||
|
||||
ziwei.pageTitle = 紫微斗数
|
||||
ziwei.birthInfo = 出生信息
|
||||
ziwei.birthDate = 出生日期
|
||||
ziwei.birthHour = 出生时辰
|
||||
ziwei.gender = 性别
|
||||
ziwei.pleaseSelect = 请选择
|
||||
ziwei.generating = 排盘中...
|
||||
ziwei.generate = 排盘
|
||||
ziwei.chartTitle = 紫微斗数盘
|
||||
ziwei.sanFangAnalysis = 三方四正分析
|
||||
ziwei.sanFangScore = 三方得分
|
||||
ziwei.siZhengScore = 四正得分
|
||||
ziwei.overallEval = 综合评价
|
||||
ziwei.summary = 盘面概述
|
||||
ziwei.scoreUnit = 分
|
||||
|
||||
fortune.pageTitle = 运势分析
|
||||
fortune.daily = 日运
|
||||
fortune.monthly = 月运
|
||||
fortune.selectDate = 选择日期
|
||||
fortune.selectMonth = 选择月份
|
||||
fortune.overallFortune = 综合运势
|
||||
fortune.career = 事业
|
||||
fortune.wealth = 财运
|
||||
fortune.relationship = 感情
|
||||
fortune.health = 健康
|
||||
fortune.luckyColor = 幸运色
|
||||
fortune.luckyNumber = 幸运数字
|
||||
fortune.luckyDirection = 幸运方位
|
||||
fortune.noChart = 请先在紫微斗数页面完成排盘
|
||||
|
||||
search.conditions = 搜索条件
|
||||
search.addCondition = 添加条件
|
||||
search.addConditionHint = 请至少添加一个搜索条件
|
||||
search.addConditionEmpty = 请添加搜索条件
|
||||
search.days = 搜索天数
|
||||
search.dayUnit = 天
|
||||
search.searchResult = 搜索结果
|
||||
search.resultCount = 共{count}条结果
|
||||
search.matchCount = 匹配度: {count}
|
||||
search.sort = 排序
|
||||
search.sortByDate = 日期
|
||||
search.sortByMatch = 匹配度
|
||||
search.typeSuitable = 宜
|
||||
search.typeUnsuitable = 忌
|
||||
search.operatorAnd = 与(AND)
|
||||
search.operatorOr = 或(OR)
|
||||
search.excludeCondition = 排除条件
|
||||
search.items = 事项
|
||||
search.operator = 逻辑运算符
|
||||
|
||||
template.title = 搜索模板
|
||||
template.searchPlaceholder= 搜索模板
|
||||
template.empty = 暂无模板
|
||||
template.emptyDesc = 没有找到符合条件的模板
|
||||
template.all = 全部
|
||||
|
||||
export.title = 导出搜索结果
|
||||
export.selectFormat = 选择导出格式
|
||||
export.selectContent = 选择导出内容
|
||||
export.date = 日期
|
||||
export.lunarDate = 农历日期
|
||||
export.weekday = 星期
|
||||
export.matchedItems = 匹配事项
|
||||
export.matchCount = 匹配度
|
||||
|
||||
history.title = 搜索历史
|
||||
history.clear = 清除历史
|
||||
history.clearConfirm = 确认清除
|
||||
history.clearConfirmMsg = 确定要清除所有搜索历史吗?
|
||||
history.empty = 暂无搜索历史
|
||||
history.emptyDesc = 执行搜索后,搜索条件将显示在这里
|
||||
history.justNow = 刚刚
|
||||
history.hoursAgo = {count}小时前
|
||||
history.daysAgo = {count}天前
|
||||
```
|
||||
|
||||
## 测试策略
|
||||
|
||||
### 1. 单元测试 — 翻译完整性校验
|
||||
|
||||
新增 `locales/__tests__/completeness.test.ts`:
|
||||
- 校验所有 8 种非中文语言的翻译文件,key 集合必须与 `zh-CN` 相等
|
||||
- 发现缺失 key 时测试失败,输出具体缺失的 key 列表
|
||||
|
||||
### 2. 单元测试 — 插值格式校验
|
||||
|
||||
- 校验所有使用插值(`{count}` 等)的 key,在每种语言中插值占位符名称一致
|
||||
|
||||
### 3. 组件测试 — 翻译渲染验证
|
||||
|
||||
对关键组件(BottomNavigation、SearchConditionPanel、EmptyState)编写测试:
|
||||
- 切换 locale 后,验证渲染文本对应正确语言
|
||||
- 验证插值参数正确替换
|
||||
|
||||
### 4. E2E 测试 — 语言切换端到端验证
|
||||
|
||||
- 在 H5 模式下模拟不同 `navigator.language`,验证页面标题和关键文本正确切换
|
||||
- 验证 `preferred-locale` 持久化后重启仍生效
|
||||
|
||||
## 不在范围内
|
||||
|
||||
- 领域术语的国际化(天干地支、星曜名、宫位名、黄历活动名)
|
||||
- templateService 中模板名/描述/分类的国际化
|
||||
- App 内语言切换 UI
|
||||
- 落地页 i18n.js 的改动(已独立支持 9 种语言)
|
||||
Reference in New Issue
Block a user