import csv import sys import time from pathlib import Path from typing import Dict, List, Optional # Configuration PROJECT_ROOT = Path(__file__).parent.parent.parent SOURCE_DIR = PROJECT_ROOT / "static" / "game_configs" TEMPLATE_DIR = PROJECT_ROOT / "src" / "i18n" / "locales" / "templates" POT_FILE = TEMPLATE_DIR / "game_configs.pot" def ensure_dir(path: Path): if not path.exists(): path.mkdir(parents=True) def read_csv(path: Path) -> List[Dict[str, str]]: if not path.exists(): return [] with open(path, "r", encoding="utf-8") as f: reader = csv.reader(f) lines = list(reader) if len(lines) < 2: return [] headers = lines[0] if headers and headers[0].startswith('\ufeff'): headers[0] = headers[0][1:] data = [] # Skip headers and comment row # Heuristic: if row 2 looks like comments (Chinese/Types), skip it start_idx = 1 if len(lines) > 1: # Check if second row is likely a comment row (contains non-ascii or matches known structure) if any(ord(c) > 127 for c in "".join(lines[1])): start_idx = 2 for row in lines[start_idx:]: if not row: continue item = {} for i, h in enumerate(headers): if i < len(row): item[h.strip()] = row[i].strip() data.append(item) return data def escape_po_string(s: str) -> str: return s.replace('\\', '\\\\').replace('"', '\\"').replace('\n', '\\n') def generate_pot_entry(msgid: str, comment: str = "") -> str: s = "" if comment: s += f"#. {comment}\n" s += f'msgid "{escape_po_string(msgid)}"\n' s += f'msgstr ""\n\n' return s def main(): print(f"Extracting translations from {SOURCE_DIR}...") ensure_dir(TEMPLATE_DIR) entries = [] # Header header = f"""# Game Configs Translations # Generated by tools/i18n/extract_csv.py # msgid "" msgstr "" "Content-Type: text/plain; charset=UTF-8\\n" "Content-Transfer-Encoding: 8bit\\n" "Project-Id-Version: Cultivation World Simulator\\n" """ entries.append(header) count = 0 # Sort files for stable output for csv_file in sorted(SOURCE_DIR.glob("*.csv")): filename = csv_file.name # Skip name files as they are handled differently (file suffix) if "given_name" in filename or "last_name" in filename: continue data = read_csv(csv_file) for item in data: # Check for name_id name_id = item.get("name_id") if name_id: ref_text = item.get("name", "") entries.append(generate_pot_entry(name_id, f"{filename}: {ref_text}")) count += 1 # Check for desc_id desc_id = item.get("desc_id") if desc_id: ref_text = item.get("desc", "") # Truncate long descriptions in comments if len(ref_text) > 50: ref_text = ref_text[:47] + "..." entries.append(generate_pot_entry(desc_id, f"{filename}: {ref_text}")) count += 1 with open(POT_FILE, "w", encoding="utf-8") as f: f.write("".join(entries)) print(f"Extracted {count} keys to {POT_FILE}") print("Don't forget to update your .po files using msgmerge or Poedit!") if __name__ == "__main__": main()