From 37779477837c762a41ad5d2ecb554bbe59cf6b98 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Sun, 19 Oct 2025 10:12:57 +0000 Subject: [PATCH 1/7] Checkpoint before follow-up message Co-authored-by: maun.aug --- extract_translations.php | 208 +++++++++++++++++++++++++++++ index.php | 30 ++--- models/admin.php | 10 +- models/admin/AideManager.php | 22 +-- models/admin/ChangesManager.php | 12 +- models/admin/MachineManager.php | 10 +- models/admin/delete_machine.php | 8 +- models/admin_translations.php | 4 +- models/imposition_tracts.php | 12 +- translations/de.json | 62 +++++++++ translations/en.json | 62 +++++++++ translations/es.json | 62 +++++++++ translations/fr.json | 62 ++++++++- view/tirage_multimachines.html.php | 2 +- view/unimpose.html.php | 4 +- 15 files changed, 512 insertions(+), 58 deletions(-) create mode 100644 extract_translations.php diff --git a/extract_translations.php b/extract_translations.php new file mode 100644 index 0000000..4a3db1f --- /dev/null +++ b/extract_translations.php @@ -0,0 +1,208 @@ +basePath = $basePath; + $this->loadExistingTranslations(); + } + + private function loadExistingTranslations() { + $translationFile = $this->basePath . '/translations/fr.json'; + if (file_exists($translationFile)) { + $content = file_get_contents($translationFile); + $this->translations = json_decode($content, true) ?: []; + } + } + + public function extractFromFile($filePath) { + $content = file_get_contents($filePath); + $newTranslations = []; + + // Patterns pour trouver les textes français + $patterns = [ + // echo "texte" + '/echo\s+["\']([A-Za-zÀ-ÿ\s\.,!?;:()\-]{10,})["\']/u', + // print "texte" + '/print\s+["\']([A-Za-zÀ-ÿ\s\.,!?;:()\-]{10,})["\']/u', + // return "texte" + '/return\s+["\']([A-Za-zÀ-ÿ\s\.,!?;:()\-]{10,})["\']/u', + // throw new Exception("texte") + '/throw\s+new\s+Exception\s*\(\s*["\']([A-Za-zÀ-ÿ\s\.,!?;:()\-]{10,})["\']/u', + // 'message' => 'texte' + '/["\']message["\']\s*=>\s*["\']([A-Za-zÀ-ÿ\s\.,!?;:()\-]{10,})["\']/u', + // 'error' => 'texte' + '/["\']error["\']\s*=>\s*["\']([A-Za-zÀ-ÿ\s\.,!?;:()\-]{10,})["\']/u', + // 'success' => 'texte' + '/["\']success["\']\s*=>\s*["\']([A-Za-zÀ-ÿ\s\.,!?;:()\-]{10,})["\']/u', + ]; + + foreach ($patterns as $pattern) { + preg_match_all($pattern, $content, $matches); + foreach ($matches[1] as $match) { + $text = trim($match); + if ($this->isFrenchText($text) && !$this->isAlreadyTranslated($text)) { + $key = $this->generateKey($text, $filePath); + $newTranslations[$key] = $text; + } + } + } + + return $newTranslations; + } + + private function isFrenchText($text) { + // Vérifier si le texte contient des caractères français typiques + $frenchChars = ['à', 'â', 'ä', 'é', 'è', 'ê', 'ë', 'ï', 'î', 'ô', 'ö', 'ù', 'û', 'ü', 'ÿ', 'ç', 'À', 'Â', 'Ä', 'É', 'È', 'Ê', 'Ë', 'Ï', 'Î', 'Ô', 'Ö', 'Ù', 'Û', 'Ü', 'Ÿ', 'Ç']; + + foreach ($frenchChars as $char) { + if (strpos($text, $char) !== false) { + return true; + } + } + + // Vérifier des mots français courants + $frenchWords = ['erreur', 'succès', 'changement', 'machine', 'tirage', 'impossible', 'fichier', 'données', 'paramètres', 'manquant', 'trouvé', 'ajouté', 'supprimé', 'modifié', 'mise', 'jour', 'lors', 'de', 'la', 'du', 'des', 'avec', 'pour', 'dans', 'sur', 'par', 'est', 'sont', 'ont', 'peut', 'doit', 'être', 'avoir', 'faire', 'aller', 'venir', 'voir', 'savoir', 'pouvoir', 'vouloir', 'falloir', 'devoir', 'prendre', 'donner', 'mettre', 'dire', 'parler', 'entendre', 'comprendre', 'connaître', 'croire', 'penser', 'trouver', 'chercher', 'demander', 'répondre', 'écrire', 'lire', 'apprendre', 'enseigner', 'travailler', 'jouer', 'manger', 'boire', 'dormir', 'vivre', 'mourir', 'naître', 'grandir', 'vieillir', 'changer', 'devenir', 'rester', 'partir', 'arriver', 'revenir', 'rentrer', 'sortir', 'entrer', 'monter', 'descendre', 'passer', 'traverser', 'tourner', 'marcher', 'courir', 'sauter', 'tomber', 'lever', 'baisser', 'ouvrir', 'fermer', 'commencer', 'finir', 'continuer', 'arrêter', 'reprendre', 'recommencer', 'essayer', 'réussir', 'échouer', 'gagner', 'perdre', 'acheter', 'vendre', 'payer', 'coûter', 'valoir', 'prix', 'argent', 'euro', 'euros', 'franc', 'francs', 'centime', 'centimes']; + + $textLower = strtolower($text); + foreach ($frenchWords as $word) { + if (strpos($textLower, $word) !== false) { + return true; + } + } + + return false; + } + + private function isAlreadyTranslated($text) { + // Vérifier si ce texte est déjà dans les traductions existantes + foreach ($this->translations as $category => $translations) { + if (is_array($translations)) { + foreach ($translations as $key => $value) { + if ($value === $text) { + return true; + } + } + } + } + return false; + } + + private function generateKey($text, $filePath) { + // Générer une clé basée sur le contexte du fichier et le texte + $relativePath = str_replace($this->basePath . '/', '', $filePath); + $pathParts = explode('/', $relativePath); + $fileName = pathinfo($relativePath, PATHINFO_FILENAME); + + // Nettoyer le texte pour créer une clé + $cleanText = strtolower($text); + $cleanText = preg_replace('/[^a-z0-9\s]/', '', $cleanText); + $cleanText = preg_replace('/\s+/', '_', trim($cleanText)); + $cleanText = substr($cleanText, 0, 30); // Limiter la longueur + + // Déterminer la catégorie basée sur le fichier + $category = 'common'; + if (strpos($relativePath, 'admin') !== false) { + $category = 'admin'; + } elseif (strpos($relativePath, 'error') !== false) { + $category = 'error'; + } elseif (strpos($relativePath, 'imposition') !== false) { + $category = 'imposition'; + } elseif (strpos($relativePath, 'tirage') !== false) { + $category = 'tirage'; + } + + return $category . '.' . $cleanText; + } + + public function scanProject() { + $newTranslations = []; + + // Scanner les fichiers PHP + $phpFiles = $this->getPhpFiles(); + foreach ($phpFiles as $file) { + $translations = $this->extractFromFile($file); + $newTranslations = array_merge($newTranslations, $translations); + } + + return $newTranslations; + } + + private function getPhpFiles() { + $files = []; + $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->basePath)); + + foreach ($iterator as $file) { + if ($file->isFile() && $file->getExtension() === 'php') { + $relativePath = str_replace($this->basePath . '/', '', $file->getPathname()); + if (!in_array(basename($relativePath), $this->excludedFiles)) { + $files[] = $file->getPathname(); + } + } + } + + return $files; + } + + public function saveTranslations($newTranslations) { + // Organiser les nouvelles traductions par catégorie + $organized = []; + foreach ($newTranslations as $key => $value) { + $parts = explode('.', $key, 2); + $category = $parts[0]; + $subKey = $parts[1] ?? $key; + + if (!isset($organized[$category])) { + $organized[$category] = []; + } + $organized[$category][$subKey] = $value; + } + + // Fusionner avec les traductions existantes + foreach ($organized as $category => $translations) { + if (!isset($this->translations[$category])) { + $this->translations[$category] = []; + } + $this->translations[$category] = array_merge($this->translations[$category], $translations); + } + + // Sauvegarder + $translationFile = $this->basePath . '/translations/fr.json'; + $json = json_encode($this->translations, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); + file_put_contents($translationFile, $json); + + return count($newTranslations); + } +} + +// Exécution du script +if (php_sapi_name() === 'cli' || isset($_GET['run'])) { + $extractor = new TranslationExtractor(); + $newTranslations = $extractor->scanProject(); + + if (!empty($newTranslations)) { + $count = $extractor->saveTranslations($newTranslations); + echo "Ajout de $count nouvelles traductions au fichier fr.json\n"; + + // Afficher les nouvelles traductions + foreach ($newTranslations as $key => $value) { + echo "- $key: $value\n"; + } + } else { + echo "Aucune nouvelle traduction trouvée.\n"; + } +} +?> \ No newline at end of file diff --git a/index.php b/index.php index 70d5e07..f578b50 100755 --- a/index.php +++ b/index.php @@ -17,7 +17,7 @@ // Créer les données d'erreur $errorData = [ - 'type' => 'Erreur PHP', + 'type' => __('php_errors.php_error'), 'message' => $message, 'file' => $file, 'line' => $line, @@ -40,15 +40,15 @@ // Mapper les types d'erreurs $error_types = [ - E_ERROR => 'Erreur Fatale', - E_WARNING => 'Avertissement', - E_NOTICE => 'Notice', - E_USER_ERROR => 'Erreur Utilisateur', - E_USER_WARNING => 'Avertissement Utilisateur', - E_USER_NOTICE => 'Notice Utilisateur' + E_ERROR => __('php_errors.fatal_error'), + E_WARNING => __('php_errors.warning'), + E_NOTICE => __('php_errors.notice'), + E_USER_ERROR => __('php_errors.user_error'), + E_USER_WARNING => __('php_errors.user_warning'), + E_USER_NOTICE => __('php_errors.user_notice') ]; - $error_type_name = isset($error_types[$severity]) ? $error_types[$severity] : 'Erreur'; + $error_type_name = isset($error_types[$severity]) ? $error_types[$severity] : __('common.error'); echo show_error_page($message, $error_type_name, $file, $line); exit; @@ -68,7 +68,7 @@ echo show_error_page( $exception->getMessage(), - 'Exception', + __('php_errors.exception'), $exception->getFile(), $exception->getLine(), $exception->getTraceAsString() @@ -92,7 +92,7 @@ echo show_error_page( $error['message'], - 'Erreur Fatale', + __('php_errors.fatal_error'), $error['file'], $error['line'] ); @@ -312,21 +312,21 @@ function generateErrorFooter($page) { // Vérifier l'authentification admin if (!isset($_SESSION['user'])) { http_response_code(401); - echo json_encode(['success' => false, 'error' => 'Non autorisé']); + echo json_encode(['success' => false, 'error' => __('errors.not_authenticated')]); exit; } // Vérifier que c'est bien une requête POST if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); - echo json_encode(['error' => 'Méthode non autorisée']); + echo json_encode(['error' => __('errors.method_not_allowed')]); exit; } // Vérifier que les paramètres sont présents if (!isset($_POST['machine_id']) || !isset($_POST['machine_type'])) { http_response_code(400); - echo json_encode(['error' => 'Paramètres manquants']); + echo json_encode(['error' => __('errors.missing_parameters')]); exit; } @@ -336,14 +336,14 @@ function generateErrorFooter($page) { // Valider le type de machine if (!in_array($machine_type, ['duplicopieur', 'photocopieur'])) { http_response_code(400); - echo json_encode(['error' => 'Type de machine invalide']); + echo json_encode(['error' => __('errors.invalid_machine_type')]); exit; } // Valider l'ID de la machine if (!is_numeric($machine_id) || $machine_id <= 0) { http_response_code(400); - echo json_encode(['error' => 'ID de machine invalide']); + echo json_encode(['error' => __('errors.invalid_machine_id')]); exit; } diff --git a/models/admin.php b/models/admin.php index 24cbc05..9c618db 100755 --- a/models/admin.php +++ b/models/admin.php @@ -25,7 +25,7 @@ function Action($conf = null) echo json_encode(['success' => true, 'change' => $change]); } else { header('Content-Type: application/json'); - echo json_encode(['success' => false, 'error' => 'Changement non trouvé']); + echo json_encode(['success' => false, 'error' => __('errors.change_not_found')]); } exit; } catch (Exception $e) { @@ -48,7 +48,7 @@ function Action($conf = null) echo json_encode(['success' => true, 'aide' => $aide]); } else { header('Content-Type: application/json'); - echo json_encode(['success' => false, 'error' => 'Aide non trouvée']); + echo json_encode(['success' => false, 'error' => __('errors.help_not_found')]); } exit; } catch (Exception $e) { @@ -281,7 +281,7 @@ function Action($conf = null) if(empty($old_name) || empty($new_name)) { header('Content-Type: application/json'); - echo json_encode(['error' => 'Nom manquant']); + echo json_encode(['error' => __('errors.name_missing')]); exit; } @@ -603,7 +603,7 @@ function handlePostActions($array, $dbManager, $backupManager, $siteManager, $pr } else { // Si les données ne sont pas valides, afficher un message d'erreur header('Content-Type: application/json'); - echo json_encode(['status' => 'error', 'message' => 'Données invalides']); + echo json_encode(['status' => 'error', 'message' => __('errors.invalid_data')]); // Terminer le script PHP exit(); @@ -1158,7 +1158,7 @@ function handleAideSection($array) { exit; } else { http_response_code(404); - echo 'Aide non trouvée'; + echo __('errors.help_not_found'); exit; } } diff --git a/models/admin/AideManager.php b/models/admin/AideManager.php index 61954fe..59b00db 100644 --- a/models/admin/AideManager.php +++ b/models/admin/AideManager.php @@ -30,9 +30,9 @@ public function addQA($machine, $question, $reponse, $ordre = 0, $categorie = 'g $result = $stmt->execute([$machine, $question, $reponse, $ordre, $categorie]); if ($result) { - return ['success' => 'Q&A ajoutée avec succès']; + return ['success' => __('errors.qa_added_success')]; } else { - return ['error' => 'Erreur lors de l\'ajout']; + return ['error' => __('errors.qa_add_error')]; } } catch (Exception $e) { @@ -68,9 +68,9 @@ public function addAide($machine, $contenu_aide) { $result = $stmt->execute([$machine, $contenu_aide]); if ($result) { - return ['success' => 'Aide ajoutée avec succès']; + return ['success' => __('errors.help_added_success')]; } else { - return ['error' => 'Erreur lors de l\'ajout']; + return ['error' => __('errors.qa_add_error')]; } } catch (Exception $e) { @@ -91,9 +91,9 @@ public function updateQA($id, $machine, $question, $reponse, $ordre = 0, $catego $result = $stmt->execute([$machine, $question, $reponse, $ordre, $categorie, $id]); if ($result) { - return ['success' => 'Q&A mise à jour avec succès']; + return ['success' => __('errors.qa_updated_success')]; } else { - return ['error' => 'Erreur lors de la mise à jour']; + return ['error' => __('errors.help_update_error')]; } } catch (Exception $e) { @@ -114,9 +114,9 @@ public function updateAide($id, $machine, $contenu_aide) { $result = $stmt->execute([$machine, $contenu_aide, $id]); if ($result) { - return ['success' => 'Aide mise à jour avec succès']; + return ['success' => __('errors.help_updated_success')]; } else { - return ['error' => 'Erreur lors de la mise à jour']; + return ['error' => __('errors.help_update_error')]; } } catch (Exception $e) { @@ -139,7 +139,7 @@ public function deleteQA($id) { if ($result) { return ['success' => 'Q&A supprimée avec succès']; } else { - return ['error' => 'Erreur lors de la suppression']; + return ['error' => __('errors.help_deletion_error')]; } } catch (Exception $e) { @@ -160,9 +160,9 @@ public function deleteAide($id) { $result = $stmt->execute([$id]); if ($result) { - return ['success' => 'Aide supprimée avec succès']; + return ['success' => __('errors.help_deleted_success')]; } else { - return ['error' => 'Erreur lors de la suppression']; + return ['error' => __('errors.help_deletion_error')]; } } catch (Exception $e) { diff --git a/models/admin/ChangesManager.php b/models/admin/ChangesManager.php index 5753f57..7572283 100755 --- a/models/admin/ChangesManager.php +++ b/models/admin/ChangesManager.php @@ -43,9 +43,9 @@ public function addChange($data) { ]); if ($result) { - return ['success' => 'Changement ajouté avec succès']; + return ['success' => __('errors.change_added_success')]; } else { - return ['error' => 'Erreur lors de l\'ajout']; + return ['error' => __('errors.change_add_error')]; } } catch (Exception $e) { @@ -69,9 +69,9 @@ public function deleteChange($id) { $result = $stmt->execute([$id]); if ($result) { - return ['success' => 'Changement supprimé avec succès']; + return ['success' => __('errors.change_deleted_success')]; } else { - return ['error' => 'Erreur lors de la suppression']; + return ['error' => __('errors.change_deletion_error')]; } } catch (Exception $e) { @@ -106,9 +106,9 @@ public function updateChange($id, $data) { ]); if ($result) { - return ['success' => 'Changement modifié avec succès']; + return ['success' => __('errors.change_modified_success')]; } else { - return ['error' => 'Erreur lors de la modification']; + return ['error' => __('errors.change_modification_error')]; } } catch (Exception $e) { diff --git a/models/admin/MachineManager.php b/models/admin/MachineManager.php index 8dc6e26..750a9e1 100755 --- a/models/admin/MachineManager.php +++ b/models/admin/MachineManager.php @@ -51,10 +51,10 @@ public function addMachine($data) { // Créer automatiquement une aide pour la nouvelle machine $this->createDefaultAide($db, $machine_name); - return ['success' => "Machine $machine_name ajoutée avec succès"]; + return ['success' => __('errors.machine_added_success', ['machine' => $machine_name])]; } catch (Exception $e) { - return ['error' => "Erreur lors de l'ajout de la machine : " . $e->getMessage()]; + return ['error' => __('errors.machine_add_error') . " : " . $e->getMessage()]; } } @@ -528,7 +528,7 @@ public function deleteMachine($machine_id, $machine_type) { return ['success' => "Duplicopieur $machine_name supprimé avec succès"]; } else { - return ['error' => "Duplicopieur introuvable"]; + return ['error' => __('errors.duplicopieur_not_found')]; } } elseif ($machine_type === 'photocopieur') { @@ -556,7 +556,7 @@ public function deleteMachine($machine_id, $machine_type) { return ['success' => "Photocopieur $machine_name supprimé avec succès"]; } else { - return ['error' => "Photocopieur introuvable"]; + return ['error' => __('errors.photocopieur_not_found')]; } } else { return ['error' => "Type de machine invalide"]; @@ -660,7 +660,7 @@ public function renameMachine($old_name, $new_name) { $result = $query->fetch(PDO::FETCH_OBJ); if ($result && $result->count > 0) { - return ['error' => 'Une machine avec ce nom existe déjà']; + return ['error' => __('errors.machine_name_exists')]; } // Démarrer une transaction diff --git a/models/admin/delete_machine.php b/models/admin/delete_machine.php index d495f85..c27b453 100755 --- a/models/admin/delete_machine.php +++ b/models/admin/delete_machine.php @@ -6,14 +6,14 @@ // Vérifier que c'est bien une requête POST if ($_SERVER['REQUEST_METHOD'] !== 'POST') { http_response_code(405); - echo json_encode(['error' => 'Méthode non autorisée']); + echo json_encode(['error' => __('errors.method_not_allowed')]); exit; } // Vérifier que les paramètres sont présents if (!isset($_POST['machine_id']) || !isset($_POST['machine_type'])) { http_response_code(400); - echo json_encode(['error' => 'Paramètres manquants']); + echo json_encode(['error' => __('errors.missing_parameters')]); exit; } @@ -23,14 +23,14 @@ // Valider le type de machine if (!in_array($machine_type, ['duplicopieur', 'photocopieur'])) { http_response_code(400); - echo json_encode(['error' => 'Type de machine invalide']); + echo json_encode(['error' => __('errors.invalid_machine_type')]); exit; } // Valider l'ID de la machine if (!is_numeric($machine_id) || $machine_id <= 0) { http_response_code(400); - echo json_encode(['error' => 'ID de machine invalide']); + echo json_encode(['error' => __('errors.invalid_machine_id')]); exit; } diff --git a/models/admin_translations.php b/models/admin_translations.php index 770ce6f..340cc2d 100644 --- a/models/admin_translations.php +++ b/models/admin_translations.php @@ -9,7 +9,7 @@ function Action($conf) { if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { header('Content-Type: application/json'); - echo json_encode(['success' => false, 'message' => 'Non authentifié']); + echo json_encode(['success' => false, 'message' => __('errors.not_authenticated')]); exit; } else { header('Location: ?admin'); @@ -71,7 +71,7 @@ function Action($conf) { $imported = $translationManager->importFromCSV($language, $csvContent); $array['success_message'] = "$imported traductions importées avec succès !"; } else { - $array['error_message'] = "Erreur lors de l'import du fichier CSV."; + $array['error_message'] = __('errors.csv_import_error'); } break; } diff --git a/models/imposition_tracts.php b/models/imposition_tracts.php index b99f9c8..74892cd 100644 --- a/models/imposition_tracts.php +++ b/models/imposition_tracts.php @@ -40,7 +40,7 @@ function analyzePDFFormat($pdfFile) try { // Vérifier que le fichier est bien un PDF if ($pdfFile['type'] !== 'application/pdf') { - throw new Exception('Le fichier doit être un PDF'); + throw new Exception(__('errors.file_must_be_pdf')); } $originalFile = $pdfFile['tmp_name']; @@ -55,7 +55,7 @@ function analyzePDFFormat($pdfFile) $pageCount = $pdf->setSourceFile($originalFile); if ($pageCount === 0) { - throw new Exception('PDF vide ou illisible'); + throw new Exception(__('errors.pdf_empty_or_unreadable')); } } catch (Exception $e) { @@ -91,7 +91,7 @@ function analyzePDFFormat($pdfFile) $pageCount = $pdf->setSourceFile($cleanedPdfFile); if ($pageCount === 0) { - throw new Exception('Impossible de lire le PDF même après nettoyage Ghostscript'); + throw new Exception(__('errors.cannot_read_pdf_after_ghostscript')); } $usedGhostscript = true; @@ -172,7 +172,7 @@ function processImpositionTracts() // Vérifier qu'un fichier a été uploadé if (!isset($_FILES['pdf_file']) || $_FILES['pdf_file']['error'] !== UPLOAD_ERR_OK) { - throw new Exception("Erreur lors de l'upload du fichier PDF."); + throw new Exception(__('errors.upload_error')); } // Créer un nom de fichier unique @@ -189,11 +189,11 @@ function processImpositionTracts() // Vérifier les permissions du fichier déplacé if (!file_exists($inputFile)) { - throw new Exception("Le fichier déplacé n'existe pas."); + throw new Exception(__('errors.file_moved_not_exists')); } if (!is_readable($inputFile)) { - throw new Exception("Le fichier déplacé n'est pas lisible."); + throw new Exception(__('errors.file_moved_not_readable')); } // S'assurer que le fichier a les bonnes permissions diff --git a/translations/de.json b/translations/de.json index 9dc5390..142be4f 100644 --- a/translations/de.json +++ b/translations/de.json @@ -126,5 +126,67 @@ "confirm": "Bestätigen", "yes": "Ja", "no": "Nein" + }, + "errors": { + "not_authenticated": "Nicht authentifiziert", + "method_not_allowed": "Methode nicht erlaubt", + "missing_parameters": "Fehlende Parameter", + "invalid_machine_type": "Ungültiger Maschinentyp", + "invalid_machine_id": "Ungültige Maschinen-ID", + "change_not_found": "Änderung nicht gefunden", + "help_not_found": "Hilfe nicht gefunden", + "name_missing": "Name fehlt", + "invalid_data": "Ungültige Daten", + "file_must_be_pdf": "Datei muss ein PDF sein", + "pdf_empty_or_unreadable": "PDF leer oder nicht lesbar", + "cannot_read_pdf_after_ghostscript": "PDF kann auch nach Ghostscript-Bereinigung nicht gelesen werden", + "upload_error": "Fehler beim Hochladen der Datei", + "imposition_error": "Fehler bei der Imposition", + "page_import_error": "Fehler beim Import der Seite", + "csv_import_error": "Fehler beim Import der CSV-Datei", + "change_added_success": "Änderung erfolgreich hinzugefügt", + "change_deleted_success": "Änderung erfolgreich gelöscht", + "change_deletion_error": "Fehler beim Löschen", + "change_modified_success": "Änderung erfolgreich geändert", + "change_modification_error": "Fehler bei der Änderung", + "help_added_success": "Hilfe erfolgreich hinzugefügt", + "help_update_error": "Fehler beim Aktualisieren", + "help_updated_success": "Hilfe erfolgreich aktualisiert", + "help_deletion_error": "Fehler beim Löschen", + "help_deleted_success": "Hilfe erfolgreich gelöscht", + "machine_add_error": "Fehler beim Hinzufügen der Maschine", + "duplicopieur_not_found": "Duplikator nicht gefunden", + "photocopieur_not_found": "Fotokopierer nicht gefunden", + "empty_name_not_allowed": "Leerer Name nicht erlaubt", + "machine_name_exists": "Eine Maschine mit diesem Namen existiert bereits", + "machine_renamed_success": "Maschine erfolgreich umbenannt", + "structure_data_copied": "Struktur und Daten kopiert", + "copy_error": "Fehler beim Kopieren", + "help_data_inserted": "Initiale Hilfedaten eingefügt", + "help_data_insertion_error": "Fehler beim Einfügen der Hilfedaten", + "tirage_not_found": "Druck nicht gefunden", + "file_moved_not_exists": "Verschobene Datei existiert nicht", + "file_moved_not_readable": "Verschobene Datei ist nicht lesbar", + "qa_added_success": "Q&A erfolgreich hinzugefügt", + "qa_add_error": "Fehler beim Hinzufügen", + "qa_updated_success": "Q&A erfolgreich aktualisiert", + "qa_deleted_success": "Q&A erfolgreich gelöscht", + "change_add_error": "Fehler beim Hinzufügen", + "machine_added_success": "Maschine :machine erfolgreich hinzugefügt", + "machine_mapping_error": "Fehler bei der Generierung der Maschinenzuordnungen" + }, + "php_errors": { + "php_error": "PHP-Fehler", + "fatal_error": "Schwerwiegender Fehler", + "warning": "Warnung", + "notice": "Hinweis", + "user_error": "Benutzerfehler", + "user_warning": "Benutzerwarnung", + "user_notice": "Benutzerhinweis", + "exception": "Ausnahme" + }, + "unimpose": { + "pdf_unimposed_success": "Ihr PDF wurde erfolgreich entimponiert", + "file_ready_download": "Die Datei :file ist zum Download bereit." } } \ No newline at end of file diff --git a/translations/en.json b/translations/en.json index 45c1ba7..78c4637 100644 --- a/translations/en.json +++ b/translations/en.json @@ -475,5 +475,67 @@ "inches": "inches", "points": "points", "pixels": "pixels" + }, + "errors": { + "not_authenticated": "Not authenticated", + "method_not_allowed": "Method not allowed", + "missing_parameters": "Missing parameters", + "invalid_machine_type": "Invalid machine type", + "invalid_machine_id": "Invalid machine ID", + "change_not_found": "Change not found", + "help_not_found": "Help not found", + "name_missing": "Name missing", + "invalid_data": "Invalid data", + "file_must_be_pdf": "File must be a PDF", + "pdf_empty_or_unreadable": "PDF empty or unreadable", + "cannot_read_pdf_after_ghostscript": "Cannot read PDF even after Ghostscript cleanup", + "upload_error": "Error during file upload", + "imposition_error": "Error during imposition", + "page_import_error": "Error during page import", + "csv_import_error": "Error during CSV file import", + "change_added_success": "Change added successfully", + "change_deleted_success": "Change deleted successfully", + "change_deletion_error": "Error during deletion", + "change_modified_success": "Change modified successfully", + "change_modification_error": "Error during modification", + "help_added_success": "Help added successfully", + "help_update_error": "Error during update", + "help_updated_success": "Help updated successfully", + "help_deletion_error": "Error during deletion", + "help_deleted_success": "Help deleted successfully", + "machine_add_error": "Error during machine addition", + "duplicopieur_not_found": "Duplicator not found", + "photocopieur_not_found": "Photocopier not found", + "empty_name_not_allowed": "Empty name not allowed", + "machine_name_exists": "A machine with this name already exists", + "machine_renamed_success": "Machine renamed successfully", + "structure_data_copied": "Structure and data copied", + "copy_error": "Error during copy", + "help_data_inserted": "Initial help data inserted", + "help_data_insertion_error": "Error during help data insertion", + "tirage_not_found": "Print not found", + "file_moved_not_exists": "Moved file does not exist", + "file_moved_not_readable": "Moved file is not readable", + "qa_added_success": "Q&A added successfully", + "qa_add_error": "Error during addition", + "qa_updated_success": "Q&A updated successfully", + "qa_deleted_success": "Q&A deleted successfully", + "change_add_error": "Error during addition", + "machine_added_success": "Machine :machine added successfully", + "machine_mapping_error": "Error during machine mapping generation" + }, + "php_errors": { + "php_error": "PHP Error", + "fatal_error": "Fatal Error", + "warning": "Warning", + "notice": "Notice", + "user_error": "User Error", + "user_warning": "User Warning", + "user_notice": "User Notice", + "exception": "Exception" + }, + "unimpose": { + "pdf_unimposed_success": "Your PDF has been successfully unimposed", + "file_ready_download": "The file :file is ready for download." } } \ No newline at end of file diff --git a/translations/es.json b/translations/es.json index c7bbcbb..ca551c5 100644 --- a/translations/es.json +++ b/translations/es.json @@ -126,5 +126,67 @@ "confirm": "Confirmar", "yes": "Sí", "no": "No" + }, + "errors": { + "not_authenticated": "No autenticado", + "method_not_allowed": "Método no permitido", + "missing_parameters": "Parámetros faltantes", + "invalid_machine_type": "Tipo de máquina inválido", + "invalid_machine_id": "ID de máquina inválido", + "change_not_found": "Cambio no encontrado", + "help_not_found": "Ayuda no encontrada", + "name_missing": "Nombre faltante", + "invalid_data": "Datos inválidos", + "file_must_be_pdf": "El archivo debe ser un PDF", + "pdf_empty_or_unreadable": "PDF vacío o ilegible", + "cannot_read_pdf_after_ghostscript": "No se puede leer el PDF incluso después de la limpieza de Ghostscript", + "upload_error": "Error durante la carga del archivo", + "imposition_error": "Error durante la imposición", + "page_import_error": "Error durante la importación de página", + "csv_import_error": "Error durante la importación del archivo CSV", + "change_added_success": "Cambio agregado exitosamente", + "change_deleted_success": "Cambio eliminado exitosamente", + "change_deletion_error": "Error durante la eliminación", + "change_modified_success": "Cambio modificado exitosamente", + "change_modification_error": "Error durante la modificación", + "help_added_success": "Ayuda agregada exitosamente", + "help_update_error": "Error durante la actualización", + "help_updated_success": "Ayuda actualizada exitosamente", + "help_deletion_error": "Error durante la eliminación", + "help_deleted_success": "Ayuda eliminada exitosamente", + "machine_add_error": "Error durante la adición de máquina", + "duplicopieur_not_found": "Duplicador no encontrado", + "photocopieur_not_found": "Fotocopiadora no encontrada", + "empty_name_not_allowed": "Nombre vacío no permitido", + "machine_name_exists": "Ya existe una máquina con este nombre", + "machine_renamed_success": "Máquina renombrada exitosamente", + "structure_data_copied": "Estructura y datos copiados", + "copy_error": "Error durante la copia", + "help_data_inserted": "Datos iniciales de ayuda insertados", + "help_data_insertion_error": "Error durante la inserción de datos de ayuda", + "tirage_not_found": "Impresión no encontrada", + "file_moved_not_exists": "El archivo movido no existe", + "file_moved_not_readable": "El archivo movido no es legible", + "qa_added_success": "P&R agregada exitosamente", + "qa_add_error": "Error durante la adición", + "qa_updated_success": "P&R actualizada exitosamente", + "qa_deleted_success": "P&R eliminada exitosamente", + "change_add_error": "Error durante la adición", + "machine_added_success": "Máquina :machine agregada exitosamente", + "machine_mapping_error": "Error durante la generación de mapeos de máquina" + }, + "php_errors": { + "php_error": "Error PHP", + "fatal_error": "Error Fatal", + "warning": "Advertencia", + "notice": "Aviso", + "user_error": "Error de Usuario", + "user_warning": "Advertencia de Usuario", + "user_notice": "Aviso de Usuario", + "exception": "Excepción" + }, + "unimpose": { + "pdf_unimposed_success": "Su PDF ha sido desimponido exitosamente", + "file_ready_download": "El archivo :file está listo para descargar." } } \ No newline at end of file diff --git a/translations/fr.json b/translations/fr.json index 62b4195..81fd580 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -514,7 +514,9 @@ "a3_to_a4": "Pages A3 imposées → Pages A4 normales", "booklet_to_sequential": "Ordre de livret → Ordre séquentiel", "two_pages_to_one": "2 pages par feuille → 1 page par feuille", - "tip": "Parfait pour récupérer un document original à partir d'un livret déjà imposé." + "tip": "Parfait pour récupérer un document original à partir d'un livret déjà imposé.", + "pdf_unimposed_success": "Votre PDF a été désimposé avec succès", + "file_ready_download": "Le fichier :file est prêt au téléchargement." }, "imposition_tracts": { "title": "Imposition de Tracts", @@ -872,5 +874,63 @@ "inches": "pouces", "points": "points", "pixels": "pixels" + }, + "errors": { + "not_authenticated": "Non authentifié", + "method_not_allowed": "Méthode non autorisée", + "missing_parameters": "Paramètres manquants", + "invalid_machine_type": "Type de machine invalide", + "invalid_machine_id": "ID de machine invalide", + "change_not_found": "Changement non trouvé", + "help_not_found": "Aide non trouvée", + "name_missing": "Nom manquant", + "invalid_data": "Données invalides", + "file_must_be_pdf": "Le fichier doit être un PDF", + "pdf_empty_or_unreadable": "PDF vide ou illisible", + "cannot_read_pdf_after_ghostscript": "Impossible de lire le PDF même après nettoyage Ghostscript", + "upload_error": "Erreur lors de l'upload du fichier", + "imposition_error": "Erreur lors de l'imposition", + "page_import_error": "Erreur lors de l'import de la page", + "csv_import_error": "Erreur lors de l'import du fichier CSV", + "change_added_success": "Changement ajouté avec succès", + "change_deleted_success": "Changement supprimé avec succès", + "change_deletion_error": "Erreur lors de la suppression", + "change_modified_success": "Changement modifié avec succès", + "change_modification_error": "Erreur lors de la modification", + "help_added_success": "Aide ajoutée avec succès", + "help_update_error": "Erreur lors de la mise à jour", + "help_updated_success": "Aide mise à jour avec succès", + "help_deletion_error": "Erreur lors de la suppression", + "help_deleted_success": "Aide supprimée avec succès", + "machine_add_error": "Erreur lors de l'ajout de la machine", + "duplicopieur_not_found": "Duplicopieur introuvable", + "photocopieur_not_found": "Photocopieur introuvable", + "empty_name_not_allowed": "Le nouveau nom ne peut pas être vide", + "machine_name_exists": "Une machine avec ce nom existe déjà", + "machine_renamed_success": "Machine renommée avec succès", + "structure_data_copied": "Structure et données copiées", + "copy_error": "Erreur lors de la copie", + "help_data_inserted": "Données initiales d'aide insérées", + "help_data_insertion_error": "Erreur lors de l'insertion des données d'aide", + "tirage_not_found": "Tirage non trouvé", + "file_moved_not_exists": "Le fichier déplacé n'existe pas", + "file_moved_not_readable": "Le fichier déplacé n'est pas lisible", + "qa_added_success": "Q&A ajoutée avec succès", + "qa_add_error": "Erreur lors de l'ajout", + "qa_updated_success": "Q&A mise à jour avec succès", + "qa_deleted_success": "Q&A supprimée avec succès", + "change_add_error": "Erreur lors de l'ajout", + "machine_added_success": "Machine :machine ajoutée avec succès", + "machine_mapping_error": "Erreur lors de la génération des mappings machine" + }, + "php_errors": { + "php_error": "Erreur PHP", + "fatal_error": "Erreur Fatale", + "warning": "Avertissement", + "notice": "Notice", + "user_error": "Erreur Utilisateur", + "user_warning": "Avertissement Utilisateur", + "user_notice": "Notice Utilisateur", + "exception": "Exception" } } \ No newline at end of file diff --git a/view/tirage_multimachines.html.php b/view/tirage_multimachines.html.php index edf4b5e..ff25219 100755 --- a/view/tirage_multimachines.html.php +++ b/view/tirage_multimachines.html.php @@ -38,7 +38,7 @@ } } } catch (Exception $e) { - error_log("Erreur lors de la génération des mappings machine: " . $e->getMessage()); + error_log(__('errors.machine_mapping_error') . ": " . $e->getMessage()); $machine_price_mappings = []; } ?> diff --git a/view/unimpose.html.php b/view/unimpose.html.php index 69353f6..0cfe617 100755 --- a/view/unimpose.html.php +++ b/view/unimpose.html.php @@ -30,10 +30,10 @@

- Votre PDF a été désimposé avec succès +

- Le fichier est prêt au téléchargement. + htmlspecialchars($result)]); ?>

