171 lines
5.8 KiB
Python
171 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Convert game data JSON files to i18n-ready format.
|
|
Transforms plain text fields to inline translation objects.
|
|
|
|
Usage: python convert_to_i18n.py
|
|
"""
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
GAMEDATA_DIR = Path(__file__).parent.parent / 'gamedata'
|
|
|
|
# Fields that should be translated
|
|
TRANSLATABLE_FIELDS = ['name', 'description']
|
|
|
|
# Nested text fields in outcomes
|
|
OUTCOME_TEXT_FIELDS = ['success', 'failure', 'crit_success', 'crit_failure']
|
|
|
|
|
|
def convert_text_to_i18n(value: str) -> dict:
|
|
"""Convert a plain string to i18n format"""
|
|
if not value or not isinstance(value, str):
|
|
return value
|
|
return {
|
|
"en": value,
|
|
"es": "" # Empty - to be translated
|
|
}
|
|
|
|
|
|
def convert_item(item_id: str, item: dict) -> dict:
|
|
"""Convert an item to i18n format"""
|
|
result = {}
|
|
for key, value in item.items():
|
|
if key in TRANSLATABLE_FIELDS and isinstance(value, str):
|
|
result[key] = convert_text_to_i18n(value)
|
|
else:
|
|
result[key] = value
|
|
return result
|
|
|
|
|
|
def convert_location(location: dict) -> dict:
|
|
"""Convert a location to i18n format with nested interactable outcomes"""
|
|
result = {}
|
|
for key, value in location.items():
|
|
if key in TRANSLATABLE_FIELDS and isinstance(value, str):
|
|
result[key] = convert_text_to_i18n(value)
|
|
elif key == 'interactables' and isinstance(value, dict):
|
|
# Convert interactable outcome texts
|
|
result[key] = convert_interactables(value)
|
|
else:
|
|
result[key] = value
|
|
return result
|
|
|
|
|
|
def convert_interactables(interactables: dict) -> dict:
|
|
"""Convert interactable templates and outcomes to i18n format"""
|
|
result = {}
|
|
for inter_id, inter_data in interactables.items():
|
|
result[inter_id] = {}
|
|
for key, value in inter_data.items():
|
|
if key in TRANSLATABLE_FIELDS and isinstance(value, str):
|
|
result[inter_id][key] = convert_text_to_i18n(value)
|
|
elif key == 'actions' and isinstance(value, dict):
|
|
result[inter_id][key] = convert_actions(value)
|
|
elif key == 'outcomes' and isinstance(value, dict):
|
|
result[inter_id][key] = convert_outcomes(value)
|
|
else:
|
|
result[inter_id][key] = value
|
|
return result
|
|
|
|
|
|
def convert_actions(actions: dict) -> dict:
|
|
"""Convert action labels to i18n format"""
|
|
result = {}
|
|
for action_id, action_data in actions.items():
|
|
result[action_id] = {}
|
|
for key, value in action_data.items():
|
|
if key == 'label' and isinstance(value, str):
|
|
result[action_id][key] = convert_text_to_i18n(value)
|
|
else:
|
|
result[action_id][key] = value
|
|
return result
|
|
|
|
|
|
def convert_outcomes(outcomes: dict) -> dict:
|
|
"""Convert outcome text fields to i18n format"""
|
|
result = {}
|
|
for outcome_id, outcome_data in outcomes.items():
|
|
result[outcome_id] = {}
|
|
for key, value in outcome_data.items():
|
|
if key == 'text' and isinstance(value, dict):
|
|
result[outcome_id][key] = {}
|
|
for text_key, text_value in value.items():
|
|
if text_key in OUTCOME_TEXT_FIELDS and isinstance(text_value, str) and text_value:
|
|
result[outcome_id][key][text_key] = convert_text_to_i18n(text_value)
|
|
else:
|
|
result[outcome_id][key][text_key] = text_value
|
|
else:
|
|
result[outcome_id][key] = value
|
|
return result
|
|
|
|
|
|
def convert_npc(npc: dict) -> dict:
|
|
"""Convert an NPC to i18n format"""
|
|
result = {}
|
|
for key, value in npc.items():
|
|
if key in TRANSLATABLE_FIELDS and isinstance(value, str):
|
|
result[key] = convert_text_to_i18n(value)
|
|
else:
|
|
result[key] = value
|
|
return result
|
|
|
|
|
|
|
|
def convert_interactable_template(interactable: dict) -> dict:
|
|
"""Convert an interactable template to i18n format"""
|
|
result = {}
|
|
for key, value in interactable.items():
|
|
if key in TRANSLATABLE_FIELDS and isinstance(value, str):
|
|
result[key] = convert_text_to_i18n(value)
|
|
elif key == 'actions' and isinstance(value, dict):
|
|
result[key] = convert_actions(value)
|
|
else:
|
|
result[key] = value
|
|
return result
|
|
|
|
|
|
def convert_file(filename: str, converter, key_name: str):
|
|
"""Convert a JSON file to i18n format"""
|
|
filepath = GAMEDATA_DIR / filename
|
|
|
|
print(f"Converting {filename}...")
|
|
|
|
with open(filepath, 'r', encoding='utf-8') as f:
|
|
data = json.load(f)
|
|
|
|
if key_name in data:
|
|
if isinstance(data[key_name], dict):
|
|
# items.json format: {"items": {"item_id": {...}, ...}}
|
|
data[key_name] = {
|
|
item_id: converter(item_id, item) if key_name == 'items' else converter(item)
|
|
for item_id, item in data[key_name].items()
|
|
}
|
|
elif isinstance(data[key_name], list):
|
|
# locations.json format: {"locations": [{...}, ...]}
|
|
data[key_name] = [converter(item) for item in data[key_name]]
|
|
|
|
# Write back
|
|
output_file = GAMEDATA_DIR / f'{filename.replace(".json", "_i18n.json")}'
|
|
with open(output_file, 'w', encoding='utf-8') as f:
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
|
|
print(f" -> Saved to {output_file.name}")
|
|
|
|
|
|
def main():
|
|
print("Converting game data to i18n format...\n")
|
|
|
|
convert_file('items.json', convert_item, 'items')
|
|
convert_file('locations.json', convert_location, 'locations')
|
|
convert_file('npcs.json', convert_npc, 'npcs')
|
|
convert_file('interactables.json', convert_interactable_template, 'interactables')
|
|
|
|
print("\nDone! Review *_i18n.json files, then rename to replace originals.")
|
|
print("Spanish translations are empty - add them in the web-map editor.")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|