Add i18n, save validation, and tolerant import handling.

Prepare the UI for English (default/fallback) and German with auto or manual locale selection, and report import issues with client-translated warnings instead of failing on minor save format changes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-19 15:59:57 +02:00
parent 4b8b921e02
commit fbc2deec45
11 changed files with 1430 additions and 270 deletions
+178
View File
@@ -0,0 +1,178 @@
{
"app": {
"title": "Idle Fantasy",
"subtitle": "Save Viewer",
"loading": "Lade Save…"
},
"nav": {
"overview": "Übersicht",
"skills": "Skills",
"inventory": "Inventar",
"equipment": "Ausrüstung",
"quests": "Quests",
"combat": "Kampf",
"history": "Verlauf"
},
"settings": {
"language": "Sprache",
"langAuto": "Automatisch (Browser)",
"langEn": "English",
"langDe": "Deutsch"
},
"actions": {
"importBackup": "Backup importieren",
"compare": "Vergleichen",
"dismiss": "Schließen"
},
"empty": {
"noSave": "Kein Save importiert. Starte mit: python app.py fantasyidler_save.json",
"loadError": "Fehler beim Laden: {message}",
"unknown": "Unbekannt",
"none": "Keine",
"empty": "Leer",
"noItems": "Keine Items gefunden",
"noSnapshots": "Noch keine Snapshots. Importiere ein Backup.",
"noChanges": "Keine Änderungen",
"pickTwoSnapshots": "Wähle zwei verschiedene Snapshots."
},
"import": {
"failed": "Import fehlgeschlagen",
"duplicate": "Backup bereits vorhanden (Duplikat).",
"success": "Importiert: Snapshot #{id}",
"successWithNotes": "Importiert: Snapshot #{id}\n\n{warnings} Warnung(en), {infos} Hinweis(e) Details im Dashboard-Banner.",
"titleError": "Import-Fehler",
"titleWarning": "Import-Warnungen",
"titleInfo": "Import-Hinweise",
"countErrors": "{count} Fehler",
"countWarnings": "{count} Warnung(en)",
"countInfos": "{count} Hinweis(e)",
"newFieldsSummary": "{count} neue/unbekannte Feld(er) aus dem Spiel",
"invalid_root": "Die Datei ist kein JSON-Objekt kein gültiges Idle-Fantasy-Backup.",
"empty_save": "Die Save-Datei ist leer.",
"unknown_top_level": "Unbekanntes Feld im Backup: „{field}“ (Spiel-Update?).",
"missing_field": "Erwartetes Feld fehlt: „{field}“ zugehörige Daten werden leer angezeigt.",
"nested_json_invalid": "Feld „{field}“ konnte nicht als JSON gelesen werden Rohwert ignoriert.",
"invalid_coins": "Feld „coins“ ist nicht numerisch.",
"invalid_exported_at": "Feld „exported_at“ ist kein gültiger Zeitstempel.",
"missing_exported_at": "Kein Export-Zeitstempel Verlaufsvergleiche können ungenau sein.",
"skill_xp_mismatch": "{count} Skill(s) ohne XP-Eintrag (z. B. {examples}).",
"skill_level_mismatch": "{count} XP-Einträge ohne Skill-Level.",
"unparsed_nested_json": "Feld „{field}“ ist noch Text JSON-Inhalt konnte nicht gelesen werden.",
"invalid_type": "Feld „{field}“ hat unerwarteten Typ ({type}).",
"coerced_empty_dict": "Feld „{field}“ ist kein Objekt wird als leer behandelt.",
"coerced_empty_list": "Feld „{field}“ ist keine Liste wird übersprungen.",
"invalid_number": "Ungültiger Zahlenwert in „{field}“{detail}.",
"invalid_quest_entry": "Quest-Eintrag #{index} ist kein Objekt und wurde übersprungen.",
"invalid_session_entry": "Session-Eintrag #{index} ist kein Objekt und wurde übersprungen.",
"unparsed_session_frames": "Session #{index}: Aktivitäts-Frames konnten nicht gelesen werden.",
"invalid_pets": "Feld „pets“ ist keine Liste.",
"invalid_farming_patch": "Farming-Patch #{index} wurde übersprungen.",
"missing_character_name": "Kein Charaktername im Save gefunden.",
"invalid_quest_ids": "Quest-IDs ({label}) sind keine Liste.",
"invalid_quest_progress": "Quest-Fortschritt ({label}) ist kein Objekt."
},
"meta": {
"export": "Export",
"points": "Punkte"
},
"kpi": {
"coins": "Münzen",
"totalLevel": "Gesamtlevel",
"items": "Items",
"totalQty": "Gesamtmenge"
},
"overview": {
"character": "Charakter",
"hp": "HP",
"activePotion": "Aktiver Trank",
"activeSpell": "Aktiver Zauber",
"weaponSlot": "Waffenslot",
"blessing": "Segen",
"sessionQueue": "Session-Warteschlange",
"slayer": "Slayer",
"noSlayerTask": "Keine aktive Slayer-Aufgabe",
"pets": "Haustiere",
"farming": "Farming",
"patch": "Patch {n}",
"guildRep": "Gilden-Ruf"
},
"skills": {
"search": "Skill suchen…",
"sortLevel": "Nach Level",
"sortXp": "Nach XP",
"sortName": "Nach Name",
"skill": "Skill",
"level": "Level",
"progress": "Fortschritt"
},
"inventory": {
"search": "Item suchen…",
"sortCategory": "Nach Kategorie",
"sortName": "Nach Name",
"sortQty": "Nach Menge",
"highlightEquipped": "Ausgerüstete hervorheben",
"item": "Item",
"qty": "Menge",
"id": "ID",
"equipped": "Ausgerüstet",
"groupMeta": "{count} Items · {qty} Stk."
},
"equipment": {
"title": "Ausrüstung"
},
"quests": {
"story": "Story",
"daily": "Daily",
"weekly": "Weekly",
"guild": "Gilde",
"filterAll": "Alle",
"filterOpen": "Offen",
"filterDone": "Erledigt",
"quest": "Quest",
"progress": "Fortschritt",
"status": "Status",
"done": "Erledigt",
"open": "Offen"
},
"combat": {
"enemyKills": "Gegner-Kills",
"dungeonRuns": "Dungeon-Läufe",
"runs": "{count} Läufe",
"recentActivity": "Letzte Aktivität",
"activeSessions": "Aktive Sessions",
"sessionDone": "fertig",
"sessionRunning": "läuft"
},
"history": {
"loading": "Lade Verlauf…",
"coinsChart": "Münzen über Zeit",
"levelChart": "Gesamtlevel über Zeit",
"snapshotCompare": "Snapshot-Vergleich",
"allSnapshots": "Alle Snapshots",
"character": "Charakter",
"file": "Datei",
"inventoryChanges": "Inventar-Änderungen ({count})",
"skillChanges": "Skill-Änderungen ({count})",
"delta": "Delta",
"xpDelta": "XP-Delta",
"coinsSummary": "Münzen: {delta} · Gesamtlevel: {levelDelta}"
},
"category": {
"currency": "Währung",
"ores_mining": "Erze & Mining",
"bars_smithing": "Barren & Schmieden",
"wood_planks": "Holz & Bretter",
"runes": "Runen",
"raw_food": "Rohkost",
"cooked_food": "Gekochtes",
"seeds_farming": "Samen & Farming",
"melee_weapons": "Nahkampfwaffen",
"ranged": "Fernkampf",
"magic": "Magie",
"armor": "Rüstung",
"bones_hides": "Knochen & Felle",
"gems_jewelry": "Edelsteine & Schmuck",
"potions_brews": "Tränke & Brauerei",
"misc": "Sonstiges"
}
}
+178
View File
@@ -0,0 +1,178 @@
{
"app": {
"title": "Idle Fantasy",
"subtitle": "Save Viewer",
"loading": "Loading save…"
},
"nav": {
"overview": "Overview",
"skills": "Skills",
"inventory": "Inventory",
"equipment": "Equipment",
"quests": "Quests",
"combat": "Combat",
"history": "History"
},
"settings": {
"language": "Language",
"langAuto": "Auto (browser)",
"langEn": "English",
"langDe": "Deutsch"
},
"actions": {
"importBackup": "Import backup",
"compare": "Compare",
"dismiss": "Dismiss"
},
"empty": {
"noSave": "No save imported. Start with: python app.py fantasyidler_save.json",
"loadError": "Failed to load: {message}",
"unknown": "Unknown",
"none": "None",
"empty": "Empty",
"noItems": "No items found",
"noSnapshots": "No snapshots yet. Import a backup.",
"noChanges": "No changes",
"pickTwoSnapshots": "Select two different snapshots."
},
"import": {
"failed": "Import failed",
"duplicate": "Backup already exists (duplicate).",
"success": "Imported: Snapshot #{id}",
"successWithNotes": "Imported: Snapshot #{id}\n\n{warnings} warning(s), {infos} note(s) see dashboard banner for details.",
"titleError": "Import errors",
"titleWarning": "Import warnings",
"titleInfo": "Import notes",
"countErrors": "{count} error(s)",
"countWarnings": "{count} warning(s)",
"countInfos": "{count} info(s)",
"newFieldsSummary": "{count} new/unknown field(s) from the game",
"invalid_root": "The file is not a JSON object not a valid Idle Fantasy backup.",
"empty_save": "The save file is empty.",
"unknown_top_level": "Unknown field in backup: \"{field}\" (added by a game update?).",
"missing_field": "Expected field missing: \"{field}\" related data will be shown empty.",
"nested_json_invalid": "Field \"{field}\" could not be read as JSON raw value ignored.",
"invalid_coins": "Field \"coins\" is not numeric.",
"invalid_exported_at": "Field \"exported_at\" is not a valid timestamp.",
"missing_exported_at": "No export timestamp history comparisons may be inaccurate.",
"skill_xp_mismatch": "{count} skill(s) without XP entry (e.g. {examples}).",
"skill_level_mismatch": "{count} XP entries without skill level.",
"unparsed_nested_json": "Field \"{field}\" is still a text string JSON content could not be read.",
"invalid_type": "Field \"{field}\" has unexpected type ({type}).",
"coerced_empty_dict": "Field \"{field}\" is not an object treated as empty.",
"coerced_empty_list": "Field \"{field}\" is not a list skipped.",
"invalid_number": "Invalid number in \"{field}\"{detail}.",
"invalid_quest_entry": "Quest entry #{index} is not an object and was skipped.",
"invalid_session_entry": "Session entry #{index} is not an object and was skipped.",
"unparsed_session_frames": "Session #{index}: activity frames could not be read.",
"invalid_pets": "Field \"pets\" is not a list.",
"invalid_farming_patch": "Farming patch #{index} was skipped.",
"missing_character_name": "No character name found in save.",
"invalid_quest_ids": "Quest IDs ({label}) are not a list.",
"invalid_quest_progress": "Quest progress ({label}) is not an object."
},
"meta": {
"export": "Export",
"points": "points"
},
"kpi": {
"coins": "Coins",
"totalLevel": "Total level",
"items": "Items",
"totalQty": "Total quantity"
},
"overview": {
"character": "Character",
"hp": "HP",
"activePotion": "Active potion",
"activeSpell": "Active spell",
"weaponSlot": "Weapon slot",
"blessing": "Blessing",
"sessionQueue": "Session queue",
"slayer": "Slayer",
"noSlayerTask": "No active slayer task",
"pets": "Pets",
"farming": "Farming",
"patch": "Patch {n}",
"guildRep": "Guild reputation"
},
"skills": {
"search": "Search skills…",
"sortLevel": "By level",
"sortXp": "By XP",
"sortName": "By name",
"skill": "Skill",
"level": "Level",
"progress": "Progress"
},
"inventory": {
"search": "Search items…",
"sortCategory": "By category",
"sortName": "By name",
"sortQty": "By quantity",
"highlightEquipped": "Highlight equipped",
"item": "Item",
"qty": "Qty",
"id": "ID",
"equipped": "Equipped",
"groupMeta": "{count} items · {qty} pcs"
},
"equipment": {
"title": "Equipment"
},
"quests": {
"story": "Story",
"daily": "Daily",
"weekly": "Weekly",
"guild": "Guild",
"filterAll": "All",
"filterOpen": "Open",
"filterDone": "Completed",
"quest": "Quest",
"progress": "Progress",
"status": "Status",
"done": "Done",
"open": "Open"
},
"combat": {
"enemyKills": "Enemy kills",
"dungeonRuns": "Dungeon runs",
"runs": "{count} runs",
"recentActivity": "Recent activity",
"activeSessions": "Active sessions",
"sessionDone": "done",
"sessionRunning": "running"
},
"history": {
"loading": "Loading history…",
"coinsChart": "Coins over time",
"levelChart": "Total level over time",
"snapshotCompare": "Snapshot comparison",
"allSnapshots": "All snapshots",
"character": "Character",
"file": "File",
"inventoryChanges": "Inventory changes ({count})",
"skillChanges": "Skill changes ({count})",
"delta": "Delta",
"xpDelta": "XP delta",
"coinsSummary": "Coins: {delta} · Total level: {levelDelta}"
},
"category": {
"currency": "Currency",
"ores_mining": "Ores & Mining",
"bars_smithing": "Bars & Smithing",
"wood_planks": "Wood & Planks",
"runes": "Runes",
"raw_food": "Raw Food",
"cooked_food": "Cooked Food",
"seeds_farming": "Seeds & Farming",
"melee_weapons": "Melee Weapons",
"ranged": "Ranged",
"magic": "Magic",
"armor": "Armor",
"bones_hides": "Bones & Hides",
"gems_jewelry": "Gems & Jewelry",
"potions_brews": "Potions & Brews",
"misc": "Misc"
}
}