first commit

This commit is contained in:
jakciehan
2026-04-10 22:59:39 +08:00
commit cc2e7b9bb0
89 changed files with 23631 additions and 0 deletions
@@ -0,0 +1,260 @@
# 需求文档:UI文案国际化(i18n)
## 引言
《坦克探险》微信小游戏需要支持中英文双语UI。根据用户所在区域自动展示对应语言的文案,中文地区显示中文,其他地区显示英文。
---
## 技术方案
### 1. i18n 模块结构
`js/i18n/` 目录下创建以下文件:
- **`I18n.js`** — 核心管理器,负责语言检测和文案获取
- **`zh.js`** — 中文语言包
- **`en.js`** — 英文语言包
### 2. 语言检测
通过微信 `wx.getSystemInfoSync().language` 自动检测:
- `zh_CN``zh_TW``zh_HK` 等以 `zh` 开头 → 使用中文
- 其他 → 使用英文(默认 fallback)
### 3. 使用方式
各场景文件通过 `const { t } = require('../i18n/I18n');` 引入翻译函数:
- 简单文案:`t('menu.title')``'坦克探险'` / `'Tank Adventure'`
- 带参数模板:`t('pvp.hp', { count: 3 })``'生命 x3'` / `'HP x3'`
### 4. Key 命名规范
按场景分组,使用点号分隔:
- `menu.*` — 主菜单
- `room.*` — 双人对战房间
- `teamRoom.*` — 3v3团队房间
- `pvp.*` — 双人对战游戏
- `team.*` — 3v3团队游戏
- `pvpResult.*` — 双人对战结算
- `teamResult.*` — 3v3团队结算
- `game.*` — 经典模式
- `common.*` — 通用文案
---
## 需求
### 需求 1:创建 i18n 核心模块
**用户故事:** 作为开发者,我需要一个 i18n 模块来管理多语言文案,支持自动语言检测和带参数的文案模板。
#### 验收标准
1. 创建 `js/i18n/I18n.js`,提供 `t(key, params)` 函数
2. 创建 `js/i18n/zh.js`,包含所有中文文案
3. 创建 `js/i18n/en.js`,包含所有英文文案
4. 通过 `wx.getSystemInfoSync().language` 自动检测语言
5. 支持 `{variable}` 占位符插值
6. 缺失 key 时 fallback 到英文,仍缺失则返回 key 本身
---
### 需求 2:主菜单场景(MenuScenei18n 化
#### 验收标准
| Key | 中文 | 英文 |
|-----|------|------|
| `menu.title` | 坦克探险 | Tank Adventure |
| `menu.subtitle` | 经典坦克对战 | TANK WAR |
| `menu.classic` | 经典模式 | Classic |
| `menu.endless` | 无尽模式 | Endless |
| `menu.pvp` | 双人对战 | PVP |
| `menu.team3v3` | 3v3 对战 | 3v3 Battle |
| `menu.ranking` | 排行榜 | Ranking |
| `menu.settings` | 设置 | Settings |
---
### 需求 3:双人对战房间场景(RoomScenei18n 化
#### 验收标准
| Key | 中文 | 英文 |
|-----|------|------|
| `room.title` | 双人对战 | PVP Battle |
| `room.idleHint` | 创建房间或输入房间号加入 | Create a room or join with a code |
| `room.create` | 创建房间 | Create Room |
| `room.join` | 加入房间 | Join Room |
| `room.connecting` | 连接中{dots} | Connecting{dots} |
| `room.roomCode` | 房间号: | Room Code: |
| `room.waiting` | 等待对手加入{dots} | Waiting for opponent{dots} |
| `room.shareHint` | 将房间号分享给好友 | Share the room code with your friend |
| `room.inputCode` | 输入房间号: | Enter Room Code: |
| `room.opponentFound` | 对手已找到! | Opponent found! |
| `room.starting` | 即将开始... | Game starting... |
| `room.tapBack` | 点击任意位置返回 | Tap anywhere to go back |
| `common.back` | ← 返回 | ← Back |
| `common.joinBtn` | 加入 | Join |
| `common.cannotConnect` | 无法连接服务器 | Cannot connect to server |
| `common.connectFailed` | 连接失败 | Connection failed |
| `common.disconnected` | 与服务器断开连接 | Disconnected from server |
---
### 需求 43v3 团队房间场景(TeamRoomScenei18n 化
#### 验收标准
| Key | 中文 | 英文 |
|-----|------|------|
| `teamRoom.title` | 3v3 团队对战 | 3v3 Team Battle |
| `teamRoom.chooseMode` | 选择游戏方式 | Choose how to play |
| `teamRoom.createTeam` | 🎮 组队开黑 | 🎮 Create Team |
| `teamRoom.soloMatch` | ⚡ 快速匹配 | ⚡ Quick Match |
| `teamRoom.teamId` | 队伍:{id} | Team: {id} |
| `teamRoom.leader` | 队长 | Leader |
| `teamRoom.ready` | ✓ 已准备 | ✓ Ready |
| `teamRoom.notReady` | 未准备 | Not Ready |
| `teamRoom.emptySlot` | 空位 | Empty |
| `teamRoom.invite` | 📨 邀请好友 | 📨 Invite |
| `teamRoom.startMatch` | 🔍 开始匹配 | 🔍 Start Match |
| `teamRoom.disband` | 解散队伍 | Disband |
| `teamRoom.readyBtn` | ✓ 准备 | ✓ Ready |
| `teamRoom.cancelReady` | 取消准备 | Cancel Ready |
| `teamRoom.leaveTeam` | 退出队伍 | Leave Team |
| `teamRoom.matching` | 匹配中{dots} | Matching{dots} |
| `teamRoom.waitTime` | 已等待 {seconds} 秒 | Waited {seconds}s |
| `teamRoom.cancelMatch` | 取消匹配 | Cancel Match |
| `teamRoom.matchFound` | 对手已找到! | Match found! |
| `teamRoom.enterBattle` | 即将进入战斗... | Entering battle... |
| `teamRoom.tapBack` | 点击任意位置返回 | Tap anywhere to go back |
| `teamRoom.shareTitle` | 坦克3v3,速来开黑! | Tank 3v3, join the battle! |
| `common.kicked` | 你已被踢出队伍 | You have been kicked from the team |
---
### 需求 5:双人对战游戏场景(PvpGameScenei18n 化
#### 验收标准
| Key | 中文 | 英文 |
|-----|------|------|
| `pvp.playerLabel` | P{slot} (我方) | P{slot} (You) |
| `pvp.hp` | 生命 x{count} | HP x{count} |
| `pvp.kills` | 击杀:{count} | Kills: {count} |
| `common.paused` | 暂停 | PAUSED |
| `common.tapContinue` | 点击继续 | Tap to continue |
| `pvp.youWin` | 你赢了! | YOU WIN! |
| `pvp.draw` | 平局 | DRAW |
| `pvp.youLose` | 你输了 | YOU LOSE |
---
### 需求 63v3 团队对战游戏场景(TeamGameScenei18n 化
#### 验收标准
| Key | 中文 | 英文 |
|-----|------|------|
| `team.teamA` | A队 | Team A |
| `team.teamB` | B队 | Team B |
| `team.myTeam` | 我方:{team}队 | You: {team} Team |
| `team.killDeath` | 杀:{kills} 亡:{deaths} | K:{kills} D:{deaths} |
| `team.respawn` | {seconds}秒后重生 | Respawning in {seconds}s |
| `team.victory` | 胜利! | VICTORY! |
| `team.defeat` | 失败 | DEFEAT |
| `team.baseHpSummary` | A队:{hpA} 生命 \| B队:{hpB} 生命 | Team A: {hpA} HP \| Team B: {hpB} HP |
| `team.disconnectTitle` | ⚠ 连接断开 | ⚠ Connection Lost |
| `team.reconnecting` | 重连中{dots} ({attempts}/{max}) | Reconnecting{dots} ({attempts}/{max}) |
| `team.reconnectHint` | 请稍候,您的坦克将由AI代管 | Please wait, your tank will be controlled by AI |
---
### 需求 7:双人对战结算场景(PvpResultScenei18n 化
#### 验收标准
| Key | 中文 | 英文 |
|-----|------|------|
| `pvpResult.title` | 对战结果 | MATCH RESULT |
| `pvpResult.victory` | 🏆 胜利! | 🏆 VICTORY! |
| `pvpResult.draw` | ⚔️ 平局 | ⚔️ DRAW |
| `pvpResult.defeat` | 💀 失败 | 💀 DEFEAT |
| `pvpResult.kills` | 击杀 | Kills |
| `pvpResult.lives` | 生命 | Lives |
| `pvpResult.timeRemaining` | 剩余时间:{time} | Time remaining: {time} |
| `pvpResult.rematch` | 再来一局 | Rematch |
| `pvpResult.backMenu` | 返回菜单 | Back to Menu |
---
### 需求 83v3 团队结算场景(TeamResultScenei18n 化
#### 验收标准
| Key | 中文 | 英文 |
|-----|------|------|
| `teamResult.title` | 3v3 对战结果 | 3v3 MATCH RESULT |
| `teamResult.victory` | 🏆 胜利! | 🏆 VICTORY! |
| `teamResult.defeat` | 💀 失败 | 💀 DEFEAT |
| `teamResult.teamAHp` | A队:{hp} 生命 | Team A: {hp} HP |
| `teamResult.teamBHp` | B队:{hp} 生命 | Team B: {hp} HP |
| `teamResult.baseDestroyed` | 基地被摧毁 | Base Destroyed |
| `teamResult.disconnectedReason` | 断线 | Disconnected |
| `teamResult.teamAHeader` | A队 | Team A |
| `teamResult.teamBHeader` | B队 | Team B |
| `teamResult.myTeamSuffix` | (我方) | (You) |
| `teamResult.player` | 玩家 | Player |
| `teamResult.k` | 杀 | K |
| `teamResult.d` | 亡 | D |
| `teamResult.a` | 助 | A |
| `teamResult.dmg` | 伤害 | DMG |
| `teamResult.bot` | 🤖 机器人 | 🤖 Bot |
| `teamResult.duration` | 对战时长:{time} | Match duration: {time} |
| `teamResult.mvp` | ⭐ MVP{name}{kills} 击杀) | ⭐ MVP: {name} ({kills} kills) |
| `teamResult.rankUp` | 📈 积分 +{points} | 📈 Rank +{points} |
| `teamResult.mvpBonus` | MVP加成 +5 | (MVP bonus +5) |
| `teamResult.rankDown` | 📉 积分 -{points} | 📉 Rank -{points} |
| `teamResult.rematch` | 再来一局 | Rematch |
| `teamResult.backMenu` | 返回菜单 | Back to Menu |
---
### 需求 9:经典模式游戏场景(GameScenei18n 化
#### 验收标准
| Key | 中文 | 英文 |
|-----|------|------|
| `game.level` | 第 {level} 关 | Level {level} |
| `game.hp` | 生命 x{count} | HP x{count} |
| `game.fireLevel` | LV{level} | LV{level} |
| `game.enemies` | 敌人: {count} | Enemies: {count} |
| `game.score` | {score}分 | {score}pts |
| `game.gameOver` | 游戏结束 | GAME OVER |
| `game.stageClear` | 关卡通过! | STAGE CLEAR! |
---
## 边界情况与技术约束
### 边界情况
1. **中文字体渲染**Canvas 中使用 `'Arial'` 字体渲染中文时,微信小游戏环境下系统会自动 fallback 到系统中文字体,无需额外处理。
2. **文案长度变化**:中英文文案长度不同,替换后需确认UI布局不会溢出或错位。
3. **`GameScene` 中的字符串比较**`text === '游戏结束'` 改为 `text === t('game.gameOver')`,确保逻辑不受语言影响。
4. **错误消息来源**:部分错误消息可能来自服务端(如 `data.message`),本次仅替换客户端硬编码的文案。
### 技术约束
1. 所有文案替换涉及 `js/scenes/` 目录下的场景文件和新建的 `js/i18n/` 模块。
2. 替换操作不应影响游戏逻辑,仅修改展示层的字符串。
3. 不需要在设置页面增加语言切换选项,完全依赖微信系统语言自动检测。
### 成功标准
1. 中文区域用户看到全中文UI,非中文区域用户看到全英文UI。
2. 替换后游戏功能正常,无因文案修改导致的逻辑错误。
3. 文案在各场景中布局合理,无溢出或错位现象。