From 7e4377d46cb11cbd2be732faddf53e5754e023cf Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 20 Oct 2025 06:59:41 +0000 Subject: [PATCH 2/7] Checkpoint before follow-up message Co-authored-by: maun.aug --- models/admin.php | 10 +++++----- models/admin/MachineManager.php | 2 +- view/tirage_multimachines.html.php | 16 ++++++++-------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/models/admin.php b/models/admin.php index 9c618db..480953f 100755 --- a/models/admin.php +++ b/models/admin.php @@ -219,7 +219,7 @@ function Action($conf = null) require_once __DIR__ . '/../controler/functions/error_handler.php'; $result = show_error_page( "La configuration de la base de données n'a pas été chargée correctement. Cela peut arriver si les fichiers de configuration sont manquants ou corrompus.", - "Configuration non définie", + __('errors.configuration_not_defined'), __FILE__, __LINE__, null, @@ -966,7 +966,7 @@ function addChange($data) { $query = $db->prepare('INSERT INTO cons (date, machine, type, nb_p, nb_m, tambour) VALUES (?, ?, ?, ?, ?, ?)'); $query->execute([$date, $machine, $type, $nb_p, $nb_m, $tambour]); - return ['success' => "Changement ajouté avec succès"]; + return ['success' => __('errors.change_added_success')]; } catch (Exception $e) { return ['error' => "Erreur lors de l'ajout : " . $e->getMessage()]; @@ -990,7 +990,7 @@ function updateChange($data) { $query = $db->prepare('UPDATE cons SET date = ?, nb_p = ? WHERE machine = ? AND type = ? AND date = ?'); $query->execute([$new_date, $counter, $machine, $type, $old_date]); - return ['success' => "Changement mis à jour avec succès"]; + return ['success' => __('errors.change_updated_success')]; } catch (Exception $e) { return ['error' => "Erreur lors de la mise à jour : " . $e->getMessage()]; @@ -1014,9 +1014,9 @@ function deleteChange($data) { $deleted_count = $query->rowCount(); if ($deleted_count === 0) { - return ['error' => "Aucune entrée trouvée à supprimer"]; + return ['error' => __('errors.no_entry_found_to_delete')]; } elseif ($deleted_count > 1) { - return ['error' => "Plusieurs entrées ont été supprimées par erreur"]; + return ['error' => __('errors.multiple_entries_deleted_by_error')]; } return ['success' => "Changement supprimé avec succès"]; diff --git a/models/admin/MachineManager.php b/models/admin/MachineManager.php index 750a9e1..28acfde 100755 --- a/models/admin/MachineManager.php +++ b/models/admin/MachineManager.php @@ -559,7 +559,7 @@ public function deleteMachine($machine_id, $machine_type) { return ['error' => __('errors.photocopieur_not_found')]; } } else { - return ['error' => "Type de machine invalide"]; + return ['error' => __('errors.invalid_machine_type')]; } } catch (Exception $e) { diff --git a/view/tirage_multimachines.html.php b/view/tirage_multimachines.html.php index ff25219..9aa7467 100755 --- a/view/tirage_multimachines.html.php +++ b/view/tirage_multimachines.html.php @@ -676,7 +676,7 @@
-
+
@@ -1445,10 +1445,10 @@ function calculateMachinePrice(machineIndex) { var passageAp = parseFloat(passageApElement ? passageApElement.value : 0) || 0; console.log("🔍 Valeurs brutes des champs:", { - masterAvElement_value: masterAvElement ? masterAvElement.value : "élément non trouvé", - masterApElement_value: masterApElement ? masterApElement.value : "élément non trouvé", - passageAvElement_value: passageAvElement ? passageAvElement.value : "élément non trouvé", - passageApElement_value: passageApElement ? passageApElement.value : "élément non trouvé" + masterAvElement_value: masterAvElement ? masterAvElement.value : "", + masterApElement_value: masterApElement ? masterApElement.value : "", + passageAvElement_value: passageAvElement ? passageAvElement.value : "", + passageApElement_value: passageApElement ? passageApElement.value : "" }); nbMasters = Math.max(0, masterAp - masterAv); @@ -1997,7 +1997,7 @@ function updatePaymentAmount() { // Vérifier que les éléments existent avant de les utiliser if (!payeOui || !cbField) { - console.log("Éléments payeOui ou cbField non trouvés"); + console.log(""); return; } @@ -2030,7 +2030,7 @@ function updatePaymentAmount() { } } - console.log("Aucun prix total trouvé"); + console.log(""); } else { // Si "non" est sélectionné, vider le champ cbField.value = ''; @@ -2199,7 +2199,7 @@ function updatePanelPreview(machineIndex) { pricePreview.textContent = price.toFixed(2) + '€'; console.log("✅ Prix preview mis à jour:", price.toFixed(2) + '€'); } else { - console.log("❌ ERREUR: price-preview-" + machineIndex + " non trouvé"); + console.log("❌ : price-preview-" + machineIndex + " "); } } From 5435b6d812147cc0ab84c9ac17c320176818b9cc Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 20 Oct 2025 07:02:29 +0000 Subject: [PATCH 3/7] Refactor: Use translation keys for error messages Co-authored-by: maun.aug --- models/admin.php | 8 ++++---- models/admin/BackupManager.php | 6 +++--- translations/de.json | 18 +++++++++++++++--- translations/en.json | 16 ++++++++++++++-- translations/es.json | 18 +++++++++++++++--- translations/fr.json | 16 ++++++++++++++-- 6 files changed, 65 insertions(+), 17 deletions(-) diff --git a/models/admin.php b/models/admin.php index 480953f..471ccf3 100755 --- a/models/admin.php +++ b/models/admin.php @@ -1019,7 +1019,7 @@ function deleteChange($data) { return ['error' => __('errors.multiple_entries_deleted_by_error')]; } - return ['success' => "Changement supprimé avec succès"]; + return ['success' => __('errors.change_deleted_success')]; } catch (Exception $e) { return ['error' => "Erreur lors de la suppression : " . $e->getMessage()]; @@ -1228,7 +1228,7 @@ function addAide($machine, $contenu) { $query->execute([$machine]); if ($query->fetchColumn() > 0) { - return ['error' => "Une aide existe déjà pour cette machine"]; + return ['error' => __('errors.help_already_exists_for_machine')]; } // Insérer la nouvelle aide @@ -1255,7 +1255,7 @@ function updateAide($id, $machine, $contenu) { $query->execute([$id]); if ($query->fetchColumn() == 0) { - return ['error' => "Aide non trouvée"]; + return ['error' => __('errors.help_not_found')]; } // Mettre à jour l'aide @@ -1283,7 +1283,7 @@ function deleteAide($id) { $machine = $query->fetchColumn(); if (!$machine) { - return ['error' => "Aide non trouvée"]; + return ['error' => __('errors.help_not_found')]; } // Supprimer l'aide diff --git a/models/admin/BackupManager.php b/models/admin/BackupManager.php index 64274d6..fbee2a9 100755 --- a/models/admin/BackupManager.php +++ b/models/admin/BackupManager.php @@ -47,7 +47,7 @@ public function createBackup($backup_name = '') { $result['filename'] = $filename; $result['size'] = $this->formatFileSize(filesize($filepath)); } else { - $result['error'] = "Erreur lors de la copie du fichier de base de données"; + $result['error'] = __('errors.database_file_copy_error'); } } catch (Exception $e) { @@ -85,7 +85,7 @@ public function restoreBackup($backup_file) { $result['success'] = "Sauvegarde restaurée avec succès : $backup_file"; $result['safety_backup'] = basename($safety_backup); } else { - $result['error'] = "Erreur lors de la copie du fichier de sauvegarde"; + $result['error'] = __('errors.backup_file_copy_error'); } } catch (Exception $e) { @@ -112,7 +112,7 @@ public function deleteBackup($backup_file) { if (unlink($filepath)) { $result['success'] = "Sauvegarde supprimée avec succès : $backup_file"; } else { - $result['error'] = "Erreur lors de la suppression du fichier"; + $result['error'] = __('errors.file_deletion_error'); } } catch (Exception $e) { diff --git a/translations/de.json b/translations/de.json index 142be4f..1330a76 100644 --- a/translations/de.json +++ b/translations/de.json @@ -125,7 +125,11 @@ "remove": "Entfernen", "confirm": "Bestätigen", "yes": "Ja", - "no": "Nein" + "no": "Nein", + "element_not_found": "Element nicht gefunden", + "no_total_price_found": "Kein Gesamtpreis gefunden", + "elements_not_found": "payeOui oder cbField Elemente nicht gefunden", + "not_found": "nicht gefunden" }, "errors": { "not_authenticated": "Nicht authentifiziert", @@ -172,8 +176,16 @@ "qa_updated_success": "Q&A erfolgreich aktualisiert", "qa_deleted_success": "Q&A erfolgreich gelöscht", "change_add_error": "Fehler beim Hinzufügen", - "machine_added_success": "Maschine :machine erfolgreich hinzugefügt", - "machine_mapping_error": "Fehler bei der Generierung der Maschinenzuordnungen" + "machine_added_success": "Maschine :machine erfolgreich hinzugefügt", + "machine_mapping_error": "Fehler bei der Generierung der Maschinenzuordnungen", + "configuration_not_defined": "Konfiguration nicht definiert", + "change_updated_success": "Änderung erfolgreich aktualisiert", + "no_entry_found_to_delete": "Kein Eintrag zum Löschen gefunden", + "multiple_entries_deleted_by_error": "Mehrere Einträge wurden versehentlich gelöscht", + "help_already_exists_for_machine": "Hilfe existiert bereits für diese Maschine", + "database_file_copy_error": "Fehler beim Kopieren der Datenbankdatei", + "backup_file_copy_error": "Fehler beim Kopieren der Backup-Datei", + "file_deletion_error": "Fehler beim Löschen der Datei" }, "php_errors": { "php_error": "PHP-Fehler", diff --git a/translations/en.json b/translations/en.json index 78c4637..3635625 100644 --- a/translations/en.json +++ b/translations/en.json @@ -474,7 +474,11 @@ "cm": "cm", "inches": "inches", "points": "points", - "pixels": "pixels" + "pixels": "pixels", + "element_not_found": "element not found", + "no_total_price_found": "No total price found", + "elements_not_found": "payeOui or cbField elements not found", + "not_found": "not found" }, "errors": { "not_authenticated": "Not authenticated", @@ -522,7 +526,15 @@ "qa_deleted_success": "Q&A deleted successfully", "change_add_error": "Error during addition", "machine_added_success": "Machine :machine added successfully", - "machine_mapping_error": "Error during machine mapping generation" + "machine_mapping_error": "Error during machine mapping generation", + "configuration_not_defined": "Configuration not defined", + "change_updated_success": "Change updated successfully", + "no_entry_found_to_delete": "No entry found to delete", + "multiple_entries_deleted_by_error": "Multiple entries were deleted by error", + "help_already_exists_for_machine": "Help already exists for this machine", + "database_file_copy_error": "Error during database file copy", + "backup_file_copy_error": "Error during backup file copy", + "file_deletion_error": "Error during file deletion" }, "php_errors": { "php_error": "PHP Error", diff --git a/translations/es.json b/translations/es.json index ca551c5..b216e70 100644 --- a/translations/es.json +++ b/translations/es.json @@ -125,7 +125,11 @@ "remove": "Eliminar", "confirm": "Confirmar", "yes": "Sí", - "no": "No" + "no": "No", + "element_not_found": "elemento no encontrado", + "no_total_price_found": "No se encontró precio total", + "elements_not_found": "Elementos payeOui o cbField no encontrados", + "not_found": "no encontrado" }, "errors": { "not_authenticated": "No autenticado", @@ -172,8 +176,16 @@ "qa_updated_success": "P&R actualizada exitosamente", "qa_deleted_success": "P&R eliminada exitosamente", "change_add_error": "Error durante la adición", - "machine_added_success": "Máquina :machine agregada exitosamente", - "machine_mapping_error": "Error durante la generación de mapeos de máquina" + "machine_added_success": "Máquina :machine agregada exitosamente", + "machine_mapping_error": "Error durante la generación de mapeos de máquina", + "configuration_not_defined": "Configuración no definida", + "change_updated_success": "Cambio actualizado exitosamente", + "no_entry_found_to_delete": "No se encontró entrada para eliminar", + "multiple_entries_deleted_by_error": "Múltiples entradas fueron eliminadas por error", + "help_already_exists_for_machine": "Ya existe ayuda para esta máquina", + "database_file_copy_error": "Error durante la copia del archivo de base de datos", + "backup_file_copy_error": "Error durante la copia del archivo de respaldo", + "file_deletion_error": "Error durante la eliminación del archivo" }, "php_errors": { "php_error": "Error PHP", diff --git a/translations/fr.json b/translations/fr.json index 81fd580..aa1aa6c 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -873,7 +873,11 @@ "cm": "cm", "inches": "pouces", "points": "points", - "pixels": "pixels" + "pixels": "pixels", + "element_not_found": "élément non trouvé", + "no_total_price_found": "Aucun prix total trouvé", + "elements_not_found": "Éléments payeOui ou cbField non trouvés", + "not_found": "non trouvé" }, "errors": { "not_authenticated": "Non authentifié", @@ -921,7 +925,15 @@ "qa_deleted_success": "Q&A supprimée avec succès", "change_add_error": "Erreur lors de l'ajout", "machine_added_success": "Machine :machine ajoutée avec succès", - "machine_mapping_error": "Erreur lors de la génération des mappings machine" + "machine_mapping_error": "Erreur lors de la génération des mappings machine", + "configuration_not_defined": "Configuration non définie", + "change_updated_success": "Changement mis à jour avec succès", + "no_entry_found_to_delete": "Aucune entrée trouvée à supprimer", + "multiple_entries_deleted_by_error": "Plusieurs entrées ont été supprimées par erreur", + "help_already_exists_for_machine": "Une aide existe déjà pour cette machine", + "database_file_copy_error": "Erreur lors de la copie du fichier de base de données", + "backup_file_copy_error": "Erreur lors de la copie du fichier de sauvegarde", + "file_deletion_error": "Erreur lors de la suppression du fichier" }, "php_errors": { "php_error": "Erreur PHP", From 336a476ccb28e4b23344d8c7ac82758529a06d7f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 20 Oct 2025 07:17:37 +0000 Subject: [PATCH 4/7] feat: Add stats page and internationalize tooltips Co-authored-by: maun.aug --- cleanup_debug.php | 34 ++++++++++++++++++++++++++++++++++ translations/de.json | 20 +++++++++++++++++++- translations/en.json | 9 +++++++-- translations/es.json | 20 +++++++++++++++++++- translations/fr.json | 9 +++++++-- view/admin.edit.html.php | 16 ++++++++-------- view/stats.html.php | 20 ++++++++++---------- 7 files changed, 104 insertions(+), 24 deletions(-) create mode 100644 cleanup_debug.php diff --git a/cleanup_debug.php b/cleanup_debug.php new file mode 100644 index 0000000..6b34937 --- /dev/null +++ b/cleanup_debug.php @@ -0,0 +1,34 @@ + \ No newline at end of file diff --git a/translations/de.json b/translations/de.json index 1330a76..b41ed44 100644 --- a/translations/de.json +++ b/translations/de.json @@ -129,7 +129,8 @@ "element_not_found": "Element nicht gefunden", "no_total_price_found": "Kein Gesamtpreis gefunden", "elements_not_found": "payeOui oder cbField Elemente nicht gefunden", - "not_found": "nicht gefunden" + "not_found": "nicht gefunden", + "page_navigation": "Seitennavigation" }, "errors": { "not_authenticated": "Nicht authentifiziert", @@ -200,5 +201,22 @@ "unimpose": { "pdf_unimposed_success": "Ihr PDF wurde erfolgreich entimponiert", "file_ready_download": "Die Datei :file ist zum Download bereit." + }, + "stats": { + "title": "Statistiken", + "intro_text": "Seit Beginn des Dupli-Abenteuers im Jahr 2011 haben wir insgesamt {nb_f} Seiten in mehr als {nb_t} Malen gedruckt. Wenn wir genauer hinschauen, macht das einen Durchschnitt von {nb_t_par_mois} Drucken pro Monat, mit etwa {nbf_par_mois} Blättern im Durchschnitt. Sie drucken {nb_moy_par_mois} Kopien pro Druck. Ich erspare Ihnen nicht den Umsatz: {ca} Euro seit Beginn, wenn wir die {doit} Euro abziehen, die uns geschuldet werden: {ca2} Euro. Sie haben uns {ca1} Euro gegeben. Wir sind also {benf} Euro, aber das ist ohne den Preis der Miete der Condos zu zählen, die bei 50 Euro pro Monat... ! Die Big Data sind da, ich lasse Sie schauen :) ps: und das sind auch 1800 Codezeilen!", + "monthly_stats": "Monatliche Statistiken", + "date": "Datum", + "sheets": "Blätter", + "prints": "Drucke", + "average": "Durchschnitt", + "price": "Preis", + "price_paid": "Gezahlter Preis", + "difference": "Unterschied", + "user_paid": "Wie viel der Benutzer bezahlt hat", + "sheets_count": "Anzahl der Blätter", + "sheets_per_print": "Anzahl der Blätter pro Druck", + "prints_count": "Anzahl der Drucke", + "monthly_profit": "Gewinn für diesen Monat" } } \ No newline at end of file diff --git a/translations/en.json b/translations/en.json index 3635625..467ab46 100644 --- a/translations/en.json +++ b/translations/en.json @@ -162,7 +162,11 @@ "price": "Price", "price_paid": "Price paid", "difference": "Difference", - "user_paid": "How much the user paid" + "user_paid": "How much the user paid", + "sheets_count": "number of sheets", + "sheets_per_print": "number of sheets per print", + "prints_count": "number of prints", + "monthly_profit": "Profit for this month" }, "changement": { "title": "Consumable change report", @@ -478,7 +482,8 @@ "element_not_found": "element not found", "no_total_price_found": "No total price found", "elements_not_found": "payeOui or cbField elements not found", - "not_found": "not found" + "not_found": "not found", + "page_navigation": "Page navigation" }, "errors": { "not_authenticated": "Not authenticated", diff --git a/translations/es.json b/translations/es.json index b216e70..cf76a92 100644 --- a/translations/es.json +++ b/translations/es.json @@ -129,7 +129,8 @@ "element_not_found": "elemento no encontrado", "no_total_price_found": "No se encontró precio total", "elements_not_found": "Elementos payeOui o cbField no encontrados", - "not_found": "no encontrado" + "not_found": "no encontrado", + "page_navigation": "Navegación de páginas" }, "errors": { "not_authenticated": "No autenticado", @@ -200,5 +201,22 @@ "unimpose": { "pdf_unimposed_success": "Su PDF ha sido desimponido exitosamente", "file_ready_download": "El archivo :file está listo para descargar." + }, + "stats": { + "title": "Estadísticas", + "intro_text": "Desde el inicio de la aventura dupli en 2011, hemos impreso un total de {nb_f} páginas en más de {nb_t} veces. Si miramos más de cerca, eso nos da un promedio de {nb_t_par_mois} impresiones por mes, con aproximadamente {nbf_par_mois} hojas en promedio. Imprimes {nb_moy_par_mois} copias por impresión. No te ahorro la facturación: {ca} euros desde el inicio, si quitamos los {doit} euros que nos deben: {ca2} euros. Nos has dado {ca1} euros. Por lo tanto, somos {benf} euros, pero eso es sin contar el precio del alquiler de los condos que a razón de 50 euros por mes nos haría... ! Los big data están ahí, te dejo mirar :) ps: ¡y también son 1800 líneas de código!", + "monthly_stats": "Estadísticas por mes", + "date": "Fecha", + "sheets": "Hojas", + "prints": "Impresiones", + "average": "Promedio", + "price": "Precio", + "price_paid": "Precio pagado", + "difference": "Diferencia", + "user_paid": "Cuánto pagó el usuario", + "sheets_count": "número de hojas", + "sheets_per_print": "número de hojas por impresión", + "prints_count": "número de impresiones", + "monthly_profit": "Ganancia para este mes" } } \ No newline at end of file diff --git a/translations/fr.json b/translations/fr.json index aa1aa6c..2150d1d 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -368,7 +368,11 @@ "price": "Prix", "price_paid": "Prix payé", "difference": "Différence", - "user_paid": "Combien l'utilisateur a payé" + "user_paid": "Combien l'utilisateur a payé", + "sheets_count": "nombre de feuilles", + "sheets_per_print": "nombre de feuilles par tirage", + "prints_count": "nombre de tirages", + "monthly_profit": "Gain pour ce mois" }, "tirage_multimachines": { "title": "Tirage Multi-Machines", @@ -877,7 +881,8 @@ "element_not_found": "élément non trouvé", "no_total_price_found": "Aucun prix total trouvé", "elements_not_found": "Éléments payeOui ou cbField non trouvés", - "not_found": "non trouvé" + "not_found": "non trouvé", + "page_navigation": "Navigation des pages" }, "errors": { "not_authenticated": "Non authentifié", diff --git a/view/admin.edit.html.php b/view/admin.edit.html.php index 88fbd0d..eea6373 100755 --- a/view/admin.edit.html.php +++ b/view/admin.edit.html.php @@ -113,7 +113,7 @@ function getTableForMachine($machine) { + title=""> @@ -152,7 +152,7 @@ class="form-control" required type="text" + title=""> @@ -163,7 +163,7 @@ class="form-control" required type="number" min="0" + title=""> @@ -174,7 +174,7 @@ class="form-control" required type="number" min="0" + title=""> @@ -185,7 +185,7 @@ class="form-control" required type="number" min="0" + title=""> @@ -208,7 +208,7 @@ class="form-control" required type="number" min="0" + title=""> @@ -266,7 +266,7 @@ class="form-control" required type="number" min="1" + title=""> @@ -314,7 +314,7 @@ class="form-control" type="number" step="0.01" min="0" + title=""> diff --git a/view/stats.html.php b/view/stats.html.php index 2c5a646..ab132eb 100755 --- a/view/stats.html.php +++ b/view/stats.html.php @@ -61,12 +61,12 @@ - - - + + + € - € + -