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>
This commit is contained in:
@@ -40,3 +40,54 @@ def load_config():
|
||||
|
||||
# 导出配置对象
|
||||
CONFIG = load_config()
|
||||
|
||||
def update_paths_for_language(lang_code: str = None):
|
||||
"""根据语言更新 game_configs 和 templates 的路径"""
|
||||
from src.classes.language import language_manager
|
||||
|
||||
if lang_code is None:
|
||||
# 尝试从配置中同步语言状态到 language_manager (针对 CLI/Test 等非 server 环境)
|
||||
if hasattr(CONFIG, "system") and hasattr(CONFIG.system, "language"):
|
||||
saved_lang = CONFIG.system.language
|
||||
|
||||
# Avoid triggering set_language -> df import loop during initialization
|
||||
try:
|
||||
from src.classes.language import LanguageType
|
||||
language_manager._current = LanguageType(saved_lang)
|
||||
except (ValueError, ImportError):
|
||||
pass
|
||||
|
||||
# Reload translations only (safe)
|
||||
from src.i18n import reload_translations
|
||||
reload_translations()
|
||||
|
||||
lang_code = saved_lang
|
||||
|
||||
if lang_code is None:
|
||||
lang_code = "zh-CN"
|
||||
|
||||
# Normalize lang_code (e.g. zh_CN -> zh-CN) to match folder structure in static/locales
|
||||
lang_code = lang_code.replace("_", "-")
|
||||
|
||||
# 默认 locales 目录
|
||||
locales_dir = CONFIG.paths.get("locales", Path("static/locales"))
|
||||
|
||||
# 构建特定语言的目录
|
||||
target_dir = locales_dir / lang_code
|
||||
|
||||
# 更新配置路径
|
||||
# 语言无关的配置目录
|
||||
CONFIG.paths.shared_game_configs = Path("static/game_configs")
|
||||
# 语言相关的配置目录
|
||||
CONFIG.paths.game_configs = target_dir / "game_configs"
|
||||
CONFIG.paths.templates = target_dir / "templates"
|
||||
|
||||
# 简单的存在性检查日志
|
||||
if not CONFIG.paths.game_configs.exists():
|
||||
print(f"[Config] Warning: Game configs dir not found at {CONFIG.paths.game_configs}")
|
||||
else:
|
||||
print(f"[Config] Switched paths to {lang_code}")
|
||||
|
||||
# 模块加载时自动初始化默认路径,确保 CONFIG.paths.game_configs 存在,避免 import 时 KeyError
|
||||
update_paths_for_language()
|
||||
|
||||
|
||||
@@ -65,13 +65,33 @@ def load_csv(path: Path) -> List[Dict[str, Any]]:
|
||||
|
||||
def load_game_configs() -> dict[str, List[Dict[str, Any]]]:
|
||||
game_configs = {}
|
||||
for path in CONFIG.paths.game_configs.glob("*.csv"):
|
||||
data = load_csv(path)
|
||||
game_configs[path.stem] = data
|
||||
|
||||
# 1. 加载共享配置 (Shared)
|
||||
if hasattr(CONFIG.paths, "shared_game_configs") and CONFIG.paths.shared_game_configs.exists():
|
||||
for path in CONFIG.paths.shared_game_configs.glob("*.csv"):
|
||||
data = load_csv(path)
|
||||
game_configs[path.stem] = data
|
||||
|
||||
# 2. 加载本地化配置 (Localized) - 会覆盖同名文件
|
||||
if hasattr(CONFIG.paths, "game_configs") and CONFIG.paths.game_configs.exists():
|
||||
for path in CONFIG.paths.game_configs.glob("*.csv"):
|
||||
data = load_csv(path)
|
||||
# 如果存在同名配置,这里会进行覆盖
|
||||
game_configs[path.stem] = data
|
||||
|
||||
return game_configs
|
||||
|
||||
game_configs = load_game_configs()
|
||||
|
||||
def reload_game_configs():
|
||||
"""重新加载所有 CSV 配置"""
|
||||
print("[DF] Reloading game configs from csv...")
|
||||
new_data = load_game_configs()
|
||||
game_configs.clear()
|
||||
game_configs.update(new_data)
|
||||
print(f"[DF] Loaded {len(game_configs)} config files.")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# 辅助函数:让业务层代码更简洁
|
||||
# =============================================================================
|
||||
|
||||
Reference in New Issue
Block a user