From 21104bbce300aa904858c61027fdd33f9874f51e Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 16 Oct 2025 04:55:30 +0000 Subject: [PATCH 1/2] Checkpoint before follow-up message Co-authored-by: maun.aug --- controler/func.php | 1 + controler/functions/translation.php | 170 ++++++++++++++++++++++++++++ lang/en.php | 120 ++++++++++++++++++++ lang/fr.php | 120 ++++++++++++++++++++ view/header.html.php | 44 +++---- 5 files changed, 433 insertions(+), 22 deletions(-) create mode 100644 controler/functions/translation.php create mode 100644 lang/en.php create mode 100644 lang/fr.php diff --git a/controler/func.php b/controler/func.php index b641f57..e616f0b 100755 --- a/controler/func.php +++ b/controler/func.php @@ -21,6 +21,7 @@ require_once __DIR__ . '/functions/tirage.php'; require_once __DIR__ . '/functions/consommation.php'; require_once __DIR__ . '/functions/utilities.php'; +require_once __DIR__ . '/functions/translation.php'; // Définir le mode développement define('DEVELOPMENT_MODE', true); diff --git a/controler/functions/translation.php b/controler/functions/translation.php new file mode 100644 index 0000000..29180dc --- /dev/null +++ b/controler/functions/translation.php @@ -0,0 +1,170 @@ + $param_value) { + $translation = str_replace("{{$param_key}}", $param_value, $translation); + } + } + + return $translation; +} + +/** + * Obtenir la langue actuelle + * + * @return string Code de la langue actuelle + */ +function get_current_language(): string +{ + global $current_language; + return $current_language; +} + +/** + * Obtenir la liste des langues supportées + * + * @return array Liste des codes de langue + */ +function get_supported_languages(): array +{ + return SUPPORTED_LANGUAGES; +} + +/** + * Obtenir le nom de la langue en français + * + * @param string $lang_code Code de la langue + * @return string Nom de la langue + */ +function get_language_name(string $lang_code): string +{ + $names = [ + 'fr' => 'Français', + 'en' => 'English' + ]; + + return $names[$lang_code] ?? $lang_code; +} + +/** + * Générer l'URL pour changer de langue + * + * @param string $lang_code Code de la langue + * @return string URL complète + */ +function get_language_url(string $lang_code): string +{ + $current_url = $_SERVER['REQUEST_URI']; + $parsed_url = parse_url($current_url); + + // Supprimer le paramètre lang existant + if (isset($parsed_url['query'])) { + parse_str($parsed_url['query'], $query_params); + unset($query_params['lang']); + } else { + $query_params = []; + } + + // Ajouter le nouveau paramètre lang + $query_params['lang'] = $lang_code; + + // Reconstruire l'URL + $new_query = http_build_query($query_params); + $new_url = $parsed_url['path']; + if (!empty($new_query)) { + $new_url .= '?' . $new_query; + } + + return $new_url; +} + +// Charger les traductions au chargement du module +load_translations($current_language); + +// Log de l'initialisation +if (function_exists('log_info')) { + log_info("Module de traduction initialisé - Langue: {$current_language}", 'translation.php'); +} +?> \ No newline at end of file diff --git a/lang/en.php b/lang/en.php new file mode 100644 index 0000000..fe16850 --- /dev/null +++ b/lang/en.php @@ -0,0 +1,120 @@ + 'Previous', + 'nav.duplicator' => 'Duplicator.', + 'nav.pdf_tools' => 'PDF Tools', + 'nav.new_print' => 'New Print', + 'nav.change_report' => 'Change Report', + 'nav.help_tutorials' => 'Help & Tutorials', + 'nav.statistics' => 'Statistics', + 'nav.administration' => 'Administration', + + // PDF Tools + 'tools.impose' => 'Impose', + 'tools.impose.description' => 'Create an A3 booklet', + 'tools.unimpose' => 'Unimpose', + 'tools.unimpose.description' => 'Transform a booklet into normal pages', + 'tools.impose_tracts' => 'Tract Imposition', + 'tools.impose_tracts.description' => 'Duplicate and optimize your tracts', + 'tools.images_to_pdf' => 'Images → PDF', + 'tools.images_to_pdf.description' => 'Convert PNG/JPG to PDF A3/A4', + 'tools.pdf_to_images' => 'PDF → Images', + 'tools.pdf_to_images.description' => 'Extract pages as PNG', + 'tools.riso_separator' => 'Riso Separator', + 'tools.riso_separator.description' => 'Separate colors for multi-drum', + 'tools.fill_rate' => 'Fill Rate', + 'tools.fill_rate.description' => 'Calculate ink usage percentage', + + // Home page + 'home.welcome' => 'Welcome duplicator', + 'home.multi_machine_print' => 'Multi-Machine Print', + 'home.multi_machine_print.description' => 'Record your print on all available machines and optimize your prints!', + 'home.useful_info' => 'Useful Information', + 'home.mailing_list' => 'Subscribe to the Mailing List', + 'home.email_placeholder' => 'email', + + // Administration + 'admin.title' => 'Administration', + 'admin.machines.title' => 'Machine Management', + 'admin.machines.manage' => 'Machine Management', + 'admin.machines.manage.description' => 'Duplicators and photocopiers', + 'admin.changes.manage' => 'Change Management', + 'admin.changes.manage.description' => 'Ink, master, toner', + 'admin.prices.manage' => 'Price Management', + 'admin.prices.manage.description' => 'Rates and consumables', + 'admin.prints.manage' => 'Print Management', + 'admin.prints.manage.description' => 'View and modify prints', + + 'admin.content.title' => 'Content Management', + 'admin.help.manage' => 'Help Management', + 'admin.help.manage.description' => 'Help by machine', + 'admin.news.manage' => 'News Management', + 'admin.news.manage.description' => 'News and information', + 'admin.stats.manage' => 'Statistics Management', + 'admin.stats.manage.description' => 'Statistics texts and messages', + 'admin.emails.manage' => 'Email Management', + 'admin.emails.manage.description' => 'Mailing list', + + 'admin.security.title' => 'Security', + 'admin.passwords.manage' => 'Password Management', + 'admin.passwords.manage.description' => 'Security and access', + 'admin.database.manage' => 'Database Management', + 'admin.database.manage.description' => 'Creation, backup, restoration', + + 'admin.back_home' => 'Back to Home', + + // Password management + 'passwords.title' => 'Password Management', + 'passwords.change.title' => 'Change Password', + 'passwords.current' => 'Current password:', + 'passwords.new' => 'New password:', + 'passwords.confirm' => 'Confirm new password:', + 'passwords.min_length' => 'Minimum 6 characters', + 'passwords.change_button' => 'Change Password', + 'passwords.info.title' => 'Information', + 'passwords.security' => 'Security:', + 'passwords.security.stored' => 'Password is stored securely', + 'passwords.security.bcrypt' => 'Uses bcrypt hashing', + 'passwords.security.old_deleted' => 'Old passwords deleted', + 'passwords.recommendations' => 'Recommendations:', + 'passwords.recommendations.length' => 'Use at least 8 characters', + 'passwords.recommendations.mix' => 'Mix letters, numbers and symbols', + 'passwords.recommendations.avoid' => 'Avoid common passwords', + 'passwords.navigation.title' => 'Navigation', + 'passwords.back_admin' => 'Back to Administration', + + // Error messages + 'error.title' => 'An error occurred', + 'error.message' => 'Sorry, an unexpected error occurred while processing your request.', + 'error.technical_details' => 'Technical Details', + 'error.file' => 'File:', + 'error.line' => 'Line:', + 'error.stack_trace' => 'Stack trace:', + 'error.url' => 'URL:', + 'error.what_to_do' => 'What would you like to do?', + 'error.back_home' => 'Back to Home', + 'error.previous_page' => 'Previous Page', + 'error.reload' => 'Reload Page', + + // Footer + 'footer.coded_with_love' => 'Coded with ❤️ for Duplicator. Source:', + 'footer.github' => 'GitHub', + + // Validation messages + 'validation.passwords_not_match' => 'The new passwords do not match.', + 'validation.password_too_short' => 'The new password must contain at least 6 characters.', + 'validation.passwords_not_match_realtime' => 'The passwords do not match.', + + // Languages + 'language.french' => 'Français', + 'language.english' => 'English', + 'language.selector' => 'Language', +]; \ No newline at end of file diff --git a/lang/fr.php b/lang/fr.php new file mode 100644 index 0000000..7e47764 --- /dev/null +++ b/lang/fr.php @@ -0,0 +1,120 @@ + 'Précédent', + 'nav.duplicator' => 'Duplicator.', + 'nav.pdf_tools' => 'Outils PDF', + 'nav.new_print' => 'Nouveau Tirage', + 'nav.change_report' => 'Signalement de changement', + 'nav.help_tutorials' => 'Aide & Tutoriels', + 'nav.statistics' => 'Statistiques', + 'nav.administration' => 'Administration', + + // Outils PDF + 'tools.impose' => 'Imposer', + 'tools.impose.description' => 'Créer un livret A3', + 'tools.unimpose' => 'Désimposer', + 'tools.unimpose.description' => 'Transformer un livret en pages normales', + 'tools.impose_tracts' => 'Imposition Tracts', + 'tools.impose_tracts.description' => 'Dupliquer et optimiser vos tracts', + 'tools.images_to_pdf' => 'Images → PDF', + 'tools.images_to_pdf.description' => 'Convertir PNG/JPG en PDF A3/A4', + 'tools.pdf_to_images' => 'PDF → Images', + 'tools.pdf_to_images.description' => 'Extraire les pages en PNG', + 'tools.riso_separator' => 'Séparateur Riso', + 'tools.riso_separator.description' => 'Séparer couleurs pour multi-tambours', + 'tools.fill_rate' => 'Taux de Remplissage', + 'tools.fill_rate.description' => 'Calculer le % d\'encre utilisé', + + // Page d'accueil + 'home.welcome' => 'Bienvenue duplicateur-euse', + 'home.multi_machine_print' => 'Tirage Multi-Machines', + 'home.multi_machine_print.description' => 'Enregistre ton tirage sur toutes les machines disponibles et optimise tes impressions !', + 'home.useful_info' => 'Informations utiles', + 'home.mailing_list' => 'S\'inscrire à la liste de Diffusion', + 'home.email_placeholder' => 'email', + + // Administration + 'admin.title' => 'Administration', + 'admin.machines.title' => 'Gestion des machines', + 'admin.machines.manage' => 'Gestion des machines', + 'admin.machines.manage.description' => 'Duplicopieurs et photocopieurs', + 'admin.changes.manage' => 'Gestion des changements', + 'admin.changes.manage.description' => 'Encre, master, toner', + 'admin.prices.manage' => 'Gestion des prix', + 'admin.prices.manage.description' => 'Tarifs et consommables', + 'admin.prints.manage' => 'Gestion des tirages', + 'admin.prints.manage.description' => 'Voir et modifier les tirages', + + 'admin.content.title' => 'Gestion du contenu', + 'admin.help.manage' => 'Gestion des aides', + 'admin.help.manage.description' => 'Aides par machine', + 'admin.news.manage' => 'Gestion des infos', + 'admin.news.manage.description' => 'Actualités et informations', + 'admin.stats.manage' => 'Gestion des statistiques', + 'admin.stats.manage.description' => 'Textes et messages des stats', + 'admin.emails.manage' => 'Gestion des emails', + 'admin.emails.manage.description' => 'Liste de diffusion', + + 'admin.security.title' => 'Sécurité', + 'admin.passwords.manage' => 'Gestion des mots de passe', + 'admin.passwords.manage.description' => 'Sécurité et accès', + 'admin.database.manage' => 'Gestion des BDD', + 'admin.database.manage.description' => 'Création, sauvegarde, restauration', + + 'admin.back_home' => 'Retour à l\'accueil', + + // Gestion des mots de passe + 'passwords.title' => 'Gestion des Mots de Passe', + 'passwords.change.title' => 'Changer le mot de passe', + 'passwords.current' => 'Mot de passe actuel :', + 'passwords.new' => 'Nouveau mot de passe :', + 'passwords.confirm' => 'Confirmer le nouveau mot de passe :', + 'passwords.min_length' => 'Minimum 6 caractères', + 'passwords.change_button' => 'Changer le mot de passe', + 'passwords.info.title' => 'Informations', + 'passwords.security' => 'Sécurité :', + 'passwords.security.stored' => 'Le mot de passe est stocké de manière sécurisée', + 'passwords.security.bcrypt' => 'Utilisation de hachage bcrypt', + 'passwords.security.old_deleted' => 'Anciens mots de passe supprimés', + 'passwords.recommendations' => 'Recommandations :', + 'passwords.recommendations.length' => 'Utilisez au moins 8 caractères', + 'passwords.recommendations.mix' => 'Mélangez lettres, chiffres et symboles', + 'passwords.recommendations.avoid' => 'Évitez les mots de passe courants', + 'passwords.navigation.title' => 'Navigation', + 'passwords.back_admin' => 'Retour à l\'administration', + + // Messages d'erreur + 'error.title' => 'Une erreur s\'est produite', + 'error.message' => 'Désolé, une erreur inattendue s\'est produite lors du traitement de votre demande.', + 'error.technical_details' => 'Détails techniques', + 'error.file' => 'Fichier :', + 'error.line' => 'Ligne :', + 'error.stack_trace' => 'Stack trace :', + 'error.url' => 'URL :', + 'error.what_to_do' => 'Que souhaitez-vous faire ?', + 'error.back_home' => 'Retour à l\'accueil', + 'error.previous_page' => 'Page précédente', + 'error.reload' => 'Recharger la page', + + // Footer + 'footer.coded_with_love' => 'Codé avec ❤️ pour Duplicator. Source :', + 'footer.github' => 'GitHub', + + // Messages de validation + 'validation.passwords_not_match' => 'Les nouveaux mots de passe ne correspondent pas.', + 'validation.password_too_short' => 'Le nouveau mot de passe doit contenir au moins 6 caractères.', + 'validation.passwords_not_match_realtime' => 'Les mots de passe ne correspondent pas.', + + // Langues + 'language.french' => 'Français', + 'language.english' => 'English', + 'language.selector' => 'Langue', +]; \ No newline at end of file diff --git a/view/header.html.php b/view/header.html.php index 1ed75ba..c3da182 100755 --- a/view/header.html.php +++ b/view/header.html.php @@ -12,9 +12,9 @@ - Duplicator. + From 96d65de8cf40ff47409793a233ab2990e7a3bd12 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 16 Oct 2025 04:55:43 +0000 Subject: [PATCH 2/2] Add language selector dropdown to header Co-authored-by: maun.aug --- view/header.html.php | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/view/header.html.php b/view/header.html.php index c3da182..80accc6 100755 --- a/view/header.html.php +++ b/view/header.html.php @@ -108,6 +108,26 @@
  • +