Files
cultivation-world-simulator/docs/i18n-avatar-usage.md
4thfever e1091fdf5a Feat/i18n (#92)
* feat: add vue-i18n

* feat: add vue-i18n

* feat: add vue-i18n

* feat: add language class

* add: en templates and configs

* add: en names

* refactor: name gender id and sect id

* feat(i18n): add gettext infrastructure for dynamic text translation (#81)

* feat(i18n): add gettext infrastructure for dynamic text translation

- Add src/i18n/ module with t() translation function
- Add .po/.mo files for zh_CN and en_US locales
- Update LanguageManager to reload translations on language change
- Add comprehensive tests (14 tests, all passing)
- Add implementation spec at docs/specs/i18n-dynamic-text.md

Phase 1 of i18n dynamic text implementation.

* feat(i18n): expand .po files with comprehensive translation entries

Add translation messages for:
- Battle result messages (fatal/non-fatal outcomes)
- Fortune event messages (item discovery, cultivation gains)
- Misfortune event messages (losses, damage, regression)
- Death reason messages
- Item exchange messages (equip, sell, discard)
- Single choice context and option labels
- Common labels (weapon, auxiliary, technique, elixir)

Both zh_CN and en_US locales updated with matching entries.

* test: add .po file integrity tests

* feat: i18n for actions

* feat: i18n for effects

* feat: i18n for gathering

* feat: i18n for classes

* feat: i18n for classes

* feat: i18n for classes

* feat: i18n for classes

* fix bugs

* fix bugs

* fix bugs

* fix bugs

* fix bugs

* fix bugs

* fix bugs

* fix bugs

* update csv

* update world info

* update prompt

* update prompt

* fix bug

* fix bug

* fix bug

* fix bug

* fix bug

* fix bug

* fix bug

* fix bug

* fix bug

* update

* update

* update

* update

* update

* update

* update

---------

Co-authored-by: Zihao Xu <xzhseh@gmail.com>
2026-01-24 13:47:23 +08:00

433 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Avatar 系统多语言使用指南
本文档说明 Avatar 系统的多语言支持实现。
## 已完成的改动
### 1. `src/classes/avatar/core.py` 重构
修改了两个方法,将硬编码的 "散修" 改为使用翻译函数:
#### **get_sect_str() 方法**
**修改前**
```python
def get_sect_str(self) -> str:
if self.sect is None:
return "散修"
# ...
```
**修改后**
```python
def get_sect_str(self) -> str:
from src.i18n import t
if self.sect is None:
return t("Rogue Cultivator")
# ...
```
#### **get_sect_rank_name() 方法**
**修改前**
```python
def get_sect_rank_name(self) -> str:
if self.sect is None or self.sect_rank is None:
return "散修"
# ...
```
**修改后**
```python
def get_sect_rank_name(self) -> str:
from src.i18n import t
if self.sect is None or self.sect_rank is None:
return t("Rogue Cultivator")
# ...
```
---
### 2. `src/classes/avatar/action_mixin.py` 重构
修改了 `get_planned_actions_str()` 方法:
**修改前**
```python
def get_planned_actions_str(self: "Avatar") -> str:
if not self.planned_actions:
return ""
# ...
```
**修改后**
```python
def get_planned_actions_str(self: "Avatar") -> str:
from src.i18n import t
if not self.planned_actions:
return t("None")
# ...
```
---
### 3. `src/classes/avatar/info_presenter.py` 重构(核心文件)
这是本次重构的核心文件,包含大量用户可见文本的国际化。
#### **3.1 默认值统一翻译**
将所有硬编码的默认值改为翻译函数调用:
```python
# "无" -> t("None")
weapon_info = avatar.weapon.get_info() if avatar.weapon else t("None")
# "未知" -> t("Unknown")
alignment_info = avatar.alignment.get_info() if avatar.alignment else t("Unknown")
# "散修" -> t("Rogue Cultivator")
sect = to_avatar.sect.name if to_avatar.sect else t("Rogue Cultivator")
# "弟子" -> t("Disciple")
sect_info["rank"] = t("Disciple")
```
#### **3.2 分隔符国际化**
```python
# 关系分隔符:中文 "" / 英文 "; "
relations_info = t("relation_separator").join(relation_lines) if relation_lines else t("None")
# 元素分隔符:中文 "、" / 英文 ", "
elements = t("element_separator").join(str(e) for e in avatar.root.elements)
# 材料分隔符:中文 "" / 英文 ", "
materials_info = t("material_separator").join([...]) if avatar.materials else t("None")
```
#### **3.3 info_dict 键名翻译**
`get_avatar_info()` 函数返回的字典,所有键名都改为翻译:
**修改前**
```python
info_dict = {
"名字": avatar.name,
"性别": str(avatar.gender),
"年龄": str(avatar.age),
"hp": str(avatar.hp),
# ... 20+ 项
}
```
**修改后**
```python
info_dict = {
t("Name"): avatar.name,
t("Gender"): str(avatar.gender),
t("Age"): str(avatar.age),
t("HP"): str(avatar.hp),
t("Spirit Stones"): magic_stone_info,
t("Relations"): relations_info,
t("Sect"): sect_info,
t("Alignment"): alignment_info,
t("Region"): region_info,
t("Spirit Root"): root_info,
t("Technique"): technique_info,
t("Realm"): cultivation_info,
t("Traits"): personas_info,
t("Materials"): materials_info,
t("Appearance"): appearance_info,
t("Weapon"): weapon_info,
t("Auxiliary"): auxiliary_info,
t("Emotion"): avatar.emotion.value,
t("Long-term Goal"): avatar.long_term_objective.content if avatar.long_term_objective else t("None"),
t("Short-term Goal"): avatar.short_term_objective if avatar.short_term_objective else t("None"),
}
if detailed:
info_dict[t("Current Effects")] = _get_effects_text(avatar)
if avatar.nickname is not None:
info_dict[t("Nickname")] = avatar.nickname.value
if avatar.spirit_animal is not None:
info_dict[t("Spirit Animal")] = spirit_animal_info
```
#### **3.4 格式化字符串翻译**
所有复杂的格式化字符串都使用占位符模式:
```python
# 武器信息(带熟练度)
weapon_info = t("{weapon_name}, Proficiency: {proficiency}%",
weapon_name=avatar.weapon.get_detailed_info(),
proficiency=f"{avatar.weapon_proficiency:.1f}") if avatar.weapon else t("None")
# 观察到的角色
observed.append(t("{name}, Realm: {realm}",
name=other.name,
realm=other.cultivation_progress.get_info()))
# 动作状态
"action_state": t("Performing {action}", action=avatar.current_action_name)
# 灵根元素描述
"desc": t("Contains elements: {elements}",
elements=t("element_separator").join(str(e) for e in avatar.root.elements))
# 角色基础描述
lines = [t("{name}{gender} {age} years old",
name=avatar.name, gender=avatar.gender, age=avatar.age)]
lines.append(t("Realm: {realm}", realm=avatar.cultivation_progress.get_info()))
lines.append(t("Identity: {identity}", identity=avatar.get_sect_str()))
```
#### **3.5 其他字段键名翻译**
`get_avatar_expanded_info()` 中:
```python
info[t("Nearby Avatars")] = observed
info[t("Major Events")] = major_list
info[t("Recent Events")] = minor_list
```
#### **3.6 复杂信息串翻译**
`get_other_avatar_info()` 函数的整个返回字符串改为使用翻译:
**修改前**
```python
return (
f"{to_avatar.name},绰号:{nickname},境界:{to_avatar.cultivation_progress.get_info()}"
f"关系:{relation},宗门:{sect},阵营:{alignment}"
f"外貌:{to_avatar.appearance.get_info()},功法:{tech},兵器:{weapon},辅助:{aux}HP{to_avatar.hp}"
)
```
**修改后**
```python
return t(
"{name}, Nickname: {nickname}, Realm: {realm}, Relation: {relation}, Sect: {sect}, Alignment: {alignment}, Appearance: {appearance}, Technique: {technique}, Weapon: {weapon}, Auxiliary: {aux}, HP: {hp}",
name=to_avatar.name,
nickname=nickname,
realm=to_avatar.cultivation_progress.get_info(),
relation=relation,
sect=sect,
alignment=alignment,
appearance=to_avatar.appearance.get_info(),
technique=tech,
weapon=weapon,
aux=aux,
hp=to_avatar.hp
)
```
---
## PO 文件新增条目
共新增约 **40+ 条翻译**
### 字段标签23 项)
- `Name` - 名字 / Name
- `Gender` - 性别 / Gender
- `Age` - 年龄 / Age
- `HP` - hp / HP
- `Spirit Stones` - 灵石 / Spirit Stones
- `Relations` - 关系 / Relations
- `Sect` - 宗门 / Sect
- `Alignment` - 阵营 / Alignment
- `Region` - 地区 / Region
- `Spirit Root` - 灵根 / Spirit Root
- `Technique` - 功法 / Technique
- `Realm` - 境界 / Realm
- `Traits` - 特质 / Traits
- `Materials` - 材料 / Materials
- `Appearance` - 外貌 / Appearance
- `Weapon` - 兵器 / Weapon
- `Auxiliary` - 辅助装备 / Auxiliary
- `Emotion` - 情绪 / Emotion
- `Long-term Goal` - 长期目标 / Long-term Goal
- `Short-term Goal` - 短期目标 / Short-term Goal
- `Current Effects` - 当前效果 / Current Effects
- `Nickname` - 绰号 / Nickname
- `Spirit Animal` - 灵兽 / Spirit Animal
### 扩展信息标签3 项)
- `Nearby Avatars` - 周围角色 / Nearby Avatars
- `Major Events` - 重大事件 / Major Events
- `Recent Events` - 短期事件 / Recent Events
### 默认值4 项)
- `None` - 无 / None
- `Unknown` - 未知 / Unknown
- `Rogue Cultivator` - 散修 / Rogue Cultivator
- `Disciple` - 弟子 / Disciple
### 分隔符3 项)
- `relation_separator` - / ;
- `element_separator` - 、/ ,
- `material_separator` - / ,
### 格式化字符串8 项)
- `{weapon_name}, Proficiency: {proficiency}%` - 武器和熟练度
- `{name}, Realm: {realm}` - 名字和境界
- `Performing {action}` - 正在执行动作
- `Contains elements: {elements}` - 包含元素
- `【{name}】 {gender} {age} years old` - 角色基础描述
- `Realm: {realm}` - 境界标签
- `Identity: {identity}` - 身份标签
- `\n--- Current Effects Detail ---` - 效果明细标题
- `No additional effects` - 无额外效果
- 复杂的 `get_other_avatar_info` 格式化字符串
---
## 使用示例
### 获取角色信息
```python
from src.classes.avatar import Avatar
# 获取基础信息(字典键名自动翻译)
info = avatar.get_avatar_info(detailed=False)
# 中文环境:{"名字": "李云", "性别": "男", ...}
# 英文环境:{"Name": "Li Yun", "Gender": "Male", ...}
# 获取详细信息
detailed_info = avatar.get_avatar_info(detailed=True)
```
### 获取角色描述文本
```python
# 获取简要描述
desc = avatar.get_avatar_desc(detailed=False)
# 中文:【李云】 男 23岁\n境界: 筑基初期\n身份: 天剑宗内门弟子
# 英文【Li Yun】 Male 23 years old\nRealm: Foundation Early\nIdentity: ...
# 获取详细描述(包含效果分析)
detailed_desc = avatar.get_avatar_desc(detailed=True)
```
### 获取宗门信息
```python
# 获取宗门显示名(含职位)
sect_str = avatar.get_sect_str()
# 中文:天剑宗内门弟子 / 散修
# 英文Heaven Sword Sect Inner Disciple / Rogue Cultivator
# 仅获取职位
rank_str = avatar.get_sect_rank_name()
# 中文:内门弟子 / 散修
# 英文Inner Disciple / Rogue Cultivator
```
### 获取计划动作
```python
# 获取计划动作列表字符串
plans_str = avatar.get_planned_actions_str()
# 中文:无 / 1. 修炼 (参数: ...) \n 2. 突破 (参数: ...)
# 英文None / 1. Cultivate (params: ...) \n 2. Breakthrough (params: ...)
```
---
## 设计决策
### ✅ 采用的方案
1. **info_dict 键名直接翻译**
- 原因:返回的字典直接用于显示,翻译键名最直接
- 方案:使用 `t("Key")` 作为字典键
- 优势:一次性解决,无需后续处理
2. **统一默认值文本**
- "无" → `t("None")`
- "未知" → `t("Unknown")`
- "散修" → `t("Rogue Cultivator")`
- "弟子" → `t("Disciple")`
- 优势:保持一致性,易于维护
3. **格式化字符串使用占位符**
- 复杂字符串拆分为带占位符的模板
- 使用 `t("{key}: {value}", key=k, value=v)` 格式
- 优势:翻译灵活,支持不同语言的语序
4. **分隔符可配置**
- 中文:顿号(、)、分号(;)、逗号(,)
- 英文:逗号(, )、分号(;
- 优势:符合各语言的标点使用习惯
---
## 测试
```python
# 切换语言
from src.classes.language import language_manager
# 测试中文
language_manager.set_language("zh-CN")
info = avatar.get_avatar_info()
print(info[t("Name")]) # 输出键名为中文的字典
# 测试英文
language_manager.set_language("en-US")
info = avatar.get_avatar_info()
print(info[t("Name")]) # 输出键名为英文的字典
```
---
## 最佳实践
1. **新增字段时同步添加翻译**
-`info_presenter.py` 添加新字段时
- 使用 `t("New Field Label")` 作为键名
- 在 PO 文件添加对应翻译
2. **保持命名规范**
- 字段名使用英文,首字母大写(如 `"Spirit Root"`
- 默认值使用简短英文(如 `"None"`, `"Unknown"`
- 分隔符使用下划线命名(如 `"relation_separator"`
3. **格式化字符串命名**
- 使用描述性占位符名称(如 `{weapon_name}`, `{proficiency}`
- 保持占位符在中英文翻译中一致
4. **测试多语言切换**
- 添加新翻译后测试切换语言是否正常显示
- 检查分隔符和格式是否符合语言习惯
---
## 已完成
- ✅ 3 个文件修改(`core.py`, `action_mixin.py`, `info_presenter.py`
- ✅ 约 40+ 条新翻译(字段标签、默认值、分隔符、格式化字符串)
- ✅ info_dict 完全国际化
- ✅ 所有用户可见文本国际化
- ✅ 统一默认值和分隔符处理
---
## 影响范围
Avatar 系统的本地化影响以下功能:
1. **角色信息展示** - `get_avatar_info()`, `get_avatar_structured_info()`
2. **角色描述生成** - `get_avatar_desc()`, `get_other_avatar_info()`
3. **扩展信息查询** - `get_avatar_expanded_info()`
4. **宗门信息显示** - `get_sect_str()`, `get_sect_rank_name()`
5. **计划动作显示** - `get_planned_actions_str()`
所有这些功能现在都完全支持多语言切换!🎉