first commit
This commit is contained in:
@@ -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:主菜单场景(MenuScene)i18n 化
|
||||
|
||||
#### 验收标准
|
||||
|
||||
| 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:双人对战房间场景(RoomScene)i18n 化
|
||||
|
||||
#### 验收标准
|
||||
|
||||
| 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 |
|
||||
|
||||
---
|
||||
|
||||
### 需求 4:3v3 团队房间场景(TeamRoomScene)i18n 化
|
||||
|
||||
#### 验收标准
|
||||
|
||||
| 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:双人对战游戏场景(PvpGameScene)i18n 化
|
||||
|
||||
#### 验收标准
|
||||
|
||||
| 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 |
|
||||
|
||||
---
|
||||
|
||||
### 需求 6:3v3 团队对战游戏场景(TeamGameScene)i18n 化
|
||||
|
||||
#### 验收标准
|
||||
|
||||
| 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:双人对战结算场景(PvpResultScene)i18n 化
|
||||
|
||||
#### 验收标准
|
||||
|
||||
| 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 |
|
||||
|
||||
---
|
||||
|
||||
### 需求 8:3v3 团队结算场景(TeamResultScene)i18n 化
|
||||
|
||||
#### 验收标准
|
||||
|
||||
| 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:经典模式游戏场景(GameScene)i18n 化
|
||||
|
||||
#### 验收标准
|
||||
|
||||
| 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. 文案在各场景中布局合理,无溢出或错位现象。
|
||||
@@ -0,0 +1,75 @@
|
||||
# 实施计划:UI英文文案统一替换为中文
|
||||
|
||||
- [ ] 1. MenuScene 主菜单英文文案中文化
|
||||
- 将副标题 `'TANK WAR'` 替换为 `'经典坦克对战'`
|
||||
- 检查替换后文本居中是否正常,必要时调整绘制坐标
|
||||
- _需求:1.1_
|
||||
|
||||
- [ ] 2. RoomScene 双人对战房间英文文案中文化
|
||||
- 替换空闲状态提示 `'Create a room or join with a code'` → `'创建房间或输入房间号加入'`
|
||||
- 替换连接状态 `'Connecting...'` → `'连接中...'`
|
||||
- 替换等待状态 `'Room Code:'` → `'房间号:'`、`'Waiting for opponent...'` → `'等待对手加入...'`、`'Share the room code with your friend'` → `'将房间号分享给好友'`
|
||||
- 替换输入状态 `'Enter Room Code:'` → `'输入房间号:'`
|
||||
- 替换倒计时状态 `'Opponent found!'` → `'对手已找到!'`、`'Game starting...'` → `'即将开始...'`
|
||||
- 替换错误状态 `'Tap anywhere to go back'` → `'点击任意位置返回'`
|
||||
- 替换错误消息 `'Cannot connect to server'` → `'无法连接服务器'`、`'Connection failed'` → `'连接失败'`、`'Disconnected from server'` → `'与服务器断开连接'`
|
||||
- _需求:2.1 ~ 2.12_
|
||||
|
||||
- [ ] 3. TeamRoomScene 3v3团队房间英文文案中文化
|
||||
- 替换模式选择提示 `'Choose how to play'` → `'选择游戏方式'`
|
||||
- 替换队伍ID显示 `'Team: xxx'` → `'队伍:xxx'`
|
||||
- 替换错误消息 `'Cannot connect to server'` → `'无法连接服务器'`、`'You have been kicked from the team'` → `'你已被踢出队伍'`、`'Connection failed'` → `'连接失败'`、`'Disconnected from server'` → `'与服务器断开连接'`
|
||||
- _需求:3.1 ~ 3.6_
|
||||
|
||||
- [ ] 4. PvpGameScene 双人对战游戏场景英文文案中文化
|
||||
- 替换暂停覆盖层 `'PAUSED'` → `'暂停'`、`'Tap to continue'` → `'点击继续'`
|
||||
- 替换游戏结束覆盖层 `'YOU WIN!'` → `'你赢了!'`、`'DRAW'` → `'平局'`、`'YOU LOSE'` → `'你输了'`
|
||||
- 替换HUD玩家标识 `'P1 (You)'` / `'P2 (You)'` → `'P1 (我方)'` / `'P2 (我方)'`
|
||||
- 替换HUD生命值 `'HP'` → `'生命'`
|
||||
- 替换HUD击杀数 `'Kills:'` → `'击杀:'`
|
||||
- _需求:4.1 ~ 4.8_
|
||||
|
||||
- [ ] 5. TeamGameScene 3v3团队对战游戏场景英文文案中文化
|
||||
- 替换暂停覆盖层 `'PAUSED'` → `'暂停'`、`'Tap to continue'` → `'点击继续'`
|
||||
- 替换游戏结束覆盖层 `'VICTORY!'` → `'胜利!'`、`'DEFEAT'` → `'失败'`
|
||||
- 替换游戏结束基地HP显示 `'Team A: x HP | Team B: x HP'` → `'A队:x 生命 | B队:x 生命'`
|
||||
- 替换HUD队伍标签 `'Team A'` → `'A队'`、`'Team B'` → `'B队'`
|
||||
- 替换HUD玩家所属队伍 `'You: Team A'` → `'我方:A队'`
|
||||
- 替换HUD队伍统计 `'K:x D:x'` → `'杀:x 亡:x'`
|
||||
- 替换重生倒计时 `'Respawning in Xs'` → `'X秒后重生'`
|
||||
- _需求:5.1 ~ 5.9_
|
||||
|
||||
- [ ] 6. PvpResultScene 双人对战结算场景英文文案中文化
|
||||
- 替换结算标题 `'MATCH RESULT'` → `'对战结果'`
|
||||
- 替换胜负结果 `'🏆 VICTORY!'` → `'🏆 胜利!'`、`'⚔️ DRAW'` → `'⚔️ 平局'`、`'💀 DEFEAT'` → `'💀 失败'`
|
||||
- 替换玩家标识 `'P1 (You)'` / `'P2 (You)'` → `'P1 (我方)'` / `'P2 (我方)'`
|
||||
- 替换统计表头 `'Kills'` → `'击杀'`、`'Lives'` → `'生命'`
|
||||
- 替换剩余时间 `'Time remaining:'` → `'剩余时间:'`
|
||||
- _需求:6.1 ~ 6.7_
|
||||
|
||||
- [ ] 7. TeamResultScene 3v3团队结算场景英文文案中文化
|
||||
- 替换结算标题 `'3v3 MATCH RESULT'` → `'3v3 对战结果'`
|
||||
- 替换胜负结果 `'🏆 VICTORY!'` → `'🏆 胜利!'`、`'💀 DEFEAT'` → `'💀 失败'`
|
||||
- 替换基地HP `'Team A: x HP'` → `'A队:x 生命'`、`'Team B: x HP'` → `'B队:x 生命'`
|
||||
- 替换胜负原因 `'Base Destroyed'` → `'基地被摧毁'`、`'Disconnected'` → `'断线'`
|
||||
- 替换统计表头 `'Team A (You)'` / `'Team B (You)'` → `'A队 (我方)'` / `'B队 (我方)'`
|
||||
- 替换列标题 `'Player'` → `'玩家'`、`'K'` → `'杀'`、`'D'` → `'亡'`、`'A'` → `'助'`、`'DMG'` → `'伤害'`
|
||||
- 替换对战时长 `'Match duration:'` → `'对战时长:'`
|
||||
- 替换MVP信息 `'⭐ MVP: xxx (x kills)'` → `'⭐ MVP:xxx(x 击杀)'`
|
||||
- 替换段位积分 `'📈 Rank +x'` → `'📈 积分 +x'`、`'(MVP bonus +5)'` → `'(MVP加成 +5)'`、`'📉 Rank -x'` → `'📉 积分 -x'`
|
||||
- 替换Bot名称 `'Bot'` → `'机器人'`
|
||||
- _需求:7.1 ~ 7.11_
|
||||
|
||||
- [ ] 8. GameScene 经典模式游戏场景英文文案中文化
|
||||
- 替换HUD生命值 `'HP'` → `'生命'`
|
||||
- 替换游戏结束文案 `'GAME OVER'` → `'游戏结束'`、`'STAGE CLEAR'` → `'关卡通过'`(如存在)
|
||||
- **注意**:同步修改代码中 `text === 'GAME OVER'` 等字符串比较逻辑,改为 `text === '游戏结束'`
|
||||
- 火力等级 `'LV'` 为通用缩写,可保留不改
|
||||
- _需求:8.1 ~ 8.3_
|
||||
|
||||
- [ ] 9. 全局UI布局验证与字体适配
|
||||
- 检查所有场景中 Canvas 字体设置,确认中文渲染正常(如 `'Arial'` 字体对中文的支持)
|
||||
- 验证中文文案替换后各场景的文本居中、按钮宽度、布局间距是否正常
|
||||
- 对文案长度变化较大的位置(如 `'Share the room code with your friend'` → `'将房间号分享给好友'`)重点检查是否溢出
|
||||
- 确保模板字符串中的动态变量插值逻辑未被破坏
|
||||
- _需求:边界情况 1、2、3、5_
|
||||
Reference in New Issue
Block a user