""" Localization/Translation System Supports: English, French, Traditional Chinese """ from __future__ import annotations from dataclasses import dataclass from typing import Dict, Iterable @dataclass(frozen=True) class LanguageMetadata: display_name: str ai_language_name: str ai_example_summary: str TRANSLATIONS: Dict[str, Dict[str, str]] = { "en": { "game.window.title": "Minimalist RTS", "game.language.display": "Language: {language}", "game.win.banner": "{winner} Wins!", "game.winner.player": "Player", "game.winner.enemy": "Enemy", "hud.topbar.credits": "Credits: {amount}", "hud.topbar.power": "Power: {produced}/{consumed}", "hud.topbar.intel.summary": "Intel: {summary}", "hud.topbar.intel.waiting": "Intel: Awaiting report", "hud.intel.header.offline": "Intel: Offline", "hud.intel.header.refresh": "Intel: {mode} refresh", "hud.intel.mode.auto": "Auto", "hud.intel.mode.manual": "Manual", "hud.intel.status.model_missing": "Model not available", "hud.intel.status.updating": "Status: Updating...", "hud.intel.status.updated": "Updated {seconds}s ago", "hud.intel.status.waiting": "Waiting for first report", "hud.intel.cycle": "Cycle: ~{seconds}s", "hud.section.infantry": "Infantry", "hud.section.vehicles": "Vehicles", "hud.section.support": "Support", "hud.section.structures": "Structures", "hud.button.cost": "{cost} cr", "unit.infantry": "Infantry", "unit.tank": "Tank", "unit.artillery": "Artillery", "unit.helicopter": "Helicopter", "unit.harvester": "Harvester", "building.hq": "Headquarters", "building.barracks": "Barracks", "building.war_factory": "War Factory", "building.refinery": "Refinery", "building.power_plant": "Power Plant", "building.turret": "Defense Turret", "faction.allies": "Allies", "faction.soviets": "Soviets", "intel.unavailable": "Intel unavailable", "intel.error": "Intel error: {error}", "notification.insufficient_credits": "⚠️ Insufficient credits! Need {cost} cr, have {current} cr", "notification.low_power": "⚠️ LOW POWER! Build more Power Plants or production will be slow!", "notification.no_power": "🚨 CRITICAL POWER SHORTAGE! Buildings offline!", "notification.building_requires": "⚠️ Cannot build {building}: requires {requirement}", "notification.unit_requires": "⚠️ Cannot train {unit}: requires {requirement}", "notification.building_placed": "Building {building}", "notification.unit_training": "Training {unit}", "notification.building_cancelled": "Building cancelled", "notification.building_too_far_from_hq": "⚠️ Too far from HQ: build closer to your Headquarters", "notification.building_limit_one": "⚠️ Only one {building} can be constructed", "notification.production_building_selected": "🏭 Production will use: {building}", "hud.production.source.auto": "Auto", "hud.production.source.label": "Using:", "hud.production.source.clear": "Clear selection", "notification.units_moving": "Moving {count} units", "notification.units_selected": "Selected {count} units", "notification.units_attacking": "🎯 Attacking enemy {target}!", "notification.click_to_place": "🏗️ Click to place {building}", "notification.language_changed": "Language changed to {language}", "language.en": "English", "language.fr": "French", "language.zh-TW": "Traditional Chinese", "menu.quick_actions.title": "🎯 Quick Actions", "menu.actions.select_all": "Select All Units", "menu.actions.select_all.tooltip": "Select all your units (hotkey: Ctrl+A)", "menu.actions.stop": "Stop Selected", "menu.actions.stop.tooltip": "Stop selected units", "menu.actions.attack_move": "Attack Move", "menu.actions.attack_move.tooltip": "Attack enemies while moving (hotkey: A)", "menu.actions.restart": "Restart", "menu.control_groups.title": "🎮 Control Groups", "menu.stats.title": "📈 Game Stats", "menu.stats.player_units": "Player Units:", "menu.stats.enemy_units": "Enemy Units:", "menu.stats.buildings": "Buildings:", "status.connected": "Connected", "status.disconnected": "Disconnected", "game.header.title": "🎮 RTS Commander", "menu.build.title": "🏗️ Build Menu", "menu.units.title": "⚔️ Train Units", "menu.selection.title": "📊 Selection Info", "menu.selection.none": "No units selected", "menu.production_queue.title": "🏭 Production Queue", "menu.production_queue.empty": "Queue is empty", "control_groups.hint": "Ctrl+[1-9] to assign, [1-9] to select", "hud.topbar.tick": "Tick:", "hud.topbar.units": "Units:", "hud.nuke.charging": "Charging:", "hud.nuke.ready": "☢️ READY (Press N)", "notification.moving_units": "Moving {count} units", "notification.moving_units_distant": "Moving {count} units to distant location", "notification.connection_error": "Connection error", "notification.disconnected": "Disconnected from server", "hud.intel.requesting": "🤖 Requesting tactical analysis...", "notification.nuke_launched": "💥 NUKE LAUNCHED!", "notification.nuke_cancelled": "Nuke launch cancelled", "hud.nuke.select_target": "Select nuke target (Right-click)", "notification.group.empty": "Group {group}: Empty", "notification.group.destroyed": "Group {group}: All units destroyed", "notification.group.assigned": "Group {group} assigned: {count} units", "notification.group.selected": "Group {group} selected: {count} units", "hud.intel.header.active": "🤖 Intel: Active", "hud.intel.header.error": "🤖 Intel: Error", "hud.intel.status.failed": "Analysis failed", "hud.intel.source.llm": "Source: Large Language Model", "hud.intel.source.heuristic": "Source: Heuristic analysis", "menu.sound.enable": "Enable sound", "menu.sound.disable": "Disable sound", "notification.sound.enabled": "Sound enabled", "notification.sound.disabled": "Sound disabled", "menu.camera.zoom_in": "Zoom In", "menu.camera.zoom_out": "Zoom Out", "menu.camera.reset": "Reset View", "hud.intel.refresh.tooltip": "Refresh Intel", "hud.model.download.starting": "Downloading model…", "hud.model.download.progress": "Downloading: {percent}% ({note})", "hud.model.download.retry": "Retrying download…", "hud.model.download.done": "Model ready", "hud.model.download.error": "Model download failed", "game.draw.banner": "Draw!", }, "fr": { "game.window.title": "RTS Minimaliste", "game.language.display": "Langue : {language}", "game.win.banner": "{winner} gagne !", "game.winner.player": "Joueur", "game.winner.enemy": "Ennemi", "hud.topbar.credits": "Crédits : {amount}", "hud.topbar.power": "Énergie : {produced}/{consumed}", "hud.topbar.intel.summary": "Renseignement : {summary}", "hud.topbar.intel.waiting": "Renseignement : en attente", "hud.intel.header.offline": "Renseignement : hors ligne", "hud.intel.header.refresh": "Renseignement : cycle {mode}", "hud.intel.mode.auto": "auto", "hud.intel.mode.manual": "manuel", "hud.intel.status.model_missing": "Modèle indisponible", "hud.intel.status.updating": "Statut : mise à jour…", "hud.intel.status.updated": "Mis à jour il y a {seconds}s", "hud.intel.status.waiting": "En attente du premier rapport", "hud.intel.cycle": "Cycle : ~{seconds}s", "hud.section.infantry": "Infanterie", "hud.section.vehicles": "Véhicules", "hud.section.support": "Soutien", "hud.section.structures": "Bâtiments", "hud.button.cost": "{cost} cr", "unit.infantry": "Infanterie", "unit.tank": "Char", "unit.artillery": "Artillerie", "unit.helicopter": "Hélicoptère", "unit.harvester": "Collecteur", "building.hq": "QG", "building.barracks": "Caserne", "building.war_factory": "Usine", "building.refinery": "Raffinerie", "building.power_plant": "Centrale", "building.turret": "Tourelle", "faction.allies": "Alliés", "faction.soviets": "Soviétiques", "intel.unavailable": "Renseignement indisponible", "intel.error": "Erreur renseignement : {error}", "notification.insufficient_credits": "⚠️ Crédits insuffisants ! Besoin de {cost} cr, vous avez {current} cr", "notification.low_power": "⚠️ ÉNERGIE FAIBLE ! Construisez plus de centrales ou la production sera lente !", "notification.no_power": "🚨 PANNE D'ÉNERGIE CRITIQUE ! Bâtiments hors ligne !", "notification.building_requires": "⚠️ Impossible de construire {building} : nécessite {requirement}", "notification.unit_requires": "⚠️ Impossible d'entraîner {unit} : nécessite {requirement}", "notification.building_placed": "Construction de {building}", "notification.unit_training": "Entraînement de {unit}", "notification.building_cancelled": "Construction annulée", "notification.building_too_far_from_hq": "⚠️ Trop éloigné du QG : construisez plus près de votre Quartier Général", "notification.building_limit_one": "⚠️ Un seul {building} peut être construit", "notification.production_building_selected": "🏭 La production utilisera : {building}", "hud.production.source.auto": "Auto", "hud.production.source.label": "Utilise :", "hud.production.source.clear": "Effacer la sélection", "notification.units_moving": "Déplacement de {count} unités", "notification.units_selected": "{count} unités sélectionnées", "notification.units_attacking": "🎯 Attaque de {target} ennemi !", "notification.click_to_place": "🏗️ Cliquez pour placer {building}", "notification.language_changed": "Langue changée en {language}", "language.en": "Anglais", "language.fr": "Français", "language.zh-TW": "Chinois traditionnel", "menu.quick_actions.title": "🎯 Actions rapides", "menu.actions.select_all": "Tout sélectionner", "menu.actions.select_all.tooltip": "Sélectionner toutes vos unités (raccourci : Ctrl+A)", "menu.actions.stop": "Arrêter sélection", "menu.actions.stop.tooltip": "Arrêter les unités sélectionnées", "menu.actions.attack_move": "Attaque en mouvement", "menu.actions.attack_move.tooltip": "Attaquer les ennemis en se déplaçant (raccourci : A)", "menu.actions.restart": "Recommencer", "menu.control_groups.title": "🎮 Groupes de contrôle", "menu.stats.title": "📈 Statistiques", "menu.stats.player_units": "Unités joueur :", "menu.stats.enemy_units": "Unités ennemies :", "menu.stats.buildings": "Bâtiments :", "status.connected": "Connecté", "status.disconnected": "Déconnecté", "game.header.title": "🎮 Commandant RTS", "menu.build.title": "🏗️ Menu construction", "menu.units.title": "⚔️ Entraîner unités", "menu.selection.title": "📊 Sélection", "menu.selection.none": "Aucune unité sélectionnée", "menu.production_queue.title": "🏭 File de production", "menu.production_queue.empty": "File vide", "control_groups.hint": "Ctrl+[1-9] pour assigner, [1-9] pour sélectionner", "hud.topbar.tick": "Tick :", "hud.topbar.units": "Unités :", "hud.nuke.charging": "Chargement :", "hud.nuke.ready": "☢️ PRÊT (Appuyez sur N)", "notification.moving_units": "Déplacement de {count} unités", "notification.moving_units_distant": "Déplacement de {count} unités vers une position éloignée", "notification.connection_error": "Erreur de connexion", "notification.disconnected": "Déconnecté du serveur", "hud.intel.requesting": "🤖 Demande d'analyse tactique...", "notification.nuke_launched": "💥 BOMBE NUCLÉAIRE LANCÉE !", "notification.nuke_cancelled": "Lancement nucléaire annulé", "hud.nuke.select_target": "Sélectionnez la cible nucléaire (clic droit)", "notification.group.empty": "Groupe {group} : Vide", "notification.group.destroyed": "Groupe {group} : Toutes les unités détruites", "notification.group.assigned": "Groupe {group} assigné : {count} unité(s)", "notification.group.selected": "Groupe {group} sélectionné : {count} unité(s)", "hud.intel.header.active": "🤖 Renseignement : Actif", "hud.intel.header.error": "🤖 Renseignement : Erreur", "hud.intel.status.failed": "Analyse échouée", "hud.intel.source.llm": "Source : Modèle de langage (LLM)", "hud.intel.source.heuristic": "Source : Analyse heuristique", "menu.sound.enable": "Activer le son", "menu.sound.disable": "Désactiver le son", "notification.sound.enabled": "Son activé", "notification.sound.disabled": "Son désactivé", "game.draw.banner": "Match nul !", "menu.camera.zoom_in": "Zoom avant", "menu.camera.zoom_out": "Zoom arrière", "menu.camera.reset": "Réinitialiser la vue", "hud.intel.refresh.tooltip": "Rafraîchir le renseignement", "hud.model.download.starting": "Téléchargement du modèle…", "hud.model.download.progress": "Téléchargement : {percent}% ({note})", "hud.model.download.retry": "Nouvelle tentative de téléchargement…", "hud.model.download.done": "Modèle prêt", "hud.model.download.error": "Échec du téléchargement du modèle", }, "zh-TW": { "game.window.title": "簡約即時戰略", "game.language.display": "介面語言:{language}", "game.win.banner": "{winner} 獲勝!", "game.winner.player": "玩家", "game.winner.enemy": "敵軍", "hud.topbar.credits": "資源:{amount}", "hud.topbar.power": "電力:{produced}/{consumed}", "hud.topbar.intel.summary": "情報:{summary}", "hud.topbar.intel.waiting": "情報:等待報告", "hud.intel.header.offline": "情報:離線", "hud.intel.header.refresh": "情報:{mode} 更新", "hud.intel.mode.auto": "自動", "hud.intel.mode.manual": "手動", "hud.intel.status.model_missing": "模型不可用", "hud.intel.status.updating": "狀態:更新中...", "hud.intel.status.updated": "{seconds} 秒前更新", "hud.intel.status.waiting": "等待首次報告", "hud.intel.cycle": "週期:約 {seconds} 秒", "hud.section.infantry": "步兵", "hud.section.vehicles": "載具", "hud.section.support": "支援", "hud.section.structures": "建築", "hud.button.cost": "{cost} cr", "unit.infantry": "步兵", "unit.tank": "坦克", "unit.artillery": "火砲", "unit.helicopter": "直升機", "unit.harvester": "採礦車", "building.hq": "總部", "building.barracks": "兵營", "building.war_factory": "戰爭工廠", "building.refinery": "精煉廠", "building.power_plant": "發電廠", "building.turret": "防禦砲塔", "faction.allies": "盟軍", "faction.soviets": "蘇聯", "intel.unavailable": "情報不可用", "intel.error": "情報錯誤:{error}", "notification.insufficient_credits": "⚠️ 資源不足!需要 {cost} cr,目前有 {current} cr", "notification.low_power": "⚠️ 電力不足!建造更多發電廠,否則生產將變慢!", "notification.no_power": "🚨 嚴重電力短缺!建築離線!", "notification.building_requires": "⚠️ 無法建造 {building}:需要 {requirement}", "notification.unit_requires": "⚠️ 無法訓練 {unit}:需要 {requirement}", "notification.building_placed": "建造 {building}", "notification.unit_training": "訓練 {unit}", "notification.building_cancelled": "取消建造", "notification.building_too_far_from_hq": "⚠️ 距離總部太遠:請在更靠近總部的地方建造", "notification.building_limit_one": "⚠️ 只能建造一座{building}", "notification.production_building_selected": "🏭 將由此建築物進行生產:{building}", "hud.production.source.auto": "自動", "hud.production.source.label": "使用:", "hud.production.source.clear": "清除選取", "notification.units_moving": "移動 {count} 個單位", "notification.units_selected": "已選擇 {count} 個單位", "notification.units_attacking": "🎯 攻擊敵方 {target}!", "notification.click_to_place": "🏗️ 點擊放置 {building}", "notification.language_changed": "語言已更改為 {language}", "language.en": "英語", "language.fr": "法語", "language.zh-TW": "繁體中文", "menu.quick_actions.title": "🎯 快速動作", "menu.actions.select_all": "全選單位", "menu.actions.select_all.tooltip": "選擇所有單位(快捷鍵:Ctrl+A)", "menu.actions.stop": "停止選取", "menu.actions.stop.tooltip": "停止選取的單位", "menu.actions.attack_move": "攻擊移動", "menu.actions.attack_move.tooltip": "移動時攻擊敵人(快捷鍵:A)", "menu.actions.restart": "重新開始", "menu.control_groups.title": "🎮 控制組", "menu.stats.title": "📈 遊戲統計", "menu.stats.player_units": "玩家單位:", "menu.stats.enemy_units": "敵方單位:", "menu.stats.buildings": "建築:", "status.connected": "已連接", "status.disconnected": "已斷線", "game.header.title": "🎮 RTS 指揮官", "menu.build.title": "🏗️ 建造選單", "menu.units.title": "⚔️ 訓練單位", "menu.selection.title": "📊 選取資訊", "menu.selection.none": "未選取單位", "menu.production_queue.title": "🏭 生產佇列", "menu.production_queue.empty": "佇列為空", "control_groups.hint": "Ctrl+[1-9] 指派,[1-9] 選取", "hud.topbar.tick": "Tick:", "hud.topbar.units": "單位:", "hud.nuke.charging": "充能中:", "hud.nuke.ready": "☢️ 就緒(按 N)", "notification.moving_units": "移動 {count} 個單位", "notification.moving_units_distant": "移動 {count} 個單位到遠處", "notification.connection_error": "連線錯誤", "notification.disconnected": "已從伺服器斷線", "hud.intel.requesting": "🤖 請求戰術分析...", "notification.nuke_launched": "💥 核彈發射!", "notification.nuke_cancelled": "核彈發射已取消", "hud.nuke.select_target": "選擇核彈目標(右鍵)", "notification.group.empty": "群組 {group}:空", "notification.group.destroyed": "群組 {group}:所有單位已被摧毀", "notification.group.assigned": "群組 {group} 已指派:{count} 個單位", "notification.group.selected": "群組 {group} 已選取:{count} 個單位", "hud.intel.header.active": "🤖 情報:運作中", "hud.intel.header.error": "🤖 情報:錯誤", "hud.intel.status.failed": "分析失敗", "hud.intel.source.llm": "來源:大型語言模型 (LLM)", "hud.intel.source.heuristic": "來源:啟發式分析", "menu.sound.enable": "開啟聲音", "menu.sound.disable": "關閉聲音", "notification.sound.enabled": "已開啟聲音", "notification.sound.disabled": "已關閉聲音", "menu.camera.zoom_in": "放大", "menu.camera.zoom_out": "縮小", "menu.camera.reset": "重置視角", "hud.intel.refresh.tooltip": "重新整理情報", "hud.model.download.starting": "正在下載模型…", "hud.model.download.progress": "下載中:{percent}%({note})", "hud.model.download.retry": "重試下載…", "hud.model.download.done": "模型已就緒", "hud.model.download.error": "模型下載失敗", "game.draw.banner": "平手!", }, } LANGUAGE_METADATA: Dict[str, LanguageMetadata] = { "en": LanguageMetadata( display_name="English", ai_language_name="English", ai_example_summary="Allies hold a modest resource advantage and a forward infantry presence near the center.", ), "fr": LanguageMetadata( display_name="Français", ai_language_name="French", ai_example_summary="Les Alliés disposent d'un léger avantage économique et d'une infanterie avancée près du centre.", ), "zh-TW": LanguageMetadata( display_name="繁體中文", ai_language_name="Traditional Chinese", ai_example_summary="盟軍在資源上略占優勢,並在中央附近部署前進步兵。", ), } DEFAULT_LANGUAGE = "en" SUPPORTED_LANGUAGES: Iterable[str] = tuple(TRANSLATIONS.keys()) class LocalizationManager: """Manages translations for multiple languages""" def __init__(self) -> None: self._translations = TRANSLATIONS self._metadata = LANGUAGE_METADATA self._order = list(SUPPORTED_LANGUAGES) def translate(self, language_code: str, key: str, **kwargs) -> str: """Get translated string with variable substitution""" lang_map = self._translations.get(language_code) template = None if lang_map is None else lang_map.get(key) if template is None: template = self._translations[DEFAULT_LANGUAGE].get(key, key) try: return template.format(**kwargs) except (KeyError, ValueError): return template def get_supported_languages(self) -> Iterable[str]: """Get list of supported language codes""" return tuple(self._order) def get_display_name(self, language: str) -> str: """Get display name for language""" metadata = self._metadata.get(language) if metadata: return metadata.display_name return self._metadata[DEFAULT_LANGUAGE].display_name def get_ai_language_name(self, language: str) -> str: """Get AI language name for prompts""" metadata = self._metadata.get(language) if metadata: return metadata.ai_language_name return self._metadata[DEFAULT_LANGUAGE].ai_language_name def get_ai_example_summary(self, language: str) -> str: """Get example AI summary for language""" metadata = self._metadata.get(language) if metadata: return metadata.ai_example_summary return self._metadata[DEFAULT_LANGUAGE].ai_example_summary # Singleton instance LOCALIZATION = LocalizationManager() # Helper for Simplified → Traditional Chinese conversion using OpenCC _opencc_converter = None def convert_to_traditional(text: str) -> str: """Convert Simplified Chinese to Traditional Chinese""" global _opencc_converter if not text: return text if _opencc_converter is None: try: from opencc import OpenCC _opencc_converter = OpenCC('s2t') except ImportError: print("Warning: OpenCC not available for Chinese character conversion") _opencc_converter = False except Exception as e: print(f"Warning: OpenCC initialization failed: {e}") _opencc_converter = False if _opencc_converter and _opencc_converter is not False: try: convert_fn = getattr(_opencc_converter, 'convert', None) if callable(convert_fn): return str(convert_fn(text)) except Exception as e: print(f"Warning: OpenCC conversion failed: {e}") return text return text