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:
126
tests/test_en.py
Normal file
126
tests/test_en.py
Normal file
@@ -0,0 +1,126 @@
|
||||
import pytest
|
||||
from src.classes.language import language_manager, LanguageType
|
||||
from src.classes.avatar import Avatar
|
||||
from src.classes.world import World
|
||||
from src.utils.config import CONFIG, update_paths_for_language
|
||||
from src.utils.df import reload_game_configs, game_configs
|
||||
from src.classes.essence import EssenceType
|
||||
import ast
|
||||
|
||||
def test_system_runs_in_english(dummy_avatar, base_world):
|
||||
"""
|
||||
Test that the system can run in English mode without crashing.
|
||||
"""
|
||||
# 1. Set language to English
|
||||
original_lang = language_manager.current
|
||||
try:
|
||||
language_manager.set_language("en-US")
|
||||
assert language_manager.current == LanguageType.EN_US
|
||||
|
||||
# 2. Check basic avatar properties in English context
|
||||
# Note: The dummy_avatar fixture creates an avatar.
|
||||
# We just want to ensure that accessing properties or methods doesn't crash due to missing translations.
|
||||
|
||||
assert isinstance(dummy_avatar, Avatar)
|
||||
assert dummy_avatar.world == base_world
|
||||
|
||||
# Check if we can get a description or similar that might use i18n
|
||||
# (Even if it doesn't strictly use i18n for the name, running methods is a good check)
|
||||
info = dummy_avatar.get_desc(detailed=True)
|
||||
assert info is not None
|
||||
assert len(info) > 0
|
||||
|
||||
# 3. Test retrieving some static data that depends on language
|
||||
# For example, checking if we can get a weapon or technique description
|
||||
# Ideally, we should check if the loaded static data is actually in English,
|
||||
# but for a "runs without crashing" test, accessing it is enough.
|
||||
|
||||
if dummy_avatar.weapon:
|
||||
weapon_info = dummy_avatar.weapon.get_detailed_info()
|
||||
assert weapon_info is not None
|
||||
|
||||
# 4. Attempt a simple action or logic if possible (mocked)
|
||||
# Verify no exceptions are raised during standard operations
|
||||
dummy_avatar.action_points = 100
|
||||
# Just accessing properties is a good start.
|
||||
|
||||
finally:
|
||||
# Restore original language to avoid affecting other tests if run in suite
|
||||
language_manager.set_language(original_lang.value)
|
||||
|
||||
def test_en_csv_integrity():
|
||||
"""
|
||||
Verify that all English CSV config files are valid and strictly parsable.
|
||||
Specifically checks for issues like unquoted descriptions containing commas.
|
||||
"""
|
||||
original_lang = language_manager.current
|
||||
try:
|
||||
# Switch to EN-US
|
||||
language_manager.set_language("en-US")
|
||||
update_paths_for_language("en-US")
|
||||
reload_game_configs()
|
||||
|
||||
# 1. Verify Cultivate Regions (Check column alignment)
|
||||
cultivate_data = game_configs.get("cultivate_region", [])
|
||||
assert len(cultivate_data) > 0, "No cultivate_region data loaded"
|
||||
|
||||
for row in cultivate_data:
|
||||
rid = row.get("id")
|
||||
root_type_str = row.get("root_type")
|
||||
# If CSV columns are shifted due to commas in desc, root_type will be invalid (e.g. 'cave')
|
||||
try:
|
||||
EssenceType.from_str(root_type_str)
|
||||
except ValueError as e:
|
||||
pytest.fail(f"Cultivate Region {rid}: Invalid EssenceType '{root_type_str}'. Likely CSV parsing error due to unquoted commas in description.")
|
||||
|
||||
# 2. Verify City Regions (Check sell_item_ids format)
|
||||
city_data = game_configs.get("city_region", [])
|
||||
assert len(city_data) > 0, "No city_region data loaded"
|
||||
|
||||
for row in city_data:
|
||||
rid = row.get("id")
|
||||
sell_ids_str = row.get("sell_item_ids")
|
||||
|
||||
# If shifted, this might be something else
|
||||
assert sell_ids_str is not None, f"City Region {rid}: sell_item_ids is None"
|
||||
assert isinstance(sell_ids_str, str), f"City Region {rid}: sell_item_ids should be str"
|
||||
|
||||
try:
|
||||
parsed = ast.literal_eval(sell_ids_str)
|
||||
assert isinstance(parsed, list), f"City Region {rid}: sell_item_ids should parse to list"
|
||||
except (ValueError, SyntaxError):
|
||||
pytest.fail(f"City Region {rid}: Failed to parse sell_item_ids '{sell_ids_str}'. Likely CSV parsing error.")
|
||||
|
||||
# 3. Verify Normal Regions (Check desc)
|
||||
normal_data = game_configs.get("normal_region", [])
|
||||
assert len(normal_data) > 0, "No normal_region data loaded"
|
||||
|
||||
for row in normal_data:
|
||||
rid = row.get("id")
|
||||
|
||||
# A better check is that animal_ids/plant_ids are not long text descriptions.
|
||||
animal_ids = row.get("animal_ids")
|
||||
if animal_ids and len(str(animal_ids)) > 50:
|
||||
pytest.fail(f"Normal Region {rid}: animal_ids seems too long ('{animal_ids}'). Likely CSV parsing error shifted description into this column.")
|
||||
|
||||
# 4. Verify Personas (Check condition)
|
||||
persona_data = game_configs.get("persona", [])
|
||||
assert len(persona_data) > 0, "No persona data loaded"
|
||||
|
||||
for row in persona_data:
|
||||
pid = row.get("id")
|
||||
condition = row.get("condition")
|
||||
# If CSV is shifted, condition might be part of desc or empty when it shouldn't be
|
||||
# Check for obvious syntax errors if it's not empty
|
||||
if condition:
|
||||
try:
|
||||
# Just check if it compiles, don't eval
|
||||
compile(condition, "<string>", "eval")
|
||||
except SyntaxError as e:
|
||||
pytest.fail(f"Persona {pid}: Invalid python syntax in condition '{condition}'. Likely CSV parsing error shifted description into this column. Error: {e}")
|
||||
|
||||
finally:
|
||||
# Restore language
|
||||
language_manager.set_language(original_lang.value)
|
||||
update_paths_for_language(original_lang.value)
|
||||
reload_game_configs()
|
||||
Reference in New Issue
Block a user