erplibre/script/todo/todo_i18n.py
Mathieu Benoit 935919e07b [IMP] script todo: add QEMU/KVM VM deploy menu
Expose the QEMU deploy script from the interactive assistant so users
can create, preview, download and manage Ubuntu VMs without memorising
CLI flags. Adds a QEMU/KVM entry under Deploy, its fr/en translations,
and an extensible qemu_from_makefile section in todo.json.

Generated by Claude Code 2.1.210 claude-opus-4-8

Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
2026-07-15 11:48:12 +00:00

1160 lines
39 KiB
Python

#!/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",
},
"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 Ubuntu VM": {
"fr": "Déployer une nouvelle VM Ubuntu",
"en": "Deploy a new Ubuntu 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 an Ubuntu cloud image only": {
"fr": "Télécharger seulement une image cloud Ubuntu",
"en": "Download an Ubuntu 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",
},
"Ubuntu version:": {
"fr": "Version Ubuntu :",
"en": "Ubuntu version:",
},
"Choice (number or version, default: 24.04): ": {
"fr": "Choix (numéro ou version, défaut : 24.04) : ",
"en": "Choice (number or version, default: 24.04): ",
},
"Invalid selection, using 24.04": {
"fr": "Sélection invalide, utilisation de 24.04",
"en": "Invalid selection, using 24.04",
},
"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: ",
},
"RAM in MB (default: 8192): ": {
"fr": "RAM en Mo (défaut : 8192) : ",
"en": "RAM in MB (default: 8192): ",
},
"vCPUs (default: 4): ": {
"fr": "vCPU (défaut : 4) : ",
"en": "vCPUs (default: 4): ",
},
"Disk size (default: 20G): ": {
"fr": "Taille du disque (défaut : 20G) : ",
"en": "Disk size (default: 20G): ",
},
"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))