#!/usr/bin/env python3 # © 2021-2026 TechnoLibre (http://www.technolibre.ca) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) import os import re ENV_VAR_FILE = "./env_var.sh" _current_lang = None TRANSLATIONS = { # Main menu "Importation success!": { "fr": "L'importation est un succès!", "en": "Importation success!", }, "Opening TODO ...": { "fr": "Ouverture de TODO en cours ...", "en": "Opening TODO ...", }, "=> Enter your choice by number and press Enter!": { "fr": "=> Entre tes directives par son chiffre et fait Entrée!", "en": "=> Enter your choice by number and press Enter!", }, "Command:": { "fr": "Commande :", "en": "Command:", }, "Execute": { "fr": "Exécution", "en": "Execute", }, "Install": { "fr": "Installation", "en": "Install", }, "Question": { "fr": "Question", "en": "Question", }, "Fork - Open TODO in a new tab": { "fr": "Fork - Ouvre TODO dans une nouvelle tabulation", "en": "Fork - Open TODO in a new tab", }, "Quit": { "fr": "Quitter", "en": "Quit", }, "Command not found !": { "fr": "Commande non trouvée !", "en": "Command not found !", }, "Back": { "fr": "Retour", "en": "Back", }, # Execute submenu "Run - Execute and install an instance": { "fr": "Run - Exécuter et installer une instance", "en": "Run - Execute and install an instance", }, "Automation - Demonstration of developed features": { "fr": "Automatisation - Demonstration des fonctions développées", "en": "Automation - Demonstration of developed features", }, "Update - Update all developed staging source code": { "fr": "Mise à jour - Update all developed staging source code", "en": "Update - Update all developed staging source code", }, "Code - Developer tools": { "fr": "Code - Outil pour développeur", "en": "Code - Developer tools", }, "Doc - Documentation search": { "fr": "Doc - Recherche de documentation", "en": "Doc - Documentation search", }, "Database - Database tools": { "fr": "Database - Outils sur les bases de données", "en": "Database - Database tools", }, "Process - Execution tools": { "fr": "Process - Outils sur les executions", "en": "Process - Execution tools", }, "Config - Configuration file management": { "fr": "Config - Traitement du fichier de configuration", "en": "Config - Configuration file management", }, "Network - Network tools": { "fr": "Réseau - Outil réseautique", "en": "Network - Network tools", }, "Security - Dependency security audit": { "fr": "Sécurité - Audit de sécurité des dépendances", "en": "Security - Dependency security audit", }, "RTK - CLI proxy to reduce LLM token consumption": { "fr": "RTK - Proxy CLI pour réduire la consommation de tokens LLM", "en": "RTK - CLI proxy to reduce LLM token consumption", }, "Language - Change language / Changer la langue": { "fr": "Langue - Changer la langue / Change language", "en": "Language - Change language / Changer la langue", }, # Deploy section "Deploy - Deploy ERPLibre locally": { "fr": "Déploiement - Déployer ERPLibre localement", "en": "Deploy - Deploy ERPLibre locally", }, "Deploy ERPLibre to a local directory!": { "fr": "Déployer ERPLibre dans un répertoire local!", "en": "Deploy ERPLibre to a local directory!", }, "Clone ERPLibre locally (git clone)": { "fr": "Cloner ERPLibre localement (git clone)", "en": "Clone ERPLibre locally (git clone)", }, "Target directory path (default: ~/erplibre): ": { "fr": "Chemin du répertoire cible (défaut: ~/erplibre) : ", "en": "Target directory path (default: ~/erplibre): ", }, "Directory already exists: ": { "fr": "Le répertoire existe déjà : ", "en": "Directory already exists: ", }, "Cloning ERPLibre...": { "fr": "Clonage d'ERPLibre en cours...", "en": "Cloning ERPLibre...", }, "ERPLibre cloned successfully to: ": { "fr": "ERPLibre cloné avec succès dans : ", "en": "ERPLibre cloned successfully to: ", }, "Error cloning ERPLibre: ": { "fr": "Erreur lors du clonage d'ERPLibre : ", "en": "Error cloning ERPLibre: ", }, "Configure sshfs": { "fr": "Configurer sshfs", "en": "Configure sshfs", }, "Local": { "fr": "Local", "en": "Local", }, "SSH (remote host)": { "fr": "SSH (hôte distant)", "en": "SSH (remote host)", }, "Virtualization & notifications": { "fr": "Virtualisation & notifications", "en": "Virtualization & notifications", }, "Development": { "fr": "Développement", "en": "Development", }, "Data": { "fr": "Données", "en": "Data", }, "Sources & documentation": { "fr": "Sources & documentation", "en": "Sources & documentation", }, "AI & automation": { "fr": "IA & automatisation", "en": "AI & automation", }, "Deployment, network & security": { "fr": "Déploiement, réseau & sécurité", "en": "Deployment, network & security", }, "Preferences": { "fr": "Préférences", "en": "Preferences", }, "Deployment": { "fr": "Déploiement", "en": "Deployment", }, "Manage": { "fr": "Gérer", "en": "Manage", }, "Catalog": { "fr": "Catalogue", "en": "Catalog", }, "Open the console on a VM": { "fr": "Ouvrir la console d'une VM", "en": "Open the console on a VM", }, "Backup": { "fr": "Sauvegarde", "en": "Backup", }, "Restore": { "fr": "Restauration", "en": "Restore", }, "Danger zone": { "fr": "Zone dangereuse", "en": "Danger zone", }, "Setup": { "fr": "Installation", "en": "Setup", }, "Status": { "fr": "Statut", "en": "Status", }, "Optimize": { "fr": "Optimisation", "en": "Optimize", }, "Generate": { "fr": "Génération", "en": "Generate", }, "Advanced": { "fr": "Avancé", "en": "Advanced", }, "To leave the console, press Ctrl+] (then Enter).": { "fr": "Pour quitter la console, appuyez sur Ctrl+] (puis Entrée).", "en": "To leave the console, press Ctrl+] (then Enter).", }, "Default login (if set at deploy): erplibre / erplibre": { "fr": "Login par défaut (si défini au déploiement) : " "erplibre / erplibre", "en": "Default login (if set at deploy): erplibre / erplibre", }, "Console password for 'erplibre' (default: erplibre): ": { "fr": "Mot de passe console pour « erplibre » (défaut : erplibre) : ", "en": "Console password for 'erplibre' (default: erplibre): ", }, "Console/SSH login:": { "fr": "Connexion console/SSH :", "en": "Console/SSH login:", }, "Default login:": { "fr": "Login par défaut :", "en": "Default login:", }, "Add this VM to ~/.ssh/config? (y/N): ": { "fr": "Ajouter cette VM à ~/.ssh/config ? (o/N) : ", "en": "Add this VM to ~/.ssh/config? (y/N): ", }, "Add each VM to ~/.ssh/config? (y/N): ": { "fr": "Ajouter chaque VM à ~/.ssh/config ? (o/N) : ", "en": "Add each VM to ~/.ssh/config? (y/N): ", }, "Waiting for the VM IP (DHCP lease)...": { "fr": "Attente de l'IP de la VM (bail DHCP)...", "en": "Waiting for the VM IP (DHCP lease)...", }, "No IP yet; add it later once the VM has booted.": { "fr": "Pas encore d'IP ; à ajouter plus tard une fois la VM démarrée.", "en": "No IP yet; add it later once the VM has booted.", }, "Added to ~/.ssh/config:": { "fr": "Ajouté à ~/.ssh/config :", "en": "Added to ~/.ssh/config:", }, "SSH address input method": { "fr": "Méthode de saisie de l'adresse SSH", "en": "SSH address input method", }, "Manual entry": { "fr": "Saisie manuelle", "en": "Manual entry", }, "From ~/.ssh/config": { "fr": "Depuis ~/.ssh/config", "en": "From ~/.ssh/config", }, "Your choice (1/2): ": { "fr": "Votre choix (1/2) : ", "en": "Your choice (1/2): ", }, "No SSH hosts found in ~/.ssh/config": { "fr": "Aucun hôte SSH trouvé dans ~/.ssh/config", "en": "No SSH hosts found in ~/.ssh/config", }, "Select SSH host number: ": { "fr": "Numéro de l'hôte SSH à sélectionner : ", "en": "Select SSH host number: ", }, "Invalid selection!": { "fr": "Sélection invalide!", "en": "Invalid selection!", }, "SSH host (e.g.: user@192.168.1.100): ": { "fr": "Hôte SSH (ex: user@192.168.1.100) : ", "en": "SSH host (e.g.: user@192.168.1.100): ", }, "SSH host is required!": { "fr": "L'hôte SSH est requis!", "en": "SSH host is required!", }, "Mounting sshfs on: ": { "fr": "Montage sshfs sur : ", "en": "Mounting sshfs on: ", }, "Mounted on: ": { "fr": "Monté sur : ", "en": "Mounted on: ", }, "To unmount: ": { "fr": "Pour démonter : ", "en": "To unmount: ", }, "Error mounting sshfs: ": { "fr": "Erreur lors du montage sshfs : ", "en": "Error mounting sshfs: ", }, # RTK (Rust Token Killer) "Manage RTK (Rust Token Killer) for token optimization!": { "fr": "Gérer RTK (Rust Token Killer) pour optimiser les tokens!", "en": "Manage RTK (Rust Token Killer) for token optimization!", }, "Install RTK": { "fr": "Installer RTK", "en": "Install RTK", }, "Check RTK version": { "fr": "Vérifier la version de RTK", "en": "Check RTK version", }, "Show cumulative token savings": { "fr": "Afficher les économies de tokens cumulées", "en": "Show cumulative token savings", }, "Discover optimization opportunities": { "fr": "Identifier les opportunités d'optimisation", "en": "Discover optimization opportunities", }, "Initialize global auto-rewrite hook": { "fr": "Initialiser le hook auto-rewrite global", "en": "Initialize global auto-rewrite hook", }, "Check RTK status": { "fr": "Vérifier le statut de RTK", "en": "Check RTK status", }, "RTK is not installed. Use option 1 to install it.": { "fr": "RTK n'est pas installé. Utilisez l'option 1 pour l'installer.", "en": "RTK is not installed. Use option 1 to install it.", }, "RTK is installed, version: ": { "fr": "RTK est installé, version : ", "en": "RTK is installed, version: ", }, "Global auto-rewrite hook: active": { "fr": "Hook auto-rewrite global : actif", "en": "Global auto-rewrite hook: active", }, "Global auto-rewrite hook: inactive": { "fr": "Hook auto-rewrite global : inactif", "en": "Global auto-rewrite hook: inactive", }, "Installation method:": { "fr": "Méthode d'installation :", "en": "Installation method:", }, "curl - Automatic install script": { "fr": "curl - Script d'installation automatique", "en": "curl - Automatic install script", }, "brew - Homebrew (macOS/Linux)": { "fr": "brew - Homebrew (macOS/Linux)", "en": "brew - Homebrew (macOS/Linux)", }, "cargo - Build from source (Rust required)": { "fr": "cargo - Compilation depuis les sources (Rust requis)", "en": "cargo - Build from source (Rust required)", }, # Prompts and messages "Enter your password: ": { "fr": "Entrez votre mot de passe : ", "en": "Enter your password: ", }, "Write your question ": { "fr": "Écrit moi ta question ", "en": "Write your question ", }, "Do you want a new instance?": { "fr": "Voulez-vous une nouvelle instance?", "en": "Do you want a new instance?", }, "SSH port-forwarding": { "fr": "SSH port-forwarding", "en": "SSH port-forwarding", }, "Network performance request per second": { "fr": "Performance réseau en requêtes par seconde", "en": "Network performance request per second", }, "Setup queue job for parallelism": { "fr": "Configurer la file d'attente pour l'exécution parallèle", "en": "Setup queue job for parallelism", }, "Choose your database": { "fr": "Choisir sa base de données", "en": "Choose your database", }, "Development update": { "fr": "Mise à jour du développement", "en": "Development update", }, "What do you need for development?": { "fr": "Qu'avez-vous de besoin pour développer?", "en": "What do you need for development?", }, "Looking for documentation?": { "fr": "Vous cherchez de la documentation?", "en": "Looking for documentation?", }, "Make changes to databases!": { "fr": "Faites des modifications sur les bases de données!", "en": "Make changes to databases!", }, # Database drop / erase "Erase a database": { "fr": "Effacer une base de données", "en": "Erase a database", }, "Erase a database — irreversible operation!": { "fr": "Effacer une base de données — opération irréversible !", "en": "Erase a database — irreversible operation!", }, "Erase ALL databases (make db_drop_all)": { "fr": "Effacer TOUTES les bases de données (make db_drop_all)", "en": "Erase ALL databases (make db_drop_all)", }, "Erase a single database": { "fr": "Effacer une seule base de données", "en": "Erase a single database", }, "You are about to erase ALL databases. This cannot be undone.": { "fr": ( "Tu es sur le point d'effacer TOUTES les bases de données." " C'est irréversible." ), "en": "You are about to erase ALL databases. This cannot be undone.", }, "You are about to erase the database '{database}'. This cannot be undone.": { "fr": ( "Tu es sur le point d'effacer la base de données « {database} »." " C'est irréversible." ), "en": ( "You are about to erase the database '{database}'." " This cannot be undone." ), }, "Type 'oui' to confirm (default: no): ": { "fr": "Tape « oui » pour confirmer (défaut : non) : ", "en": "Type 'oui'/'yes' to confirm (default: no): ", }, "Database deletion cancelled.": { "fr": "Effacement de la base de données annulé.", "en": "Database deletion cancelled.", }, "No database selected.": { "fr": "Aucune base de données sélectionnée.", "en": "No database selected.", }, "Manage execution processes!": { "fr": "Manipuler les processus d'exécution!", "en": "Manage execution processes!", }, "Manage ERPLibre and Odoo configuration!": { "fr": "Manipuler la configuration ERPLibre et Odoo!", "en": "Manage ERPLibre and Odoo configuration!", }, "Network tools!": { "fr": "Outil réseautique!", "en": "Network tools!", }, "Dependency security audit!": { "fr": "Audit de securite des dépendances!", "en": "Dependency security audit!", }, "The Bash script failed with return code": { "fr": "Le script Bash a échoué avec le code de retour", "en": "The Bash script failed with return code", }, "No installed environment found. Install an Odoo version first.": { "fr": "Aucun environnement installe trouve. Installez d'abord une version d'Odoo.", "en": "No installed environment found. Install an Odoo version first.", }, "Choose an environment for the audit:": { "fr": "Choisir un environnement pour l'audit :", "en": "Choose an environment for the audit:", }, "Select: ": { "fr": "Sélection : ", "en": "Select: ", }, "Error, cannot understand value": { "fr": "Erreur, impossible de comprendre la valeur", "en": "Error, cannot understand value", }, "Dependencies file not found: ": { "fr": "Fichier de dépendances introuvable : ", "en": "Dependencies file not found: ", }, "Execution: ": { "fr": "Execution : ", "en": "Execution: ", }, "Current": { "fr": "Actuel", "en": "Current", }, "Default": { "fr": "Défaut", "en": "Default", }, "Reboot TODO ...": { "fr": "Reboot TODO ...", "en": "Reboot TODO ...", }, "pip-audit - Check vulnerabilities on Python environments": { "fr": "pip-audit - Verifier les vulnérabilités sur les environnements Python", "en": "pip-audit - Check vulnerabilities on Python environments", }, "Will execute:": { "fr": "Va exécuter :", "en": "Will execute:", }, "Choose a version:": { "fr": "Choisir une version :", "en": "Choose a version:", }, "Install type:": { "fr": "Type d'installation :", "en": "Install type:", }, "Standard install (without extra modules)": { "fr": "Installation standard (sans modules extra)", "en": "Standard install (without extra modules)", }, "Install with extra modules (CybroOdoo - large, slow)": { "fr": "Installation avec modules extra (CybroOdoo - gros, lent)", "en": "Install with extra modules (CybroOdoo - large, slow)", }, # todo.json translatable prompt_descriptions "Test - Minimal base instance": { "fr": "Test - Instance de base minimale", "en": "Test - Minimal base instance", }, "Open RobotLibre 🤖 minimal": { "fr": "Ouvrir RobotLibre 🤖 minimal", "en": "Open RobotLibre 🤖 minimal", }, "Open RobotLibre 🤖 with search enabled": { "fr": "Ouvrir RobotLibre 🤖 en activant la recherche", "en": "Open RobotLibre 🤖 with search enabled", }, "Open ERPLibre with TODO 🤖": { "fr": "Ouvrir ERPLibre avec TODO 🤖", "en": "Open ERPLibre with TODO 🤖", }, "Update all erplibre_base on database test": { "fr": "Mise à jour de tous les erplibre_base sur la base de données test", "en": "Update all erplibre_base on database test", }, "Show code status": { "fr": "Afficher le statut du code", "en": "Show code status", }, "Stash all code": { "fr": "Remiser tout le code", "en": "Stash all code", }, "Format modified code": { "fr": "Formater le code modifié", "en": "Format modified code", }, # todo.py hardcoded prompt_descriptions "Mobile - Compile and run software": { "fr": "Mobile - Compiler et exécuter le logiciel", "en": "Mobile - Compile and run software", }, "Upgrade Odoo - Migration Database": { "fr": "Mise à jour Odoo - Migration de base de données", "en": "Upgrade Odoo - Migration Database", }, "Upgrade Poetry - Dependency of Odoo": { "fr": "Mise à jour Poetry - Dépendances d'Odoo", "en": "Upgrade Poetry - Dependency of Odoo", }, "Open SHELL": { "fr": "Ouvrir le SHELL", "en": "Open SHELL", }, "Upgrade Module": { "fr": "Mise à jour de module", "en": "Upgrade Module", }, "Debug": { "fr": "Débogage", "en": "Debug", }, "Migration module coverage": { "fr": "Couverture de migration des modules", "en": "Migration module coverage", }, "What change between version": { "fr": "Quels changements entre les versions", "en": "What change between version", }, "OCA guidelines": { "fr": "Directives OCA", "en": "OCA guidelines", }, "OCA migration Odoo 19 milestone": { "fr": "Migration OCA Odoo 19 - Jalons", "en": "OCA migration Odoo 19 milestone", }, "Download database to create backup (.zip)": { "fr": "Télécharger une base de données pour créer une sauvegarde (.zip)", "en": "Download database to create backup (.zip)", }, "Restore from backup (.zip)": { "fr": "Restaurer a partir d'une sauvegarde (.zip)", "en": "Restore from backup (.zip)", }, "Create backup (.zip)": { "fr": "Créer une sauvegarde (.zip)", "en": "Create backup (.zip)", }, "Kill Odoo process from actual port": { "fr": "Terminer le processus Odoo du port actuel", "en": "Kill Odoo process from actual port", }, "Kill git daemon server process": { "fr": "Terminer le processus du serveur git daemon", "en": "Kill git daemon server process", }, "Git daemon process killed.": { "fr": "Processus git daemon terminé.", "en": "Git daemon process killed.", }, "Generate all configuration": { "fr": "Générer toute la configuration", "en": "Generate all configuration", }, "Generate from pre-configuration": { "fr": "Générer a partir de la pre-configuration", "en": "Generate from pre-configuration", }, "Generate from backup file": { "fr": "Générer a partir d'un fichier de sauvegarde", "en": "Generate from backup file", }, "Generate from database": { "fr": "Générer a partir de la base de données", "en": "Generate from database", }, "base": { "fr": "base", "en": "base", }, "base + code_generator": { "fr": "base + code_generator", "en": "base + code_generator", }, "base + image_db": { "fr": "base + image_db", "en": "base + image_db", }, "all": { "fr": "tout", "en": "all", }, "Debug todo.py": { "fr": "Débogage todo.py", "en": "Debug todo.py", }, # Test section "Test - Test an Odoo module": { "fr": "Test - Tester un module Odoo", "en": "Test - Test an Odoo module", }, "Test an Odoo module on a temporary database!": { "fr": "Tester un module Odoo sur une base de données temporaire!", "en": "Test an Odoo module on a temporary database!", }, "Test a module": { "fr": "Tester un module", "en": "Test a module", }, "Test a module with code coverage": { "fr": "Tester un module avec couverture de code", "en": "Test a module with code coverage", }, "ERPLibre unit tests": { "fr": "Tests unitaires ERPLibre", "en": "ERPLibre unit tests", }, "Running unit tests": { "fr": "Exécution des tests unitaires", "en": "Running unit tests", }, "All unit tests passed": { "fr": "Tous les tests unitaires ont réussi", "en": "All unit tests passed", }, "Some unit tests failed, exit code": { "fr": "Des tests unitaires ont échoué, code de sortie", "en": "Some unit tests failed, exit code", }, "Module name to test: ": { "fr": "Nom du module à tester : ", "en": "Module name to test: ", }, "Temporary database name (default: test_todo_tmp): ": { "fr": "Nom de la base de données temporaire (défaut: test_todo_tmp) : ", "en": "Temporary database name (default: test_todo_tmp): ", }, "Extra modules to install (comma-separated, empty for none): ": { "fr": "Modules supplémentaires à installer (séparés par des virgules, vide pour aucun) : ", "en": "Extra modules to install (comma-separated, empty for none): ", }, "Log level (default: test): ": { "fr": "Niveau de log (défaut: test) : ", "en": "Log level (default: test): ", }, "Creating temporary database": { "fr": "Création de la base de données temporaire", "en": "Creating temporary database", }, "Installing modules": { "fr": "Installation des modules", "en": "Installing modules", }, "Running tests": { "fr": "Exécution des tests", "en": "Running tests", }, "Cleaning up temporary database": { "fr": "Suppression de la base de données temporaire", "en": "Cleaning up temporary database", }, "Keep the temporary database? (y/N): ": { "fr": "Conserver la base de données temporaire? (o/N) : ", "en": "Keep the temporary database? (y/N): ", }, "Database kept": { "fr": "Base de données conservée", "en": "Database kept", }, "Tests completed successfully!": { "fr": "Tests terminés avec succès!", "en": "Tests completed successfully!", }, "Tests failed with return code": { "fr": "Les tests ont échoué avec le code de retour", "en": "Tests failed with return code", }, "Module name is required!": { "fr": "Le nom du module est requis!", "en": "Module name is required!", }, # Git section "Git - Git tools": { "fr": "Git - Outils Git", "en": "Git - Git tools", }, "Git management tools!": { "fr": "Outils de gestion Git!", "en": "Git management tools!", }, "Local git server": { "fr": "Serveur git local", "en": "Local git server", }, "Manage local git repository server!": { "fr": "Gérer le serveur de dépôts git local!", "en": "Manage local git repository server!", }, "Deploy a local git server (~/.git-server)": { "fr": "Déployer un serveur git local (~/.git-server)", "en": "Deploy a local git server (~/.git-server)", }, "Deploy a production git server (/srv/git, root required)": { "fr": "Déployer un serveur git production (/srv/git, root requis)", "en": "Deploy a production git server (/srv/git, root required)", }, "Starting git server deployment...": { "fr": "Démarrage du déploiement du serveur git...", "en": "Starting git server deployment...", }, "Local mode (~/.git-server)": { "fr": "Mode local (~/.git-server)", "en": "Local mode (~/.git-server)", }, "Production mode (/srv/git, root required)": { "fr": "Mode production (/srv/git, root requis)", "en": "Production mode (/srv/git, root required)", }, "Run all (init + remote + push + serve)": { "fr": "Tout exécuter (init + remote + push + serve)", "en": "Run all (init + remote + push + serve)", }, "Init - Create bare repos": { "fr": "Init - Créer les bare repos", "en": "Init - Create bare repos", }, "Remote - Add local remotes": { "fr": "Remote - Ajouter les remotes locaux", "en": "Remote - Add local remotes", }, "Push - Push to local server": { "fr": "Push - Pousser vers le serveur local", "en": "Push - Push to local server", }, "Serve - Start git daemon": { "fr": "Serve - Démarrer le daemon git", "en": "Serve - Start git daemon", }, # Git remote add "Add a remote to a local repository": { "fr": "Ajouter un remote vers un dépôt local", "en": "Add a remote to a local repository", }, "Remote name (default: localhost): ": { "fr": "Nom du remote (défaut: localhost) : ", "en": "Remote name (default: localhost): ", }, "Repository address (e.g.: git://192.168.1.100/my-repo.git): ": { "fr": "Adresse du dépôt (ex: git://192.168.1.100/mon-repo.git) : ", "en": "Repository address (e.g.: git://192.168.1.100/my-repo.git): ", }, "Repository address is required!": { "fr": "L'adresse du dépôt est requise!", "en": "Repository address is required!", }, "Remote added successfully!": { "fr": "Remote ajouté avec succès!", "en": "Remote added successfully!", }, "Error adding remote: ": { "fr": "Erreur lors de l'ajout du remote : ", "en": "Error adding remote: ", }, # Git config vim "Configure git local editor to vim": { "fr": "Configuration git local par vim", "en": "Configure git local editor to vim", }, "Generate git patch to /tmp": { "fr": "Générer une patch git dans /tmp", "en": "Generate git patch to /tmp", }, "Git editor configured to vim successfully!": { "fr": "Éditeur git configuré sur vim avec succès!", "en": "Git editor configured to vim successfully!", }, "Error during configuration: ": { "fr": "Erreur lors de la configuration : ", "en": "Error during configuration: ", }, # GPT code - Claude automation "Add an automation with Claude in todo.py": { "fr": "Ajouter une automatisation avec Claude dans todo.py", "en": "Add an automation with Claude in todo.py", }, "Description of the command to add: ": { "fr": "Description de la commande à ajouter : ", "en": "Description of the command to add: ", }, "Bash command to execute: ": { "fr": "Commande bash à exécuter : ", "en": "Bash command to execute: ", }, "Menu section (git/code/config/network/process): ": { "fr": "Section du menu (git/code/config/network/process) : ", "en": "Menu section (git/code/config/network/process): ", }, "Automation added successfully in todo.json!": { "fr": "Automatisation ajoutée avec succès dans todo.json!", "en": "Automation added successfully in todo.json!", }, "Error adding automation: ": { "fr": "Erreur lors de l'ajout de l'automatisation : ", "en": "Error adding automation: ", }, # SSH Deploy section "Deploy - Deploy ERPLibre via SSH": { "fr": "Déploiement - Déployer ERPLibre via SSH", "en": "Deploy - Deploy ERPLibre via SSH", }, "SSH deployment tools!": { "fr": "Outils de déploiement SSH!", "en": "SSH deployment tools!", }, "SSH - Check connection": { "fr": "SSH - Vérifier la connexion", "en": "SSH - Check connection", }, "SSH - Sync files (rsync)": { "fr": "SSH - Synchroniser les fichiers (rsync)", "en": "SSH - Sync files (rsync)", }, "SSH - Install ERPLibre": { "fr": "SSH - Installer ERPLibre", "en": "SSH - Install ERPLibre", }, "SSH - Start Odoo": { "fr": "SSH - Démarrer Odoo", "en": "SSH - Start Odoo", }, "SSH - Stop Odoo": { "fr": "SSH - Arrêter Odoo", "en": "SSH - Stop Odoo", }, "SSH - Restart Odoo": { "fr": "SSH - Redémarrer Odoo", "en": "SSH - Restart Odoo", }, "SSH - Service status": { "fr": "SSH - Statut du service", "en": "SSH - Service status", }, "SSH - View logs": { "fr": "SSH - Voir les logs", "en": "SSH - View logs", }, "SSH - Run make target": { "fr": "SSH - Exécuter une cible make", "en": "SSH - Run make target", }, "SSH - Install systemd service": { "fr": "SSH - Installer le service systemd", "en": "SSH - Install systemd service", }, "SSH - Configure nginx + SSL": { "fr": "SSH - Configurer nginx + SSL", "en": "SSH - Configure nginx + SSL", }, "Remote host (user@hostname or hostname): ": { "fr": "Hôte distant (user@hostname ou hostname) : ", "en": "Remote host (user@hostname or hostname): ", }, "SSH user (default: erplibre): ": { "fr": "Utilisateur SSH (défaut: erplibre) : ", "en": "SSH user (default: erplibre): ", }, "SSH port (default: 22): ": { "fr": "Port SSH (défaut: 22) : ", "en": "SSH port (default: 22): ", }, "SSH key path (default: ~/.ssh/id_rsa, empty for none): ": { "fr": "Chemin de la clé SSH (défaut: ~/.ssh/id_rsa, vide pour aucune) : ", "en": "SSH key path (default: ~/.ssh/id_rsa, empty for none): ", }, "Remote path (default: ~/erplibre_deploy_2): ": { "fr": "Chemin distant (défaut: ~/erplibre_deploy_2) : ", "en": "Remote path (default: ~/erplibre_deploy_2): ", }, "Make target to run remotely: ": { "fr": "Cible make à exécuter à distance : ", "en": "Make target to run remotely: ", }, "Domain name (e.g.: example.com): ": { "fr": "Nom de domaine (ex: example.com) : ", "en": "Domain name (e.g.: example.com): ", }, "Admin email for SSL certificate: ": { "fr": "Email administrateur pour le certificat SSL : ", "en": "Admin email for SSL certificate: ", }, "SSH host is required!": { "fr": "L'hôte SSH est requis!", "en": "SSH host is required!", }, # Language selection "Choose language / Choisir la langue": { "fr": "Choisir la langue / Choose language", "en": "Choose language / Choisir la langue", }, "French": { "fr": "Francais", "en": "French", }, "English": { "fr": "Anglais", "en": "English", }, "Language changed to: English": { "fr": "Langue changée pour : Francais", "en": "Language changed to: English", }, "TODO execution time": { "fr": "Temps d'exécution TODO", "en": "TODO execution time", }, "Keyboard interrupt": { "fr": "Interruption clavier", "en": "Keyboard interrupt", }, # GPT code section "GPT code - AI assistant tools": { "fr": "GPT code - Outils d'assistant IA", "en": "GPT code - AI assistant tools", }, "AI assistant tools for development!": { "fr": "Outils d'assistant IA pour le développement!", "en": "AI assistant tools for development!", }, "Configure Claude Code configurations": { "fr": "Configurer les configurations Claude Code", "en": "Configure Claude Code configurations", }, "Commit - OCA/Odoo commit command": { "fr": "Commit - Commande de commit OCA/Odoo", "en": "Commit - OCA/Odoo commit command", }, "Todo Add Command - Add a command to todo.py menu": { "fr": "Todo Add Command - Ajouter une commande au menu todo.py", "en": "Todo Add Command - Add a command to todo.py menu", }, "Enter your full name: ": { "fr": "Entrez votre nom complet : ", "en": "Enter your full name: ", }, "Enter your email: ": { "fr": "Entrez votre courriel : ", "en": "Enter your email: ", }, "Deploy Claude Code commands!": { "fr": "Déployer les commandes Claude Code!", "en": "Deploy Claude Code commands!", }, "Show installed custom commands": { "fr": "Afficher les commandes personnalisées installées", "en": "Show installed custom commands", }, "No custom commands found in ~/.claude/commands/": { "fr": "Aucune commande personnalisée trouvée dans ~/.claude/commands/", "en": "No custom commands found in ~/.claude/commands/", }, "Claude Code custom commands:": { "fr": "Commandes personnalisées Claude Code :", "en": "Claude Code custom commands:", }, "Total:": { "fr": "Total :", "en": "Total:", }, "File already exists: ": { "fr": "Le fichier existe déjà : ", "en": "File already exists: ", }, "Do you want to overwrite the file? (y/Y): ": { "fr": "Voulez-vous écraser le fichier? (y/Y) : ", "en": "Do you want to overwrite the file? (y/Y): ", }, "Nothing to do.": { "fr": "Rien à faire.", "en": "Nothing to do.", }, "File created successfully: ": { "fr": "Fichier créé avec succès : ", "en": "File created successfully: ", }, "Error creating file: ": { "fr": "Erreur lors de la création du fichier : ", "en": "Error creating file: ", }, # NTFY section "Deploy - Install NTFY notification server": { "fr": "Déployer - Installer le serveur de notifications NTFY", "en": "Deploy - Install NTFY notification server", }, "Deploy a local NTFY push notification server (Ubuntu/Arch)": { "fr": "Déployer un serveur local de notifications NTFY (Ubuntu/Arch)", "en": "Deploy a local NTFY push notification server (Ubuntu/Arch)", }, "NTFY server port (default: 8080): ": { "fr": "Port du serveur NTFY (défaut : 8080) : ", "en": "NTFY server port (default: 8080): ", }, "NTFY base URL": { "fr": "URL de base NTFY", "en": "NTFY base URL", }, "Installing NTFY server (requires sudo)...": { "fr": "Installation du serveur NTFY (sudo requis)...", "en": "Installing NTFY server (requires sudo)...", }, "NTFY server installed and started successfully!": { "fr": "Serveur NTFY installé et démarré avec succès!", "en": "NTFY server installed and started successfully!", }, "Error installing NTFY server: ": { "fr": "Erreur lors de l'installation du serveur NTFY : ", "en": "Error installing NTFY server: ", }, "NTFY install script not found: ": { "fr": "Script d'installation NTFY introuvable : ", "en": "NTFY install script not found: ", }, # QEMU / KVM (libvirt) VM deployment "QEMU/KVM - Deploy an Ubuntu VM (libvirt)": { "fr": "QEMU/KVM - Déployer une VM Ubuntu (libvirt)", "en": "QEMU/KVM - Deploy an Ubuntu VM (libvirt)", }, "Deploy a QEMU/KVM virtual machine (libvirt)!": { "fr": "Déployer une machine virtuelle QEMU/KVM (libvirt) !", "en": "Deploy a QEMU/KVM virtual machine (libvirt)!", }, "QEMU deploy script not found: ": { "fr": "Script de déploiement QEMU introuvable : ", "en": "QEMU deploy script not found: ", }, "Deploy a new VM": { "fr": "Déployer une nouvelle VM", "en": "Deploy a new VM", }, "Preview a deployment (dry-run, no sudo)": { "fr": "Prévisualiser un déploiement (dry-run, sans sudo)", "en": "Preview a deployment (dry-run, no sudo)", }, "Download a cloud image only": { "fr": "Télécharger seulement une image cloud", "en": "Download a cloud image only", }, "List VMs (virsh list --all)": { "fr": "Lister les VM (virsh list --all)", "en": "List VMs (virsh list --all)", }, "Show a VM IP address": { "fr": "Afficher l'adresse IP d'une VM", "en": "Show a VM IP address", }, "List available images and specs": { "fr": "Lister les images disponibles et leurs specs", "en": "List available images and specs", }, "Distribution:": { "fr": "Distribution :", "en": "Distribution:", }, "Choice (number or name, default: ubuntu): ": { "fr": "Choix (numéro ou nom, défaut : ubuntu) : ", "en": "Choice (number or name, default: ubuntu): ", }, "Invalid selection, using ubuntu": { "fr": "Sélection invalide, utilisation d'ubuntu", "en": "Invalid selection, using ubuntu", }, "Version for": { "fr": "Version pour", "en": "Version for", }, "Choice (number or version, blank = default):": { "fr": "Choix (numéro ou version, vide = défaut) :", "en": "Choice (number or version, blank = default):", }, "Invalid selection, using": { "fr": "Sélection invalide, utilisation de", "en": "Invalid selection, using", }, "select all": { "fr": "tout sélectionner", "en": "select all", }, "Delete VM(s)": { "fr": "Effacer une ou plusieurs VM", "en": "Delete VM(s)", }, "No VM found.": { "fr": "Aucune VM trouvée.", "en": "No VM found.", }, "Select VMs to delete:": { "fr": "Sélectionner les VM à effacer :", "en": "Select VMs to delete:", }, "Selection (numbers, or 'all'): ": { "fr": "Sélection (numéros, ou « all ») : ", "en": "Selection (numbers, or 'all'): ", }, "Also delete disk images (qcow2 + seed ISO)? (y/N): ": { "fr": "Effacer aussi les disques (qcow2 + seed ISO) ? (o/N) : ", "en": "Also delete disk images (qcow2 + seed ISO)? (y/N): ", }, "Will delete:": { "fr": "Sera effacé :", "en": "Will delete:", }, "disk images and seed ISOs": { "fr": "les disques et les seed ISO", "en": "disk images and seed ISOs", }, "disks kept": { "fr": "disques conservés", "en": "disks kept", }, "Confirm deletion? (y/N): ": { "fr": "Confirmer l'effacement ? (o/N) : ", "en": "Confirm deletion? (y/N): ", }, "Deletion done.": { "fr": "Effacement terminé.", "en": "Deletion done.", }, "Deploy ERPLibre infra (one minimal VM per image)": { "fr": "Déployer l'infra ERPLibre (une VM minimale par image)", "en": "Deploy ERPLibre infra (one minimal VM per image)", }, "Deploy ERPLibre infra: one minimal VM per image": { "fr": "Déployer l'infra ERPLibre : une VM minimale par image", "en": "Deploy ERPLibre infra: one minimal VM per image", }, "Cannot load QEMU catalog: ": { "fr": "Impossible de charger le catalogue QEMU : ", "en": "Cannot load QEMU catalog: ", }, "Distributions:": { "fr": "Distributions :", "en": "Distributions:", }, "Whole catalog (every version)": { "fr": "Tout le catalogue (chaque version)", "en": "Whole catalog (every version)", }, "Selection (numbers, or 'all', default: all): ": { "fr": "Sélection (numéros, ou « all », défaut : all) : ", "en": "Selection (numbers, or 'all', default: all): ", }, "Nothing selected.": { "fr": "Rien de sélectionné.", "en": "Nothing selected.", }, "Deployment plan": { "fr": "Plan de déploiement", "en": "Deployment plan", }, "disk": { "fr": "disque", "en": "disk", }, "Total RAM (all running):": { "fr": "RAM totale (toutes actives) :", "en": "Total RAM (all running):", }, "Total virtual disk (thin qcow2):": { "fr": "Disque virtuel total (qcow2 thin) :", "en": "Total virtual disk (thin qcow2):", }, "Host RAM available:": { "fr": "RAM disponible de l'hôte :", "en": "Host RAM available:", }, "Total RAM exceeds host free RAM: not all VMs will run at once.": { "fr": "La RAM totale dépasse la RAM libre de l'hôte : les VM ne " "tourneront pas toutes en même temps.", "en": "Total RAM exceeds host free RAM: not all VMs will run at once.", }, "Install ERPLibre into ~/git/erplibre on each VM? (y/N): ": { "fr": "Installer ERPLibre dans ~/git/erplibre sur chaque VM ? (o/N) : ", "en": "Install ERPLibre into ~/git/erplibre on each VM? (y/N): ", }, "Deploy these VMs now? (y/N): ": { "fr": "Déployer ces VM maintenant ? (o/N) : ", "en": "Deploy these VMs now? (y/N): ", }, "Cancelled.": { "fr": "Annulé.", "en": "Cancelled.", }, "already exists, skipped.": { "fr": "existe déjà, ignorée.", "en": "already exists, skipped.", }, "Cloning ERPLibre on each VM": { "fr": "Clonage d'ERPLibre sur chaque VM", "en": "Cloning ERPLibre on each VM", }, "Parallel deployments (default:": { "fr": "Déploiements en parallèle (défaut :", "en": "Parallel deployments (default:", }, "Deploying": { "fr": "Déploiement de", "en": "Deploying", }, "parallel jobs:": { "fr": "tâches parallèles :", "en": "parallel jobs:", }, "ERPLibre infra deployment done.": { "fr": "Déploiement de l'infra ERPLibre terminé.", "en": "ERPLibre infra deployment done.", }, "Manage with:": { "fr": "Gérer avec :", "en": "Manage with:", }, "Fetching ERPLibre branch list...": { "fr": "Récupération de la liste des branches ERPLibre...", "en": "Fetching ERPLibre branch list...", }, "Branch (default:": { "fr": "Branche (défaut :", "en": "Branch (default:", }, "Branches:": { "fr": "Branches :", "en": "Branches:", }, "Choice (number or name, default:": { "fr": "Choix (numéro ou nom, défaut :", "en": "Choice (number or name, default:", }, "no IP obtained, ERPLibre clone skipped.": { "fr": "aucune IP obtenue, clonage ERPLibre ignoré.", "en": "no IP obtained, ERPLibre clone skipped.", }, "cloning ERPLibre": { "fr": "clonage d'ERPLibre", "en": "cloning ERPLibre", }, "VM name (required): ": { "fr": "Nom de la VM (requis) : ", "en": "VM name (required): ", }, "VM name is required!": { "fr": "Le nom de la VM est requis !", "en": "VM name is required!", }, "VM name: ": { "fr": "Nom de la VM : ", "en": "VM name: ", }, "VM name or ID: ": { "fr": "Nom ou ID de la VM : ", "en": "VM name or ID: ", }, "VM name or ID (or 'all'): ": { "fr": "Nom ou ID de la VM (ou « all ») : ", "en": "VM name or ID (or 'all'): ", }, "RAM in MB (blank = version minimum): ": { "fr": "RAM en Mo (vide = minimum de la version) : ", "en": "RAM in MB (blank = version minimum): ", }, "vCPUs (default: 2): ": { "fr": "vCPU (défaut : 2) : ", "en": "vCPUs (default: 2): ", }, "Disk size (blank = version minimum): ": { "fr": "Taille du disque (vide = minimum de la version) : ", "en": "Disk size (blank = version minimum): ", }, "SSH public key path": { "fr": "Chemin de la clé publique SSH", "en": "SSH public key path", }, "none": { "fr": "aucune", "en": "none", }, "No SSH key found. Set a password instead? (Y/n): ": { "fr": "Aucune clé SSH trouvée. Définir un mot de passe ? (O/n) : ", "en": "No SSH key found. Set a password instead? (Y/n): ", }, "Overwrite existing VM disk if present? (y/N): ": { "fr": "Écraser le disque de la VM s'il existe ? (o/N) : ", "en": "Overwrite existing VM disk if present? (y/N): ", }, "Verify SHA256 after download? (y/N): ": { "fr": "Vérifier le SHA256 après téléchargement ? (o/N) : ", "en": "Verify SHA256 after download? (y/N): ", }, "QEMU - Sample dry-run (demo-vm, Ubuntu 24.04)": { "fr": "QEMU - Exemple dry-run (demo-vm, Ubuntu 24.04)", "en": "QEMU - Sample dry-run (demo-vm, Ubuntu 24.04)", }, } def get_lang() -> str: global _current_lang if _current_lang is not None: return _current_lang # 1. Check env_var.sh file if os.path.exists(ENV_VAR_FILE): try: with open(ENV_VAR_FILE) as f: content = f.read() match = re.search( r'^EL_LANG=["\']?(\w+)["\']?', content, re.MULTILINE ) if match: lang = match.group(1) if lang in ("fr", "en"): _current_lang = lang return _current_lang except OSError: pass # 2. Check env var env_lang = os.environ.get("EL_LANG") if env_lang in ("fr", "en"): _current_lang = env_lang return _current_lang # 3. Default _current_lang = "fr" return _current_lang def set_lang(lang: str) -> None: global _current_lang _current_lang = lang # Persist to env_var.sh if os.path.exists(ENV_VAR_FILE): try: with open(ENV_VAR_FILE) as f: content = f.read() except OSError: return new_line = f'EL_LANG="{lang}"' if re.search(r"^EL_LANG=", content, re.MULTILINE): content = re.sub( r'^EL_LANG=["\']?\w*["\']?', new_line, content, count=1, flags=re.MULTILINE, ) else: content = content.rstrip("\n") + "\n" + new_line + "\n" with open(ENV_VAR_FILE, "w") as f: f.write(content) def lang_is_configured() -> bool: """Check if a language has been explicitly set.""" if os.path.exists(ENV_VAR_FILE): try: with open(ENV_VAR_FILE) as f: content = f.read() return bool(re.search(r"^EL_LANG=", content, re.MULTILINE)) except OSError: pass return False def t(key: str) -> str: entry = TRANSLATIONS.get(key) if entry is None: return key lang = get_lang() return entry.get(lang, entry.get("fr", key))