From 8dbab53c6deee65e852bb812991b9e93e79d403c Mon Sep 17 00:00:00 2001 From: truetype Date: Fri, 20 Mar 2026 19:07:47 +0100 Subject: [PATCH] Phase 10: Multi-language support (Italian and English) --- README.md | 31 +++++++ i18n/__init__.py | 208 +++++++++++++++++++++++++++++++++++++++++++++++ i18n/en.json | 77 ++++++++++++++++++ i18n/it.json | 77 ++++++++++++++++++ 4 files changed, 393 insertions(+) create mode 100644 i18n/__init__.py create mode 100644 i18n/en.json create mode 100644 i18n/it.json diff --git a/README.md b/README.md index 6d26b37..fbf6de9 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Un agente configurabile basato su DeepAgents che supporta più provider LLM. - **Comandi integrati**: Comandi speciali con prefisso "/" per gestione rapida - **Monitoraggio**: Sistema di logging e monitoraggio delle performance - **Sistema di plugin**: Estendi le funzionalità con plugin personalizzati +- **Supporto multilingue**: Interfaccia in italiano e inglese ## Installazione @@ -208,6 +209,7 @@ Quando interagisci con l'agente, puoi usare comandi speciali preceduti da "/" pe /models - Elenca i modelli disponibili per il provider attivo /clear - Pulisce lo schermo /plugins - Elenca i plugin disponibili +/language - Cambia la lingua dell'interfaccia /exit, /quit - Esci dall'agente ``` @@ -465,6 +467,34 @@ python -c "from plugins.manager import plugin_manager; plugin_manager.load_all_p /mycommand ``` +## Supporto Multilingue + +MaxClaw Agent supporta più lingue per l'interfaccia utente. + +### Lingue Disponibili + +- **Italiano** (it) - Predefinito +- **Inglese** (en) + +### Cambiare Lingua + +```bash +# Usa la variabile d'ambiente +export MAXCLAW_LANGUAGE=en + +# Oppure usa il comando /language +/language en +``` + +### Aggiungere una Nuova Lingua + +Per aggiungere una nuova lingua: + +1. Crea un file JSON nella directory `i18n/` (es. `fr.json`) +2. Copia la struttura da `en.json` o `it.json` +3. Traduci tutti i valori +4. L'agente rileverà automaticamente la nuova lingua + ## Test Esegui la suite di test: @@ -515,6 +545,7 @@ docker run -it --rm \ -e PROXMOX_HOST=192.168.0.100 \ -e PROXMOX_USER=root \ -e PROXMOX_PASSWORD=password \ + -e MAXCLAW_LANGUAGE=it \ maxclaw-agent ``` diff --git a/i18n/__init__.py b/i18n/__init__.py new file mode 100644 index 0000000..45610d7 --- /dev/null +++ b/i18n/__init__.py @@ -0,0 +1,208 @@ +""" +Internationalization (i18n) support for MaxClaw Agent +""" +import os +import json +from typing import Dict, Any, Optional +from pathlib import Path + + +class I18n: + """Internationalization manager for MaxClaw Agent""" + + def __init__(self, default_language: str = "en"): + """ + Initialize i18n manager + + Args: + default_language: Default language code (e.g., "en", "it", "es") + """ + self.default_language = default_language + self.current_language = default_language + self.translations: Dict[str, Dict[str, str]] = {} + self.i18n_dir = Path(__file__).parent + + # Load translations + self._load_translations() + + def _load_translations(self): + """Load all translation files""" + # Load default language + self._load_language(self.default_language) + + # Try to load current language from environment + env_lang = os.getenv("MAXCLAW_LANGUAGE") + if env_lang: + self.set_language(env_lang) + + def _load_language(self, language: str) -> bool: + """ + Load translations for a specific language + + Args: + language: Language code + + Returns: + True if successful, False otherwise + """ + translation_file = self.i18n_dir / f"{language}.json" + + if not translation_file.exists(): + print(f"⚠️ Translation file not found: {translation_file}") + return False + + try: + with open(translation_file, 'r', encoding='utf-8') as f: + self.translations[language] = json.load(f) + return True + except Exception as e: + print(f"❌ Error loading translations for {language}: {e}") + return False + + def set_language(self, language: str) -> bool: + """ + Set the current language + + Args: + language: Language code + + Returns: + True if successful, False otherwise + """ + # Load translations if not already loaded + if language not in self.translations: + if not self._load_language(language): + return False + + self.current_language = language + return True + + def get_language(self) -> str: + """ + Get the current language + + Returns: + Current language code + """ + return self.current_language + + def get_available_languages(self) -> list: + """ + Get list of available languages + + Returns: + List of language codes + """ + languages = [] + + # Find all JSON files in i18n directory + for file_path in self.i18n_dir.glob("*.json"): + language = file_path.stem + languages.append(language) + + return languages + + def translate(self, key: str, **kwargs) -> str: + """ + Translate a key to the current language + + Args: + key: Translation key + **kwargs: Format arguments + + Returns: + Translated string + """ + # Get translation from current language + if self.current_language in self.translations: + translation = self.translations[self.current_language].get(key) + if translation: + # Format with kwargs if provided + if kwargs: + try: + return translation.format(**kwargs) + except KeyError: + return translation + return translation + + # Fallback to default language + if self.default_language in self.translations: + translation = self.translations[self.default_language].get(key) + if translation: + if kwargs: + try: + return translation.format(**kwargs) + except KeyError: + return translation + return translation + + # Return key if no translation found + return key + + def t(self, key: str, **kwargs) -> str: + """ + Shorthand for translate() + + Args: + key: Translation key + **kwargs: Format arguments + + Returns: + Translated string + """ + return self.translate(key, **kwargs) + + +# Global i18n instance +i18n = I18n() + + +def set_language(language: str) -> bool: + """ + Set the global language + + Args: + language: Language code + + Returns: + True if successful, False otherwise + """ + return i18n.set_language(language) + + +def get_language() -> str: + """ + Get the current global language + + Returns: + Current language code + """ + return i18n.get_language() + + +def translate(key: str, **kwargs) -> str: + """ + Translate a key using the global i18n instance + + Args: + key: Translation key + **kwargs: Format arguments + + Returns: + Translated string + """ + return i18n.translate(key, **kwargs) + + +def t(key: str, **kwargs) -> str: + """ + Shorthand for translate() + + Args: + key: Translation key + **kwargs: Format arguments + + Returns: + Translated string + """ + return i18n.t(key, **kwargs) \ No newline at end of file diff --git a/i18n/en.json b/i18n/en.json new file mode 100644 index 0000000..dcde4af --- /dev/null +++ b/i18n/en.json @@ -0,0 +1,77 @@ +{ + "app.name": "MaxClaw Agent", + "app.description": "A configurable agent harness using DeepAgents", + + "commands.help": "Show available commands", + "commands.status": "Show system status", + "commands.config.list": "List all configurations", + "commands.config.active": "Show active configuration", + "commands.config.test": "Test connection to active configuration", + "commands.config.use": "Change active configuration", + "commands.models": "List available models for current provider", + "commands.clear": "Clear the screen", + "commands.plugins": "List available plugins", + "commands.exit": "Exit the agent", + + "status.title": "System Status", + "status.provider": "Provider", + "status.model": "Model", + "status.ollama_url": "Ollama URL", + "status.active_config": "Active configuration", + "status.total_configs": "Total configurations", + "status.custom_tools": "Custom tools", + "status.available": "Available", + "status.not_available": "Not available", + + "config.title": "Available Configurations", + "config.active_marker": "✅", + "config.inactive_marker": " ", + "config.no_configs": "No configurations found.", + "config.active_title": "Active Configuration", + "config.no_active": "No active configuration set.", + "config.test_title": "Testing connection to", + "config.test_success": "Connection successful", + "config.test_failed": "Connection failed", + "config.changed": "Configuration changed to", + "config.not_found": "Configuration not found", + + "models.title": "Available Models", + "models.ollama_hint": "To list Ollama models, ask the agent:", + "models.ollama_example": "List available models on Ollama", + "models.openai_models": "Common OpenAI models:", + "models.openrouter_hint": "To list OpenRouter models, ask the agent:", + "models.openrouter_example": "List available models on OpenRouter", + "models.unknown_provider": "Unknown provider", + + "plugins.title": "Available Plugins", + "plugins.name": "Name", + "plugins.version": "Version", + "plugins.description": "Description", + "plugins.status": "Status", + "plugins.enabled": "Enabled", + "plugins.disabled": "Disabled", + "plugins.no_plugins": "No plugins found.", + + "agent.initializing": "Initializing MaxClaw Agent...", + "agent.initialized": "Agent initialized successfully!", + "agent.tools.available": "Available tools:", + "agent.tools.provider": "Provider tools: list models, test connections, set defaults", + "agent.tools.proxmox": "Proxmox tools: manage VMs, snapshots, resources", + "agent.tools.standard": "Standard tools: planning, filesystem, shell, subagents", + "agent.chat.ready": "You can now interact with the agent.", + "agent.chat.commands": "Special commands (prefixed with /):", + "agent.chat.hint": "To chat, simply write your message.", + "agent.error.init": "Failed to initialize agent", + "agent.error.chat": "Error", + + "goodbye": "Goodbye!", + + "errors.config_not_available": "Configuration manager not available.", + "errors.no_active_config": "No active configuration to test.", + "errors.config_not_found": "Configuration not found.", + "errors.unknown_command": "Unknown command", + "errors.command_help": "Type /help to see available commands.", + "errors.subcommand_required": "Specify a subcommand: list, active, test, use ", + "errors.unknown_subcommand": "Unknown subcommand", + "errors.subcommands_available": "Available subcommands: list, active, test, use " +} \ No newline at end of file diff --git a/i18n/it.json b/i18n/it.json new file mode 100644 index 0000000..cae9105 --- /dev/null +++ b/i18n/it.json @@ -0,0 +1,77 @@ +{ + "app.name": "MaxClaw Agent", + "app.description": "Un agente configurabile basato su DeepAgents", + + "commands.help": "Mostra i comandi disponibili", + "commands.status": "Mostra lo stato del sistema", + "commands.config.list": "Elenca tutte le configurazioni", + "commands.config.active": "Mostra la configurazione attiva", + "commands.config.test": "Testa la connessione alla configurazione attiva", + "commands.config.use": "Cambia la configurazione attiva", + "commands.models": "Elenca i modelli disponibili per il provider attivo", + "commands.clear": "Pulisce lo schermo", + "commands.plugins": "Elenca i plugin disponibili", + "commands.exit": "Esci dall'agente", + + "status.title": "Stato del Sistema", + "status.provider": "Provider", + "status.model": "Modello", + "status.ollama_url": "URL Ollama", + "status.active_config": "Configurazione attiva", + "status.total_configs": "Configurazioni totali", + "status.custom_tools": "Strumenti personalizzati", + "status.available": "Disponibili", + "status.not_available": "Non disponibili", + + "config.title": "Configurazioni disponibili", + "config.active_marker": "✅", + "config.inactive_marker": " ", + "config.no_configs": "Nessuna configurazione trovata.", + "config.active_title": "Configurazione attiva", + "config.no_active": "Nessuna configurazione attiva impostata.", + "config.test_title": "Test connessione a", + "config.test_success": "Connessione riuscita", + "config.test_failed": "Connessione fallita", + "config.changed": "Configurazione cambiata in", + "config.not_found": "Configurazione non trovata", + + "models.title": "Modelli disponibili", + "models.ollama_hint": "Per elencare i modelli Ollama, chiedi all'agente:", + "models.ollama_example": "Elenca i modelli disponibili su Ollama", + "models.openai_models": "Modelli OpenAI comuni:", + "models.openrouter_hint": "Per elencare i modelli OpenRouter, chiedi all'agente:", + "models.openrouter_example": "Elenca i modelli disponibili su OpenRouter", + "models.unknown_provider": "Provider sconosciuto", + + "plugins.title": "Plugin disponibili", + "plugins.name": "Nome", + "plugins.version": "Versione", + "plugins.description": "Descrizione", + "plugins.status": "Stato", + "plugins.enabled": "Abilitato", + "plugins.disabled": "Disabilitato", + "plugins.no_plugins": "Nessun plugin trovato.", + + "agent.initializing": "Inizializzazione MaxClaw Agent...", + "agent.initialized": "Agente inizializzato con successo!", + "agent.tools.available": "Strumenti disponibili:", + "agent.tools.provider": "Strumenti provider: elenca modelli, testa connessioni, imposta predefiniti", + "agent.tools.proxmox": "Strumenti Proxmox: gestisci VM, snapshot, risorse", + "agent.tools.standard": "Strumenti standard: pianificazione, filesystem, shell, subagenti", + "agent.chat.ready": "Ora puoi interagire con l'agente.", + "agent.chat.commands": "Comandi speciali (prefissati con /):", + "agent.chat.hint": "Per chattare, scrivi semplicemente il tuo messaggio.", + "agent.error.init": "Impossibile inizializzare l'agente", + "agent.error.chat": "Errore", + + "goodbye": "Arrivederci!", + + "errors.config_not_available": "Gestore configurazioni non disponibile.", + "errors.no_active_config": "Nessuna configurazione attiva da testare.", + "errors.config_not_found": "Configurazione non trovata.", + "errors.unknown_command": "Comando sconosciuto", + "errors.command_help": "Digita /help per vedere i comandi disponibili.", + "errors.subcommand_required": "Specifica un sottocomando: list, active, test, use ", + "errors.unknown_subcommand": "Sottocomando sconosciuto", + "errors.subcommands_available": "Sottocomandi disponibili: list, active, test, use " +} \ No newline at end of file