初次提交
This commit is contained in:
@@ -0,0 +1,197 @@
|
||||
# 04 本地化工作流 (Localization Workflow)
|
||||
|
||||
> 项目遵循 **ADR-A1**:所有玩家可见字符串必须通过 `tr("KEY")` 包裹,禁止业务代码中出现裸字符串。
|
||||
|
||||
---
|
||||
|
||||
## 1. 文件位置
|
||||
|
||||
```
|
||||
translations/
|
||||
zh_CN.po ← 简体中文(权威主档)
|
||||
zh_TW.po ← 繁体中文
|
||||
en.po ← 英文
|
||||
ja.po ← 日文
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. `.po` 文件格式
|
||||
|
||||
每条翻译的格式为:
|
||||
|
||||
```po
|
||||
msgid "UI_WAVE"
|
||||
msgstr "第 %d 波"
|
||||
```
|
||||
|
||||
- `msgid`:代码中 `tr("KEY")` 使用的键
|
||||
- `msgstr`:该语言显示的文字
|
||||
- `%d`、`%s`、`%.1f` 等格式占位符必须与代码中 `tr("KEY") % value` 完全对应
|
||||
|
||||
---
|
||||
|
||||
## 3. 添加新翻译字符串(标准流程)
|
||||
|
||||
### Step 1 — 在代码中使用 tr() 键
|
||||
|
||||
```gdscript
|
||||
# ❌ 错误:裸字符串
|
||||
label.text = "商店已关闭"
|
||||
|
||||
# ✅ 正确:通过键引用
|
||||
label.text = tr("SHOP_CLOSED_MSG")
|
||||
|
||||
# 带参数
|
||||
label.text = tr("UI_WAVE") % current_wave # → "第 3 波"
|
||||
label.text = tr("UI_KILLS") % [kills, alive] # → "击杀: 7 存活: 3"
|
||||
```
|
||||
|
||||
### Step 2 — 在全部四个 `.po` 文件中添加对应条目
|
||||
|
||||
**zh_CN.po**(权威档,写游戏实际中文):
|
||||
```po
|
||||
msgid "SHOP_CLOSED_MSG"
|
||||
msgstr "商店已关闭"
|
||||
```
|
||||
|
||||
**zh_TW.po**(繁体,改繁体字):
|
||||
```po
|
||||
msgid "SHOP_CLOSED_MSG"
|
||||
msgstr "商店已關閉"
|
||||
```
|
||||
|
||||
**en.po**(英文):
|
||||
```po
|
||||
msgid "SHOP_CLOSED_MSG"
|
||||
msgstr "Shop Closed"
|
||||
```
|
||||
|
||||
**ja.po**(日文):
|
||||
```po
|
||||
msgid "SHOP_CLOSED_MSG"
|
||||
msgstr "ショップが閉店しました"
|
||||
```
|
||||
|
||||
### Step 3 — 验证(运行时检查)
|
||||
|
||||
在游戏内执行脚本验证无缺键:
|
||||
|
||||
```gdscript
|
||||
var keys = ["SHOP_CLOSED_MSG"] # 你新加的键
|
||||
for loc in ["zh_CN","zh_TW","en","ja"]:
|
||||
Locale.set_locale(loc)
|
||||
for k in keys:
|
||||
if tr(k) == k:
|
||||
print("缺键!语言: %s 键: %s" % [loc, k])
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 键名规范
|
||||
|
||||
**格式**:`<模块>_<实体>_<含义>`,全大写 + 下划线
|
||||
|
||||
| 前缀 | 用途 | 示例 |
|
||||
|:---|:---|:---|
|
||||
| `UI_` | 通用 HUD 标签 | `UI_WAVE`, `UI_HP` |
|
||||
| `SHOP_` | 商店界面 | `SHOP_TITLE`, `SHOP_REROLL` |
|
||||
| `INV_` | 背包界面 | `INV_TITLE`, `INV_BENCH` |
|
||||
| `SETTLE_` | 结算屏 | `SETTLE_TITLE`, `SETTLE_STATS` |
|
||||
| `SETTINGS_` | 设置面板 | `SETTINGS_DIFFICULTY` |
|
||||
| `STATUS_` | 状态消息 | `STATUS_PURCHASED` |
|
||||
| `DIFF_` | 难度名称 | `DIFF_BEGINNER`, `DIFF_CHALLENGE` |
|
||||
| `SPELL_` | 法术名/描述 | `SPELL_SPARK_BOLT_NAME`, `SPELL_SPARK_BOLT_DESC` |
|
||||
| `CORE_` | Core 名/描述 | `CORE_WAND_BASIC_NAME` |
|
||||
| `STATUS_EFFECT_` | 状态效果名 | `STATUS_EFFECT_BURN_NAME` |
|
||||
| `BOSS_` | Boss 名称 | `BOSS_FINAL_NAME` |
|
||||
|
||||
---
|
||||
|
||||
## 5. 法术 / Core 名称本地化(待完成)
|
||||
|
||||
当前法术 `display_name` 字段存储的是裸英/中文字符串(如 `"Spark Bolt"`)。正式发布前需键化。
|
||||
> **注意**:修改后须同步更新商店按钮渲染(`combat_s2.gd → _refresh_shop_ui`),将 `spell.display_name` 改为 `tr(spell.display_name)`。
|
||||
|
||||
**Step 1 — 修改 `wand_preset.gd`**
|
||||
|
||||
```gdscript
|
||||
# 当前(裸字符串)
|
||||
n.display_name = "Spark Bolt"
|
||||
n.description = "发射一颗期限 4s 的电光飞弹,造成 3 伤害。"
|
||||
|
||||
# 修改为(键)
|
||||
n.display_name = "SPELL_SPARK_BOLT_NAME"
|
||||
n.description = "SPELL_SPARK_BOLT_DESC"
|
||||
```
|
||||
|
||||
**Step 2 — 在四语 `.po` 中添加**
|
||||
|
||||
```po
|
||||
# zh_CN.po
|
||||
msgid "SPELL_SPARK_BOLT_NAME"
|
||||
msgstr "电花弹"
|
||||
|
||||
msgid "SPELL_SPARK_BOLT_DESC"
|
||||
msgstr "发射一颗快速电花飞弹,造成 3 点闪电伤害。"
|
||||
```
|
||||
|
||||
**Step 3 — 显示时包裹 tr()**
|
||||
|
||||
```gdscript
|
||||
# UI 显示法术名时
|
||||
btn.text = tr(spell.display_name)
|
||||
# 法术描述
|
||||
desc_label.text = tr(spell.description)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. 添加新语言
|
||||
|
||||
**Step 1 — 创建新 `.po` 文件**(以韩语为例)
|
||||
|
||||
```
|
||||
translations/ko.po
|
||||
```
|
||||
|
||||
内容:复制 `en.po`,将 `Language: en` 改为 `Language: ko`,翻译所有 `msgstr`。
|
||||
|
||||
**Step 2 — 在 `locale_manager.gd` 中注册**
|
||||
|
||||
```gdscript
|
||||
const LOCALES: Array = ["zh_CN", "zh_TW", "en", "ja", "ko"] # 追加 "ko"
|
||||
```
|
||||
|
||||
新语言将自动在商店语言切换按钮中循环出现。
|
||||
|
||||
---
|
||||
|
||||
## 7. 在游戏内切换语言(测试用)
|
||||
|
||||
```gdscript
|
||||
# 切换到英文
|
||||
Locale.set_locale("en")
|
||||
|
||||
# 循环切换(等同商店 🌐 按钮)
|
||||
Locale.cycle_locale()
|
||||
|
||||
# 查看当前语言
|
||||
print(Locale.get_locale())
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 提交规范
|
||||
|
||||
每次提交涉及玩家可见字符串的改动时,须**同时更新四个 `.po` 文件**。允许以英文或空字符串占位(`msgstr ""`),但 PR 审查时须标注"待翻译"。
|
||||
|
||||
---
|
||||
|
||||
## 9. 工具推荐
|
||||
|
||||
| 工具 | 用途 |
|
||||
|:---|:---|
|
||||
| [Poedit](https://poedit.net) | `.po` 文件 GUI 编辑器,支持模糊匹配和自动翻译接口 |
|
||||
| VSCode + gettext 插件 | 轻量化文本编辑 |
|
||||
| Godot 内置本地化 | `Project → Project Settings → Localization → Translations` 可预览各语言 |
|
||||
Reference in New Issue
Block a user