diff --git a/frontend/src/i18n/index.ts b/frontend/src/i18n/index.ts index 76a74fec6..a16b4f24b 100644 --- a/frontend/src/i18n/index.ts +++ b/frontend/src/i18n/index.ts @@ -5,12 +5,14 @@ import LanguageDetector from 'i18next-browser-languagedetector'; // Import translations directly for bundling import en from './locales/en'; import de from './locales/de'; +import fr from './locales/fr'; import ja from './locales/ja'; import it from './locales/it'; const resources = { en: { translation: en }, de: { translation: de }, + fr: { translation: fr }, ja: { translation: ja }, it: { translation: it }, }; @@ -21,7 +23,7 @@ i18n .init({ resources, fallbackLng: 'en', - supportedLngs: ['en', 'de', 'ja', 'it'], + supportedLngs: ['en', 'de', 'fr', 'ja', 'it'], detection: { // Order of detection methods @@ -47,6 +49,7 @@ export default i18n; export const availableLanguages = [ { code: 'en', name: 'English', nativeName: 'English' }, { code: 'de', name: 'German', nativeName: 'Deutsch' }, + { code: 'fr', name: 'French', nativeName: 'Français' }, { code: 'ja', name: 'Japanese', nativeName: '日本語' }, { code: 'it', name: 'Italian', nativeName: 'Italiano' }, ]; diff --git a/frontend/src/i18n/locales/fr.ts b/frontend/src/i18n/locales/fr.ts new file mode 100644 index 000000000..58da14753 --- /dev/null +++ b/frontend/src/i18n/locales/fr.ts @@ -0,0 +1,2955 @@ +export default { + // Navigation + nav: { + printers: 'Imprimantes', + archives: 'Archives', + queue: 'File d\'attente', + stats: 'Statistiques', + profiles: 'Profils', + maintenance: 'Maintenance', + projects: 'Projets', + files: 'Gestionnaire de fichiers', + settings: 'Paramètres', + system: 'Système', + collapseSidebar: 'Réduire la barre latérale', + expandSidebar: 'Développer la barre latérale', + update: 'Mise à jour', + updateAvailable: 'Mise à jour disponible : v{{version}}', + updateAvailableBanner: 'La version {{version}} est disponible !', + viewUpdate: 'Voir la mise à jour', + viewOnGithub: 'Voir sur GitHub', + keyboardShortcuts: 'Raccourcis clavier (?)', + switchToLight: 'Passer au mode clair', + switchToDark: 'Passer au mode sombre', + smartSwitches: 'Interrupteurs intelligents', + logout: 'Déconnexion', + }, + + // Common + common: { + save: 'Enregistrer', + saving: 'Enregistrement...', + cancel: 'Annuler', + delete: 'Supprimer', + edit: 'Modifier', + add: 'Ajouter', + close: 'Fermer', + confirm: 'Confirmer', + loading: 'Chargement...', + error: 'Erreur', + success: 'Succès', + warning: 'Avertissement', + enabled: 'Activé', + disabled: 'Désactivé', + yes: 'Oui', + no: 'Non', + on: 'On', + off: 'Off', + all: 'Tous', + none: 'Aucun', + search: 'Rechercher', + filter: 'Filtrer', + sort: 'Trier', + refresh: 'Actualiser', + download: 'Télécharger', + upload: 'Téléverser', + actions: 'Actions', + status: 'Statut', + name: 'Nom', + description: 'Description', + date: 'Date', + time: 'Heure', + hours: 'heures', + minutes: 'minutes', + seconds: 'secondes', + days: 'jours', + enable: 'Activer', + disable: 'Désactiver', + permissions: 'Autorisations', + noPrinters: 'Aucune imprimante configurée', + noData: 'Aucune donnée disponible', + linkNotFound: 'Lien non trouvé', + required: 'Requis', + optional: 'Optionnel', + dismiss: 'Ignorer', + apply: 'Appliquer', + reset: 'Réinitialiser', + clear: 'Effacer', + selectAll: 'Tout sélectionner', + deselectAll: 'Tout désélectionner', + noChange: '— Aucun changement —', + unchanged: 'Inchangé', + unassigned: 'Non assigné', + unknown: 'Inconnu', + unknownError: 'Erreur inconnue', + today: 'Aujourd\'hui', + asap: 'Dès que possible', + overdue: 'En retard', + now: 'Maintenant', + collapse: 'Réduire', + expand: 'Développer', + viewArchive: 'Voir l\'archive', + viewInFileManager: 'Voir dans le gestionnaire de fichiers', + addedBy: 'Ajouté par {{username}}', + prints: 'impressions', + more: '+{{count}} de plus', + ascending: 'Croissant', + descending: 'Décroissant', + printer: 'Imprimante', + remove: 'Retirer', + type: 'Type', + print: 'Imprimer', + rename: 'Renommer', + move: 'Déplacer', + create: 'Créer', + duplicate: 'Dupliquer', + left: 'Gauche', + right: 'Droite', + }, + + // Printers page + printers: { + title: 'Imprimantes', + addPrinter: 'Ajouter une imprimante', + editPrinter: 'Modifier l\'imprimante', + deletePrinter: 'Supprimer l\'imprimante', + printerName: 'Nom de l\'imprimante', + serialNumber: 'Numéro de série', + ipAddress: 'Adresse IP / Nom d\'hôte', + accessCode: 'Code d\'accès', + model: 'Modèle', + nozzleCount: 'Nombre de buses', + autoArchive: 'Auto-archivage', + status: { + idle: 'Inactif', + printing: 'Impression en cours', + paused: 'En pause', + offline: 'Hors ligne', + error: 'Erreur', + finished: 'Terminé', + unknown: 'Inconnu', + }, + temperatures: { + nozzle: 'Buse', + bed: 'Plateau', + chamber: 'Chambre', + }, + progress: '{{percent}}% terminé', + timeRemaining: '{{time}} restant', + deleteConfirm: 'Êtes-vous sûr de vouloir supprimer "{{name}}" ?', + maintenanceOk: 'Maintenance OK', + maintenanceWarning: '{{count}} avertissement', + maintenanceWarning_plural: '{{count}} avertissements', + maintenanceDue: '{{count}} échéance', + maintenanceDue_plural: '{{count}} échéances', + sort: { + name: 'Nom', + status: 'Statut', + model: 'Modèle', + location: 'Emplacement', + ascending: 'Tri croissant', + descending: 'Tri décroissant', + }, + cardSize: { + small: 'Petites cartes', + medium: 'Cartes moyennes', + large: 'Grandes cartes', + extraLarge: 'Très grandes cartes', + }, + hideOffline: 'Masquer les imprimantes hors ligne', + powerOn: 'Allumer', + offlinePrintersWithPlugs: 'Imprimantes hors ligne avec prises connectées', + noPrintersConfigured: 'Aucune imprimante configurée pour le moment', + readyToPrint: 'Prête à imprimer', + external: 'Externe', + deleteArchives: 'Supprimer les archives d\'impression', + noLabel: 'Pas d\'étiquette', + printPreview: 'Aperçu avant impression', + width: 'Largeur', + height: 'Hauteur', + noObjectsFound: 'Aucun objet trouvé', + objectsLoadedOnPrintStart: 'Les objets sont chargés au début de l\'impression', + willBeSkipped: 'Sera sauté', + name: 'Nom', + serialCannotBeChanged: 'Le numéro de série ne peut pas être modifié', + locationHelp: 'Utilisé pour grouper les imprimantes et filtrer la file d\'attente', + wifiSignal: { + veryWeak: 'Très faible', + weak: 'Faible', + fair: 'Moyen', + good: 'Bon', + excellent: 'Excellent', + }, + maintenanceUpToDate: 'Maintenance à jour - Cliquez pour voir', + chamberLightOn: 'Allumer la lumière de la chambre', + chamberLightOff: 'Éteindre la lumière de la chambre', + browseFiles: 'Parcourir les fichiers de l\'imprimante', + autoOffAfterPrint: 'Extinction auto après impression', + autoOffExecuted: 'Extinction auto exécutée - rallumez pour réinitialiser', + hmsErrors: 'Erreurs HMS', + viewHmsErrors: 'Voir {{count}} erreur(s) HMS', + resume: 'Reprendre', + pause: 'Pause', + stop: 'Arrêter', + camera: 'Caméra', + skipObject: 'Sauter l\'objet', + reconnect: 'Reconnecter', + mqttDebug: 'Débogage MQTT', + activeNozzle: 'Active : buse {{nozzle}}', + nozzleRack: 'Rack à buses', + nozzleDocked: 'Rangée', + nozzleMounted: 'Montée', + nozzleActive: 'Active', + nozzleIdle: 'Inactive', + nozzleDiameter: 'Diamètre', + nozzleType: 'Type', + nozzleStatus: 'Statut', + nozzleFilament: 'Filament', + nozzleWear: 'Usure', + nozzleMaxTemp: 'Temp Max', + nozzleSerial: 'Série', + nozzleHardenedSteel: 'Acier Trempé', + nozzleStainlessSteel: 'Acier Inoxydable', + nozzleTungstenCarbide: 'Carbure de Tungstène', + nozzleFlow: 'Débit', + nozzleHighFlow: 'Haut débit', + nozzleStandardFlow: 'Standard', + firmwareUpdate: 'Mise à jour Firmware', + firmwareInstructions: 'Sur l\'écran de l\'imprimante, allez dans', + firmwareNav: 'Naviguez vers', + settings: 'Paramètres', + firmware: 'Firmware', + discoverPrinters: 'Découvrir les imprimantes', + searching: 'Recherche...', + manualEntry: 'Saisie manuelle', + addFromCloud: 'Ajouter depuis le Cloud', + toast: { + printerDeleted: 'Imprimante supprimée', + printerAdded: 'Imprimante ajoutée', + printerUpdated: 'Imprimante mise à jour', + failedToDelete: 'Échec de la suppression', + failedToAdd: 'Échec de l\'ajout', + failedToUpdate: 'Échec de la mise à jour', + commandSent: 'Commande envoyée', + failedToSendCommand: 'Échec de l\'envoi de la commande', + turnedOn: '{{name}} allumée', + failedToPowerOn: 'Échec de l\'allumage de {{name}}', + scriptTriggered: 'Script déclenché', + printStopped: 'Impression arrêtée', + printPaused: 'Impression en pause', + printResumed: 'Impression reprise', + referenceDeleted: 'Référence supprimée', + detectionAreaSaved: 'Zone de détection enregistrée', + failedToRunScript: 'Échec du script', + failedToStopPrint: 'Échec de l\'arrêt', + failedToPausePrint: 'Échec de la mise en pause', + failedToResumePrint: 'Échec de la reprise', + failedToControlChamberLight: 'Échec du contrôle de la lumière', + failedToUpdateSetting: 'Échec de mise à jour du paramètre', + failedToSkipObjects: 'Échec du saut d\'objets', + failedToRereadRfid: 'Échec lecture RFID', + failedToCheckPlate: 'Échec vérification plateau', + failedToUpdateLabel: 'Échec mise à jour étiquette', + failedToDeleteReference: 'Échec suppression référence', + failedToSaveDetectionArea: 'Échec enregistrement zone', + plateCheckEnabled: 'Vérification plateau activée', + plateCheckDisabled: 'Vérification plateau désactivée', + calibrationSaved: 'Calibration enregistrée !', + calibrationFailed: 'Échec de la calibration', + rfidRereadInitiated: 'Lecture RFID initiée', + }, + connection: { + connected: 'Connecté', + offline: 'Hors ligne', + }, + queue: { + inQueue: '{{count}} impression en file', + inQueue_plural: '{{count}} impressions en file', + }, + controls: 'Contrôles', + rfid: { + reread: 'Relire RFID', + }, + permission: { + noAdd: 'Pas d\'autorisation pour ajouter', + noEdit: 'Pas d\'autorisation pour modifier', + noDelete: 'Pas d\'autorisation pour supprimer', + noControl: 'Pas d\'autorisation pour contrôler', + noFiles: 'Pas d\'autorisation pour les fichiers', + noAmsRfid: 'Pas d\'autorisation pour le RFID', + noSmartPlugControl: 'Pas d\'autorisation pour les prises', + }, + modal: { + addTitle: 'Ajouter une imprimante', + editTitle: 'Modifier l\'imprimante', + myPrinter: 'Mon imprimante', + selectModel: 'Choisir un modèle...', + locationGroup: 'Emplacement / Groupe (optionnel)', + locationPlaceholder: 'ex: Atelier, Bureau', + autoArchiveLabel: 'Auto-archiver les impressions terminées', + fromPrinterSettings: 'Depuis les paramètres imprimante', + modelOptional: 'Modèle (optionnel)', + saveChanges: 'Enregistrer les modifications', + }, + skipObjects: { + tooltip: 'Sauter des objets', + onlyWhilePrinting: 'Sauter (uniquement pendant l\'impression)', + requiresMultiple: 'Sauter (nécessite 2+ objets)', + title: 'Sauter des objets', + matchIdsInfo: 'Faites correspondre les IDs avec l\'écran de l\'imprimante', + printerShowsIds: 'L\'écran affiche les IDs des objets sur le plateau', + skipSelected: 'Sauter la sélection', + skipping: 'Saut en cours...', + noObjectsSelected: 'Aucun objet sélectionné', + selectObjectsToSkip: 'Sélectionnez les objets à ignorer', + skipped: 'sauté', + objectsSkipped: 'Objets sautés', + activeCount: '{{count}} actifs', + waitForLayer: 'Attendez la couche 2 pour sauter des objets (couche actuelle : {{layer}})', + skip: 'Sauter', + }, + confirm: { + deleteTitle: 'Supprimer l\'imprimante', + deleteMessage: 'Supprimer "{{name}}" ? Cela retirera tous les paramètres de connexion.', + deleteArchivesNote: 'Tout l\'historique sera définitivement supprimé.', + keepArchivesNote: 'L\'historique sera conservé mais plus associé à cette imprimante.', + stopTitle: 'Arrêter l\'impression', + stopMessage: 'Arrêter l\'impression sur "{{name}}" ?', + stopButton: 'Arrêter', + pauseTitle: 'Mettre en pause', + pauseMessage: 'Mettre en pause l\'impression sur "{{name}}" ?', + pauseButton: 'Pause', + resumeTitle: 'Reprendre l\'impression', + resumeMessage: 'Reprendre l\'impression sur "{{name}}" ?', + resumeButton: 'Reprendre', + powerOnTitle: 'Allumer l\'imprimante', + powerOnMessage: 'Allumer "{{name}}" ?', + powerOnButton: 'Allumer', + powerOffTitle: 'Éteindre l\'imprimante', + powerOffMessage: 'Éteindre "{{name}}" ?', + powerOffWarning: 'ATTENTION : "{{name}}" imprime ! L\'éteindre maintenant peut endommager l\'imprimante.', + powerOffButton: 'Éteindre', + }, + discovery: { + title: 'Découvrir les imprimantes', + searching: 'Recherche...', + scanning: 'Scan en cours...', + scanProgress: 'Scan... {{scanned}}/{{total}}', + foundPrinters: '{{count}} imprimante(s) trouvée(s)', + noPrintersFound: 'Aucune imprimante trouvée', + noPrintersFoundSubnet: 'Aucune imprimante dans ce sous-réseau.', + noPrintersFoundNetwork: 'Aucune imprimante sur le réseau.', + allConfigured: 'Toutes les imprimantes trouvées sont déjà configurées.', + alreadyAdded: 'Déjà ajoutée', + select: 'Sélectionner', + manualEntry: 'Saisie manuelle', + addFromCloud: 'Ajouter depuis le Cloud', + subnetToScan: 'Sous-réseau à scanner', + dockerNote: 'Docker détecté. Entrez le sous-réseau en notation CIDR. Nécessite network_mode: host.', + scanSubnet: 'Scanner le sous-réseau', + discoverNetwork: 'Découvrir sur le réseau', + scanningSubnet: 'Scan du sous-réseau pour imprimantes Bambu...', + scanningNetwork: 'Scan du réseau...', + serialRequired: 'Série requis', + unknown: 'Inconnu', + failedToStart: 'Échec du démarrage de la découverte', + }, + filaments: 'Filaments', + openCameraOverlay: 'Ouvrir la caméra en superposition', + openCameraWindow: 'Ouvrir la caméra dans une fenêtre', + firmwareUpdateAvailable: 'Mise à jour firmware : {{current}} → {{latest}}', + firmwareUpToDate: 'Firmware {{version}} — À jour', + firmwareUpdateButton: 'Mettre à jour', + plateDetection: { + noPermission: 'Pas d\'autorisation de modification', + enabledClick: 'Vérification activée - Cliquez pour désactiver', + disabledClick: 'Vérification désactivée - Cliquez pour activer', + manageCalibration: 'Gérer la calibration de détection', + calibrationRequired: 'Calibration requise', + calibrationInstructions: 'Videz le plateau, puis cliquez sur Calibrer.', + calibrationDescription: 'Capture une image de référence du plateau vide.', + calibrationTip: 'Conseil : Stockez jusqu\'à 5 références pour différents plateaux.', + plateEmpty: 'Le plateau semble vide', + objectsDetected: 'Objets détectés sur le plateau', + confidence: 'Confiance', + difference: 'Différence', + analysisPreview: 'Aperçu de l\'analyse :', + analysisLegend: 'Cadre vert = zone, Rouge = différences', + savedReferences: 'Références ({{count}}/{{max}})', + deleteReference: 'Supprimer la référence', + labelPlaceholder: 'Étiquette...', + clickToEdit: '{{label}} - Modifier', + clickToAddLabel: 'Ajouter une étiquette', + }, + fans: { + partCooling: 'Ventilateur pièce', + auxiliary: 'Ventilateur auxiliaire', + chamber: 'Ventilateur chambre', + }, + clickToViewHmsErrors: 'Cliquez pour voir les erreurs HMS', + estimatedCompletion: 'Fin estimée', + slotOptions: 'Options du slot', + firmwareModal: { + title: 'Mise à jour Firmware', + titleUpToDate: 'Infos Firmware', + currentVersion: 'Actuelle :', + latestVersion: 'Dernière :', + releaseNotes: 'Notes de version', + checkingPrereqs: 'Vérification des prérequis...', + sdCardReady: 'Carte SD prête. Cliquez pour téléverser.', + uploadedSuccess: 'Firmware téléversé !', + applyInstructions: 'Pour appliquer sur l\'imprimante :', + step1: 'Sur l\'écran, allez dans Paramètres', + step2: 'Allez dans Firmware', + step3: 'Sélectionnez "Mettre à jour depuis carte SD"', + step4: 'Prévoyez 10-20 minutes', + done: 'Terminé', + starting: 'Démarrage...', + uploadFirmware: 'Téléverser le Firmware', + uploadFailed: 'Échec du téléversement : {{error}}', + uploadedToast: 'Firmware téléversé ! Lancez la mise à jour sur l\'écran.', + }, + accessCodePlaceholder: 'Laissez vide pour garder l\'actuel', + roi: { + title: 'Zone de détection (ROI)', + xStart: 'Début X', + yStart: 'Début Y', + width: 'Largeur', + height: 'Hauteur', + instruction: 'Ajustez le cadre vert pour cibler le plateau.', + }, + }, + + // Archives page + archives: { + title: 'Archives d\'impression', + searchPlaceholder: 'Chercher dans les archives...', + filterByPrinter: 'Par imprimante', + filterByStatus: 'Par statut', + sortBy: 'Trier par', + sortNewest: 'Plus récent', + sortOldest: 'Plus ancien', + sortName: 'Nom', + sortDuration: 'Durée', + sortLargest: 'Plus volumineux', + sortSmallest: 'Plus léger', + sortSize: 'Taille', + noArchives: 'Aucune archive trouvée', + noArchivesSearch: 'Aucune archive ne correspond', + noArchivesYet: 'Pas encore d\'archive', + loadingArchives: 'Chargement...', + releaseToUpload: 'Relâcher pour téléverser', + showAll: 'Tout afficher', + showFavoritesOnly: 'Favoris uniquement', + gridView: 'Grille', + listView: 'Liste', + calendarView: 'Calendrier', + manageTags: 'Gérer les tags', + showFailedPrints: 'Afficher les échecs', + hideFailedPrints: 'Masquer les échecs', + printTime: 'Temps d\'impression', + filamentUsed: 'Filament utilisé', + cost: 'Coût', + reprint: 'Réimprimer', + preview: 'Aperçu', + deleteArchive: 'Supprimer l\'archive', + deleteConfirm: 'Supprimer cette archive ?', + favorite: 'Favori', + unfavorite: 'Retirer des favoris', + viewDetails: 'Détails', + status: { + completed: 'Réussi', + failed: 'Échoué', + stopped: 'Arrêté', + }, + toast: { + source3mfAttached: 'Source 3MF attachée : {{filename}}', + failedUploadSource3mf: 'Échec téléversement 3MF', + source3mfRemoved: 'Source 3MF retirée', + failedRemoveSource3mf: 'Échec retrait 3MF', + f3dAttached: 'F3D attaché : {{filename}}', + failedUploadF3d: 'Échec téléversement F3D', + f3dRemoved: 'F3D retiré', + failedRemoveF3d: 'Échec retrait F3D', + timelapseAttached: 'Timelapse attaché : {{filename}}', + timelapseAlreadyAttached: 'Timelapse déjà présent', + noMatchingTimelapse: 'Pas de timelapse correspondant', + failedScanTimelapse: 'Échec scan timelapse', + failedAttachTimelapse: 'Échec attache timelapse', + archiveDeleted: 'Archive supprimée', + failedDeleteArchive: 'Échec suppression', + addedToFavorites: 'Ajouté aux favoris', + removedFromFavorites: 'Retiré des favoris', + projectUpdated: 'Projet mis à jour', + failedUpdateProject: 'Échec mise à jour projet', + linkCopied: 'Lien copié', + failedCopyLink: 'Échec copie lien', + photoDeleted: 'Photo supprimée', + failedDeletePhoto: 'Échec suppression photo', + failedDeleteArchives: 'Échec suppression archives', + failedUpdateFavorites: 'Échec mise à jour favoris', + exportDownloaded: 'Export téléchargé', + exportFailed: 'Échec export', + }, + menu: { + print: 'Imprimer', + schedule: 'Planifier', + openInBambuStudio: 'Ouvrir dans le Slicer', + slice: 'Découper', + externalLink: 'Lien externe', + viewOnMakerWorld: 'Voir sur MakerWorld', + preview3d: 'Aperçu 3D', + viewTimelapse: 'Voir le Timelapse', + scanForTimelapse: 'Scanner pour Timelapse', + downloadSource3mf: 'Télécharger Source 3MF', + uploadSource3mf: 'Téléverser Source 3MF', + replaceSource3mf: 'Remplacer Source 3MF', + removeSource3mf: 'Retirer Source 3MF', + uploadF3d: 'Téléverser F3D', + replaceF3d: 'Remplacer F3D', + downloadF3d: 'Télécharger F3D', + removeF3d: 'Retirer F3D', + download: 'Télécharger', + copyDownloadLink: 'Copier lien de téléchargement', + qrCode: 'Code QR', + viewPhotos: 'Voir les photos', + viewPhotosCount: 'Voir les photos ({{count}})', + projectPage: 'Page du Projet', + addToFavorites: 'Ajouter aux favoris', + removeFromFavorites: 'Retirer des favoris', + edit: 'Modifier', + goToProject: 'Aller au Projet : {{name}}', + addToProject: 'Ajouter au Projet', + removeFromProject: 'Retirer du Projet', + loading: 'Chargement...', + noProjectsAvailable: 'Aucun projet disponible', + select: 'Sélectionner', + deselect: 'Désélectionner', + delete: 'Supprimer', + }, + permission: { + noReprint: 'Pas d\'autorisation de réimpression', + noAddToQueue: 'Pas d\'autorisation pour la file', + noUpdateArchives: 'Pas d\'autorisation de mise à jour', + noUploadFiles: 'Pas d\'autorisation de téléversement', + noDownload: 'Pas d\'autorisation de téléchargement', + noCopyLink: 'Pas d\'autorisation de copie lien', + noDelete: 'Pas d\'autorisation de suppression', + noCreate: 'Pas d\'autorisation de création', + }, + card: { + previousPlate: 'Plateau précédent', + nextPlate: 'Plateau suivant', + plateNumber: 'Plateau {{index}}', + moreOptions: 'Clic droit pour plus d\'options', + addToFavorites: 'Ajouter aux favoris', + removeFromFavorites: 'Retirer des favoris', + cancelled: 'annulé', + failed: 'échoué', + duplicate: 'doublon', + duplicateTitle: 'Ce modèle a déjà été imprimé', + openSource3mf: 'Ouvrir 3MF dans Bambu Studio (clic droit pour plus)', + downloadF3d: 'Télécharger fichier Fusion 360', + viewTimelapse: 'Voir timelapse', + viewPhoto: 'Voir 1 photo', + viewPhotos: 'Voir {{count}} photos', + openFolder: 'Ouvrir le dossier : {{name}}', + slicedFile: 'Fichier découpé - prêt', + sourceFile: 'Fichier source uniquement - pas de mapping AMS', + gcode: 'GCODE', + source: 'SOURCE', + project: 'Projet : {{name}}', + estimated: 'Estimé : {{time}}', + actual: 'Réel : {{time}}', + accuracy: 'Précision : {{percent}}%', + filament: '{{weight}}g', + layer: '{{count}} couche', + layers: '{{count}} couches', + object: '{{count}} objet', + objects: '{{count}} objets', + slicedFor: 'Découpé pour {{model}}', + uploadedBy: 'Téléversé par', + noPermissionReprint: 'Pas d\'autorisation de réimpression', + noPermissionEdit: 'Pas d\'autorisation de modification', + noPermissionDelete: 'Pas d\'autorisation de suppression', + reprint: 'Réimprimer', + schedulePrint: 'Planifier', + schedule: 'Planifier', + openInBambuStudio: 'Ouvrir dans le Slicer', + openInBambuStudioToSlice: 'Ouvrir dans le Slicer pour découper', + slice: 'Découper', + externalLink: 'Lien externe', + makerWorld: 'MakerWorld : {{designer}}', + viewProject: 'Voir projet', + noExternalLink: 'Aucun lien externe', + preview3d: 'Aperçu 3D', + download: 'Télécharger', + edit: 'Modifier', + delete: 'Supprimer', + }, + modal: { + deleteArchive: 'Supprimer l\'archive', + deleteConfirm: 'Supprimer "{{name}}" ? Cette action est irréversible.', + deleteButton: 'Supprimer', + removeSource3mf: 'Retirer Source 3MF', + removeSource3mfConfirm: 'Retirer le fichier 3MF de "{{name}}" ?', + removeButton: 'Retirer', + removeF3d: 'Retirer F3D', + removeF3dConfirm: 'Retirer le fichier Fusion 360 de "{{name}}" ?', + timelapse: '{{name}} - Timelapse', + selectTimelapse: 'Choisir un Timelapse', + selectTimelapseDesc: 'Sélectionnez manuellement le timelapse :', + deleteArchives: 'Supprimer les archives', + deleteArchivesConfirm: 'Supprimer {{count}} archive(s) ?', + deleteCount: 'Supprimer {{count}}', + }, + page: { + title: 'Archives', + printsCount: '{{filtered}} sur {{total}} impressions', + dropFilesHere: 'Déposez les fichiers .3mf ici', + releaseToUpload: 'Relâcher pour téléverser', + only3mfSupported: 'Seuls les fichiers .3mf sont supportés', + close: 'Fermer', + selected: '{{count}} sélectionnés', + selectAll: 'Tout sélectionner', + tags: 'Tags', + project: 'Projet', + favorite: 'Favori', + delete: 'Supprimer', + toggledFavorites: 'Favoris mis à jour pour {{count}} archive(s)', + failedUpdateFavorites: 'Échec mise à jour favoris', + archivesDeleted: '{{count}} archive(s) supprimée(s)', + failedDeleteArchives: 'Échec suppression', + photoDeleted: 'Photo supprimée', + failedDeletePhoto: 'Échec suppression photo', + }, + list: { + name: 'Nom', + printer: 'Imprimante', + date: 'Date', + size: 'Taille', + actions: 'Actions', + hasTimelapse: 'A un timelapse', + }, + }, + + // Queue page + queue: { + title: 'File d\'attente', + subtitle: 'Gérez vos travaux d\'impression', + addToQueue: 'Ajouter à la file', + print: 'Imprimer', + reprint: 'Réimprimer', + schedulePrint: 'Planifier', + editQueueItem: 'Modifier l\'élément', + printToPrinters: 'Imprimer sur {{count}} imprimantes', + queueToPrinters: 'Ajouter à la file pour {{count}} imprimantes', + sending: 'Envoi...', + sendingProgress: 'Envoi {{current}}/{{total}}...', + adding: 'Ajout...', + addingProgress: 'Ajout {{current}}/{{total}}...', + savingProgress: 'Enregistrement {{current}}/{{total}}...', + clearQueue: 'Vider la file', + clearHistory: 'Effacer l\'historique', + emptyQueue: 'La file est vide', + position: 'Position', + scheduledTime: 'Heure prévue', + moveUp: 'Monter', + moveDown: 'Descendre', + startNow: 'Démarrer maintenant', + printingInProgress: 'Impression en cours...', + viewArchive: 'Voir l\'archive', + viewInFileManager: 'Voir dans le gestionnaire', + itemCount: '{{count}} élément', + itemCount_plural: '{{count}} éléments', + dragToReorder: 'Glisser pour réordonner (ASAP uniquement)', + reorderHint: 'La position n\'affecte que les éléments ASAP.', + addedBy: 'Ajouté par {{name}}', + sections: { + currentlyPrinting: 'En cours', + queued: 'En attente', + history: 'Historique', + }, + status: { + pending: 'En attente', + waiting: 'En attente', + printing: 'Impression', + paused: 'En pause', + completed: 'Terminé', + failed: 'Échoué', + skipped: 'Sauté', + cancelled: 'Annulé', + }, + summary: { + printing: 'Impressions', + queued: 'En attente', + totalTime: 'Temps total estimé', + history: 'Historique', + }, + filter: { + allPrinters: 'Toutes les imprimantes', + unassigned: 'Non assigné', + allStatus: 'Tous les statuts', + allLocations: 'Tous les emplacements', + any: 'Tout', + }, + sort: { + byPosition: 'Par position', + byName: 'Par nom', + byPrinter: 'Par imprimante', + bySchedule: 'Par planification', + byDate: 'Par date', + ascendingOldest: 'Croissant (plus vieux)', + descendingNewest: 'Décroissant (plus récent)', + }, + badges: { + staged: 'Préparé', + requiresPrevious: 'Nécessite succès précédent', + autoPowerOff: 'Extinction auto', + }, + empty: { + title: 'Aucune impression prévue', + description: 'Planifiez depuis les Archives ou glissez des fichiers ici.', + }, + time: { + asap: 'Dès que possible', + overdue: 'En retard', + now: 'Maintenant', + lessThanMinute: 'Dans moins d\'une minute', + inMinutes: 'Dans {{count}} min', + inHours: 'Dans {{count}} heures', + }, + actions: { + stopPrint: 'Arrêter', + startPrint: 'Démarrer', + requeue: 'Remettre en file', + }, + bulkEdit: { + title: 'Modifier {{count}} élément', + title_plural: 'Modifier {{count}} éléments', + description: 'Seuls les changements seront appliqués.', + printer: 'Imprimante', + noChange: '— Aucun changement —', + queueOptions: 'Options de file', + staged: 'Préparé (manuel)', + autoPowerOff: 'Extinction auto après', + requirePrevious: 'Requiert succès précédent', + printOptions: 'Options d\'impression', + bedLevelling: 'Nivellement plateau', + flowCalibration: 'Calibration débit', + vibrationCalibration: 'Vibration (Input Shaper)', + layerInspection: 'Inspection 1ère couche', + timelapse: 'Timelapse', + useAms: 'Utiliser AMS', + applyChanges: 'Appliquer', + selectAll: 'Tout sélectionner', + deselectAll: 'Tout désélectionner', + selected: '{{count}} sélectionnés', + editSelected: 'Modifier la sélection', + cancelSelected: 'Annuler la sélection', + }, + confirm: { + cancelTitle: 'Annuler l\'impression prévue', + cancelMessage: 'Annuler "{{name}}" ?', + stopTitle: 'Arrêter l\'impression', + stopMessage: 'Arrêter "{{name}}" sur l\'imprimante ?', + removeTitle: 'Retirer de l\'historique', + removeMessage: 'Retirer "{{name}}" de l\'historique ?', + clearHistoryTitle: 'Effacer l\'historique', + clearHistoryMessage: 'Retirer les {{count}} éléments ?', + cancelButton: 'Annuler l\'impression', + stopButton: 'Arrêter l\'impression', + thisPrint: 'cette impression', + thisItem: 'cet élément', + }, + toast: { + cancelled: 'Élément annulé', + cancelFailed: 'Échec annulation', + removed: 'Élément retiré', + removeFailed: 'Échec retrait', + stopped: 'Impression arrêtée', + stopFailed: 'Échec arrêt', + released: 'Libéré dans la file', + startFailed: 'Échec démarrage', + reorderFailed: 'Échec réorganisation', + historyCleared: '{{count}} éléments effacés', + clearHistoryFailed: 'Échec effacement', + updateFailed: 'Échec mise à jour', + bulkCancelled: '{{count}} éléments annulés', + bulkCancelFailed: 'Échec annulation', + }, + permissions: { + noStopPrint: 'Pas d\'autorisation d\'arrêt', + noStartPrint: 'Pas d\'autorisation de démarrage', + noEdit: 'Pas d\'autorisation de modification', + noCancel: 'Pas d\'autorisation d\'annulation', + noRequeue: 'Pas d\'autorisation de remise en file', + noRemove: 'Pas d\'autorisation de retrait', + noClearHistory: 'Pas d\'autorisation historique', + noEditItems: 'Pas d\'autorisation modification groupée', + noCancelItems: 'Pas d\'autorisation annulation groupée', + }, + }, + + // Statistics page + stats: { + title: 'Tableau de bord', + subtitle: 'Glissez les widgets pour réorganiser. Cliquez sur l\'œil pour masquer.', + overview: 'Vue d\'ensemble', + totalPrints: 'Total impressions', + successRate: 'Taux de succès', + totalPrintTime: 'Temps total d\'impression', + printTime: 'Temps d\'impression', + totalFilament: 'Total filament utilisé', + filamentUsed: 'Filament utilisé', + filamentCost: 'Coût filament', + totalCost: 'Coût total', + energyUsed: 'Énergie consommée', + energyCost: 'Coût énergie', + averagePrintTime: 'Temps moyen par impression', + printsPerDay: 'Impressions par jour', + byPrinter: 'Par imprimante', + printsByPrinter: 'Impressions par imprimante', + byMaterial: 'Par matériau', + byMonth: 'Par mois', + last7Days: '7 derniers jours', + last30Days: '30 derniers jours', + last90Days: '90 derniers jours', + allTime: 'Tout le temps', + quickStats: 'Stats rapides', + printActivity: 'Activité d\'impression', + filamentTypes: 'Types de filament', + filamentTrends: 'Tendances filament', + failureAnalysis: 'Analyse des échecs', + timeAccuracy: 'Précision du temps', + successful: 'Succès :', + failed: 'Échecs :', + perfectEstimate: '100% = estimation parfaite', + noTimeAccuracyData: 'Pas encore de données de précision', + noFilamentData: 'Aucune donnée de filament', + noPrinterData: 'Aucune donnée d\'imprimante', + noPrintData: 'Aucune donnée d\'impression', + noPrintDataLast30Days: 'Aucune impression ces 30 derniers jours', + failureReasons: 'Raisons des échecs', + topFailureReasons: 'Top raisons d\'échec', + failedPrintsCount: '{{failed}} / {{total}} impressions ont échoué', + lastWeekRate: 'Semaine dernière : {{rate}}%', + resetLayout: 'Réinitialiser la mise en page', + recalculateCosts: 'Recalculer les coûts', + recalculateCostsHint: 'Recalcule les coûts avec les prix actuels des filaments', + exportStats: 'Exporter les stats', + exportAsCsv: 'Exporter en CSV', + exportAsExcel: 'Exporter en Excel', + hiddenCount: '{{count}} Masqués', + exportDownloaded: 'Export téléchargé', + exportFailed: 'Échec export', + layoutReset: 'Mise en page réinitialisée', + recalculatedCosts: 'Coûts recalculés pour {{count}} archives', + recalculateFailed: 'Échec du calcul', + loadingStats: 'Chargement des statistiques...', + noPermissionResetLayout: 'Pas d\'autorisation de réinitialisation', + noPermissionRecalculate: 'Pas d\'autorisation de recalcul', + }, + + // Maintenance page + maintenance: { + title: 'Maintenance', + overview: 'Vue d\'ensemble', + allOk: 'Toute la maintenance est à jour', + dueCount: '{{count}} tâche à faire', + dueCount_plural: '{{count}} tâches à faire', + warningCount: '{{count}} avertissement', + warningCount_plural: '{{count}} avertissements', + totalPrintTime: 'Temps d\'impression total', + nextMaintenance: 'Prochaine maintenance', + nothingDue: 'Rien de prévu', + tasks: 'Tâches', + lastPerformed: 'Dernière réalisation', + interval: 'Intervalle', + hoursRemaining: '{{hours}}h restantes', + hoursOverdue: '{{hours}}h de retard', + markDone: 'Marquer comme fait', + performMaintenance: 'Effectuer la maintenance', + history: 'Historique', + noHistory: 'Aucun historique', + editPrintHours: 'Modifier les heures d\'impression', + currentHours: 'Heures actuelles', + statusTab: 'Statut', + settingsTab: 'Paramètres', + overdueCount: '{{count}} en retard', + dueSoonCount: '{{count}} bientôt', + dueSoon: 'Bientôt', + allGood: 'Tout va bien', + overdueBy: 'Retard de {{duration}}', + dueIn: 'Dans {{duration}}', + timeLeft: '{{duration}} restant', + day: '1 jour', + days: '{{count}} jours', + week: '1 semaine', + weeks: '{{count}} semaines', + month: '1 mois', + months: '{{count}} mois', + year: '1 an', + maintenanceTypes: 'Types de maintenance', + maintenanceTypesDescription: 'Types système et tâches personnalisées', + addCustomType: 'Ajouter un type', + intervalType: 'Type d\'intervalle', + intervalValue: 'Intervalle ({{type}})', + icon: 'Icône', + documentationLink: 'Lien documentation (optionnel)', + assignToPrinters: 'Assigner aux imprimantes', + selectAtLeastOnePrinter: 'Sélectionnez au moins une imprimante', + addType: 'Ajouter le type', + custom: 'Personnalisé', + printHours: 'Heures d\'impression', + calendarDays: 'Jours calendaires', + exampleName: 'ex: Remplacement filtre HEPA', + viewDocumentation: 'Voir documentation', + timeBasedInterval: 'Intervalle temporel', + intervalOverrides: 'Exceptions d\'intervalle', + intervalOverridesDescription: 'Intervalles spécifiques par imprimante', + assignedToPrinters: 'Assigné aux imprimantes :', + noPrintersAssigned: 'Aucune imprimante assignée', + addPrinterShort: 'Ajouter :', + printersAssignedClick: '{{count}} imprimante(s) assignée(s) - gérer', + removeFromPrinter: 'Retirer de cette imprimante', + types: { + lubricateRails: 'Lubrifier les rails linéaires', + cleanNozzle: 'Nettoyer la buse / hotend', + checkBelts: 'Vérifier la tension des courroies', + cleanBuildPlate: 'Nettoyer le plateau', + checkExtruder: 'Vérifier les engrenages de l\'extrudeur', + checkCooling: 'Vérifier les ventilateurs', + generalInspection: 'Inspection générale', + cleanCarbonRods: 'Nettoyer les tiges carbone', + checkPtfeTube: 'Vérifier le tube PTFE', + replaceHepaFilter: 'Remplacer le filtre HEPA', + replaceCarbonFilter: 'Remplacer le filtre charbon', + lubricateLeftNozzleRail: 'Lubrifier le rail de buse gauche', + }, + maintenanceComplete: 'Maintenance marquée comme faite', + typeUpdated: 'Type mis à jour', + typeDeleted: 'Type supprimé', + printHoursUpdated: 'Heures mises à jour', + printerAssigned: 'Imprimante assignée', + printerRemoved: 'Imprimante retirée', + deleteTypeConfirm: 'Supprimer "{{name}}" ?', + noPermissionUpdate: 'Pas d\'autorisation de mise à jour', + noPermissionPerform: 'Pas d\'autorisation d\'action', + noPermissionEditTypes: 'Pas d\'autorisation de modification types', + noPermissionDeleteTypes: 'Pas d\'autorisation de suppression types', + noPermissionEditHours: 'Pas d\'autorisation de modification heures', + noPermissionRemovePrinter: 'Pas d\'autorisation retrait imprimante', + noPermissionAssignPrinter: 'Pas d\'autorisation assignation', + noPermissionEditIntervals: 'Pas d\'autorisation modification intervalles', + configureSettings: 'Configurer types et intervalles', + }, + + // Settings page + settings: { + title: 'Paramètres', + general: 'Général', + tabs: { + general: 'Général', + smartPlugs: 'Prises connectées', + notifications: 'Notifications', + filament: 'Filament', + network: 'Réseau', + apiKeys: 'Clés API', + virtualPrinter: 'Imprimante virtuelle', + users: 'Utilisateurs', + backup: 'Sauvegarde', + globalEmail: 'Email Global', + }, + email: { + smtpSettings: 'Configuration SMTP', + smtpHost: 'Serveur SMTP', + smtpPort: 'Port SMTP', + security: 'Sécurité', + authentication: 'Authentification', + username: 'Utilisateur', + password: 'Mot de passe', + fromEmail: 'Email expéditeur', + fromName: 'Nom expéditeur', + testConnection: 'Tester la connexion SMTP', + testRecipient: 'Email test destinataire', + sendTest: 'Envoyer email test', + sending: 'Envoi...', + save: 'Enregistrer les paramètres', + saving: 'Enregistrement...', + advancedAuth: 'Authentification avancée', + advancedAuthEnabled: 'L\'authentification avancée est activée', + advancedAuthEnabledDesc: 'Nouvelles fonctionnalités de gestion par email actives.', + advancedAuthDisabled: 'Authentification avancée désactivée', + advancedAuthDisabledDesc: 'Activez pour les fonctionnalités liées à l\'email.', + enable: 'Activer', + disable: 'Désactiver', + feature1: 'Génération auto et envoi de mots de passe par email', + feature2: 'Connexion par utilisateur ou email', + feature3: 'Mot de passe oublié disponible', + feature4: 'Réinitialisation admin par email', + errors: { + requiredFields: 'Remplissez tous les champs requis', + usernameRequired: 'L\'utilisateur est requis pour l\'authentification', + enterTestEmail: 'Entrez une adresse email de test', + smtpServerAndEmail: 'Serveur et expéditeur requis pour le test', + usernamePasswordRequired: 'Utilisateur et mot de passe requis pour l\'auth', + configureSmtpFirst: 'Configurez et testez le SMTP d\'abord', + }, + success: { + settingsSaved: 'Paramètres SMTP enregistrés', + }, + securityOptions: { + starttls: 'STARTTLS (Port 587)', + ssl: 'SSL/TLS (Port 465)', + none: 'Aucun (Port 25)', + }, + authOptions: { + enabled: 'Activée', + disabled: 'Désactivée', + }, + }, + appearance: 'Apparence', + notifications: 'Notifications', + smartPlugs: 'Prises connectées', + spoolman: 'Spoolman', + updates: 'Mises à jour', + language: 'Langue', + languageDescription: 'Choisissez votre langue', + theme: 'Thème', + themeLight: 'Clair', + themeDark: 'Sombre', + themeSystem: 'Système', + defaultView: 'Vue par défaut', + defaultViewDescription: 'Page affichée au démarrage', + checkForUpdates: 'Vérifier les mises à jour', + autoUpdate: 'Mise à jour auto', + currentVersion: 'Version actuelle', + latestVersion: 'Dernière version', + upToDate: 'Bambuddy est à jour', + updateAvailable: 'Mise à jour disponible', + notificationLanguage: 'Langue des notifications', + notificationLanguageDescription: 'Langue pour les notifications push', + notificationProviders: 'Fournisseurs de notifications', + addProvider: 'Ajouter un fournisseur', + editProvider: 'Modifier le fournisseur', + providerType: 'Type de fournisseur', + testNotification: 'Tester la notification', + testSuccess: 'Notification de test envoyée', + testFailed: 'Échec de l\'envoi du test', + quietHours: 'Heures de silence', + quietHoursDescription: 'Ne pas déranger pendant ces heures', + quietHoursStart: 'Début', + quietHoursEnd: 'Fin', + events: { + title: 'Événements de notification', + printStart: 'Impression démarrée', + printComplete: 'Impression terminée', + printFailed: 'Impression échouée', + printStopped: 'Impression arrêtée', + printProgress: 'Jalons de progression', + printProgressDescription: 'Notifier à 25%, 50%, 75%', + printerOffline: 'Imprimante hors ligne', + printerError: 'Erreur imprimante', + filamentLow: 'Filament bas', + maintenanceDue: 'Maintenance due', + maintenanceDueDescription: 'Notifier quand une tâche est due', + }, + smartPlug: { + title: 'Prises connectées', + add: 'Ajouter une prise', + edit: 'Modifier la prise', + name: 'Nom', + ipAddress: 'Adresse IP', + linkedPrinter: 'Imprimante liée', + autoOn: 'Allumage auto', + autoOnDescription: 'Allumer au début de l\'impression', + autoOff: 'Extinction auto', + autoOffDescription: 'Éteindre après l\'impression', + offDelay: 'Délai d\'extinction', + offDelayMinutes: 'Minutes après fin', + offDelayTemp: 'Quand la buse est sous', + currentState: 'État actuel', + turnOn: 'Allumer', + turnOff: 'Éteindre', + }, + spoolmanEnabled: 'Activer l\'intégration Spoolman', + spoolmanUrl: 'URL Spoolman', + spoolmanConnected: 'Connecté', + spoolmanDisconnected: 'Déconnecté', + noDefaultPrinter: 'Aucune par défaut (demander à chaque fois)', + sidebarOrder: 'Ordre de la barre latérale', + saveThumbnails: 'Enregistrer les vignettes', + captureFinishPhoto: 'Prendre une photo à la fin', + noPrintersConfigured: 'Aucune imprimante configurée', + archiveMode: { + always: 'Toujours créer une archive', + never: 'Ne jamais créer d\'archive', + ask: 'Demander à chaque fois', + }, + checkForUpdatesLabel: 'Vérifier les mises à jour', + checkPrinterFirmware: 'Vérifier le firmware imprimante', + enableRetry: 'Activer la rétentative', + homeAssistantDescription: 'Contrôler les prises via Home Assistant', + environmentManagedLabel: '(Géré par l\'environnement)', + autoEnabledViaEnv: 'Activé via variables d\'environnement', + urlFromEnvReadOnly: 'Valeur HA_URL (lecture seule)', + tokenFromEnvReadOnly: 'Valeur HA_TOKEN (lecture seule)', + mqttConnectedTo: 'Connecté à', + prometheusDescription: 'Exposer les données au format Prometheus', + noSmartPlugsTitle: 'Aucune prise configurée', + noSmartPlugsDescription: 'Ajoutez une prise Tasmota pour suivre l\'énergie et automatiser.', + noProvidersTitle: 'Aucun fournisseur configuré', + noProvidersDescription: 'Ajoutez un fournisseur pour recevoir des alertes.', + noTemplatesAvailable: 'Aucun modèle dispo. Redémarrez pour les générer.', + apiPermissionView: 'Voir statut et file', + apiPermissionEdit: 'Gérer la file d\'attente', + apiKeysEmptyTitle: 'Aucune clé API', + apiKeysEmptyDescription: 'Créez une clé pour vos intégrations.', + noUsersFound: 'Aucun utilisateur trouvé', + noGroupsFound: 'Aucun groupe trouvé', + noGroupsAvailable: 'Aucun groupe disponible', + passwordsDoNotMatch: 'Les mots de passe ne correspondent pas', + systemGroupWarning: 'Les noms des groupes système sont fixes', + authDisabledTitle: 'Authentification désactivée', + authDisabledFeature1: 'Requis pour accéder au système', + authDisabledFeature2: 'Gestion multi-utilisateurs et groupes', + authDisabledFeature3: 'Plus de 50 permissions granulaires', + userHasCreated: 'Cet utilisateur a créé :', + userItemsQuestion: 'Que faire de ces éléments ?', + deleteUserConfirm: 'Supprimer cet utilisateur ?', + actionCannotBeUndone: 'Cette action est irréversible.', + addFirstSmartPlug: 'Ajoutez votre première prise', + providers: 'Fournisseurs', + log: 'Journal', + testAll: 'Tout tester', + testResults: 'Résultats du test', + testPassedCount: '{{count}} succès', + testFailedCount: '{{count}} échecs', + messageTemplates: 'Modèles de message', + messageTemplatesDescription: 'Personnalisez les messages par événement.', + apiKeys: 'Clés API', + apiKeysDescription: 'Créez des clés pour webhooks et API.', + createKey: 'Créer une clé', + apiKeyCreated: 'Clé API créée avec succès', + apiKeyCopyWarning: "Copiez cette clé maintenant - elle ne sera plus affichée !", + useInApiBrowser: 'Utiliser dans l\'explorateur API', + createNewApiKey: 'Nouvelle clé API', + keyName: 'Nom de la clé', + keyNamePlaceholder: 'ex: Home Assistant, OctoPrint', + readStatus: 'Lire le statut', + readStatusDescription: 'Voir les imprimantes et la file', + manageQueue: 'Gérer la file', + manageQueueDescription: 'Ajouter/retirer des éléments', + controlPrinter: 'Contrôler l\'imprimante', + controlPrinterDescription: 'Pause, reprise, arrêt', + unnamedKey: 'Clé sans nom', + lastUsed: 'Dernière utilisation', + read: 'Lecture', + control: 'Contrôle', + createFirstKey: 'Créez votre première clé', + webhookEndpoints: 'Points de terminaison Webhook', + webhookApiKeyHint: 'Utilisez la clé dans l\'en-tête X-API-Key.', + webhook: { + getAllStatus: 'Tous les statuts', + getSpecificStatus: 'Statut spécifique', + addToQueue: 'Ajouter à la file', + pausePrint: 'Pause', + resumePrint: 'Reprise', + stopPrint: 'Arrêt', + }, + apiBrowser: 'Explorateur API', + apiBrowserDescription: 'Testez les endpoints API.', + apiKeyForTesting: 'Clé API pour test', + apiKeyPlaceholder: 'Collez votre clé pour tester...', + apiKeyHint: 'Sera envoyée via l\'en-tête X-API-Key.', + deleteApiKeyTitle: 'Supprimer la clé API', + deleteApiKeyMessage: 'Les intégrations utilisant cette clé cesseront de fonctionner.', + deleteKey: 'Supprimer la clé', + amsDisplayThresholds: 'Seuils d\'affichage AMS', + amsThresholdsDescription: 'Seuils de couleur pour humidité et température.', + humidity: 'Humidité', + goodGreen: 'Bon (vert)', + fairOrange: 'Moyen (orange)', + aboveFairBad: 'Au-dessus = rouge (mauvais)', + temperature: 'Température', + goodBlue: 'Bon (bleu)', + aboveFairHot: 'Au-dessus = rouge (chaud)', + historyRetention: 'Rétention d\'historique', + keepSensorHistory: 'Garder l\'historique pendant', + historyRetentionDescription: 'Les anciennes données capteurs seront supprimées.', + printModal: 'Fenêtre d\'impression', + expandCustomMapping: 'Étendre le mapping personnalisé par défaut', + expandCustomMappingDescription: 'Affiche le mapping AMS par imprimante étendu.', + authentication: 'Authentification', + authEnabledDescription: 'L\'instance est sécurisée', + authDisabledDescription: 'Activez pour restreindre l\'accès', + authDisabledMessage: 'Activez l\'authentification pour gérer comptes et permissions.', + enableAuthentication: 'Activer l\'authentification', + currentUser: 'Utilisateur actuel', + changePassword: 'Changer le mot de passe', + admin: 'Admin', + users: 'Utilisateurs', + addUser: 'Ajouter un utilisateur', + groups: 'Groupes', + addGroup: 'Ajouter un groupe', + system: 'Système', + noDescription: 'Pas de description', + userCount: '{{count}} utilisateurs', + permissionCount: '{{count}} permissions', + createUser: 'Créer un utilisateur', + username: 'Nom d\'utilisateur', + enterUsername: 'Entrez l\'utilisateur', + password: 'Mot de passe', + enterPassword: 'Mot de passe (min 6 char)', + confirmPassword: 'Confirmer le mot de passe', + confirmPasswordPlaceholder: 'Confirmez le mot de passe', + viewReleaseOnGitHub: 'Voir la version sur GitHub', + turnAllPlugsOn: 'Tout allumer', + turnAllPlugsOff: 'Tout éteindre', + clearNotificationLogs: 'Effacer les journaux de notification', + clearLogsMessage: 'Efface définitivement les logs de plus de 30 jours.', + clearLogs: 'Effacer les logs', + resetUiPreferences: 'Réinitialiser les préférences UI', + resetUiPreferencesMessage: 'Réinitialise l\'ordre latéral, thème, widgets, etc. N\'affecte pas vos données.', + resetPreferences: 'Réinitialiser', + deleteGroupTitle: 'Supprimer le groupe', + deleteGroupMessage: 'Les utilisateurs de ce groupe perdront ces permissions.', + deleteGroup: 'Supprimer le groupe', + disableAuthenticationTitle: 'Désactiver l\'authentification', + disableAuthenticationMessage: 'Instance accessible sans connexion. Les comptes sont conservés.', + disableAuthentication: 'Désactiver', + configureBambuddy: 'Configurer Bambuddy', + systemDefault: 'Défaut système', + archiveSettings: 'Réglages Archives', + newWindow: 'Nouvelle fenêtre', + embeddedOverlay: 'Superposition intégrée', + preferredSlicer: 'Slicer préféré', + preferredSlicerDescription: 'Application pour ouvrir les fichiers', + externalCameras: 'Caméras externes', + costTracking: 'Suivi des coûts', + printsOnly: 'Impressions uniquement', + totalConsumption: 'Consommation totale', + dataManagement: 'Gestion des données', + clearNotificationLogsDescription: 'Supprimer logs de plus de 30 jours', + resetUiPreferencesDescription: 'Réinitialise thèmes et affichage sans toucher aux données.', + enableHomeAssistant: 'Activer Home Assistant', + enableMqtt: 'Activer MQTT', + useTls: 'Utiliser TLS', + enableMetricsEndpoint: 'Activer l\'endpoint Metrics', + availableMetrics: 'Metrics disponibles', + editUser: 'Modifier l\'utilisateur', + deleteUserTitle: 'Supprimer l\'utilisateur', + groupName: 'Nom du groupe', + leaveEmptyForAnonymous: 'Vide pour anonyme', + leaveEmptyForNoAuth: 'Vide si pas d\'auth', + enterNewPassword: 'Nouveau mot de passe', + confirmNewPassword: 'Confirmer nouveau mdp', + enterGroupName: 'Entrez le nom du groupe', + enterDescriptionOptional: 'Description (optionnel)', + enterCurrentPassword: 'Mdp actuel', + enterNewPasswordMin6: 'Nouveau mdp (min 6 char)', + toast: { + keyCopied: 'Clé copiée', + copyFailed: 'Échec copie', + keyAddedToBrowser: 'Clé ajoutée à l\'explorateur', + clearLogsFailed: 'Échec effacement logs', + uiPreferencesReset: 'Préférences UI réinitialisées. Rafraîchissement...', + authDisabled: 'Authentification désactivée', + authDisableFailed: 'Échec désactivation', + apiKeyCreated: 'Clé API créée', + apiKeyDeleted: 'Clé API supprimée', + userCreated: 'Utilisateur créé', + userUpdated: 'Utilisateur mis à jour', + userDeleted: 'Utilisateur supprimé', + groupCreated: 'Groupe créé', + groupUpdated: 'Groupe mis à jour', + groupDeleted: 'Groupe supprimé', + fillRequiredFields: 'Remplissez les champs requis', + passwordsDoNotMatch: 'Les mots de passe ne correspondent pas', + passwordTooShort: 'Minimum 6 caractères', + enterGroupName: 'Entrez un nom de groupe', + settingsSaved: 'Paramètres enregistrés', + cameraSettingsSaved: 'Réglages caméra enregistrés', + enterCameraUrl: 'Entrez une URL caméra', + passwordChanged: 'Mot de passe modifié', + connectionFailed: 'Échec connexion', + testFailed: 'Échec test', + cameraConnected: 'Caméra connectée {{resolution}}', + }, + testConnection: 'Tester la connexion', + }, + + // Notifications (for push notifications) + notification: { + printStarted: { + title: 'Impression démarrée', + body: '{{printer}} : {{filename}} commence l\'impression', + }, + printCompleted: { + title: 'Impression terminée', + body: '{{printer}} : {{filename}} a réussi', + }, + printFailed: { + title: 'Impression échouée', + body: '{{printer}} : {{filename}} a échoué', + }, + printStopped: { + title: 'Impression arrêtée', + body: '{{printer}} : {{filename}} a été arrêtée', + }, + printProgress: { + title: 'Progression d\'impression', + body: '{{printer}} : {{filename}} est à {{percent}}%', + }, + printerOffline: { + title: 'Imprimante hors ligne', + body: '{{printer}} est déconnectée', + }, + printerError: { + title: 'Erreur imprimante', + body: '{{printer}} : {{error}}', + }, + filamentLow: { + title: 'Filament bas', + body: '{{printer}} : Le filament est presque vide', + }, + maintenanceDue: { + title: 'Maintenance due', + body: '{{printer}} : {{items}} demandent votre attention', + }, + }, + + // Errors + errors: { + generic: 'Une erreur est survenue', + networkError: 'Erreur réseau. Vérifiez votre connexion.', + notFound: 'Non trouvé', + unauthorized: 'Non autorisé', + serverError: 'Erreur serveur', + validationError: 'Vérifiez vos saisies', + printerConnectionFailed: 'Échec connexion imprimante', + saveFailed: 'Échec enregistrement', + deleteFailed: 'Échec suppression', + loadFailed: 'Échec chargement', + }, + + // HMS Errors modal + hmsErrors: { + title: 'Erreurs - {{name}}', + noErrors: 'Aucune erreur', + viewOnWiki: 'Voir sur le Wiki Bambu Lab', + clearInstructions: 'Effacez les erreurs sur l\'imprimante pour les retirer ici.', + }, + + // MQTT Debug modal + mqttDebug: { + title: 'Journal de débogage MQTT', + searchPlaceholder: 'Chercher topic ou message...', + noMessages: 'Aucun message enregistré', + startLoggingHint: 'Cliquez sur "Démarrer" pour capturer les messages MQTT', + noMessagesMatch: 'Aucun message ne correspond', + adjustFilterHint: 'Ajustez votre recherche', + incoming: 'Entrant', + outgoing: 'Sortant', + loggingStopped: 'Enregistrement arrêté', + loggingActive: 'Enregistrement actif - rafraîchissement auto', + startLogging: 'Démarrer', + stopLogging: 'Arrêter', + clearLog: 'Effacer le journal', + topic: 'Topic', + timestamp: 'Horodatage', + direction: 'Direction', + all: 'Tous', + }, + + // Printer File Manager modal + printerFiles: { + title: 'Gestionnaire de fichiers', + storageUsed: 'Utilisé :', + storageFree: 'Libre :', + filterPlaceholder: 'Filtrer les fichiers...', + deleteButton: 'Supprimer', + deleteFiles: 'Supprimer {{count}} fichiers', + deleteFileConfirm: 'Supprimer "{{name}}" ?', + deleteFilesConfirm: 'Supprimer les {{count}} fichiers sélectionnés ?', + noFiles: 'Aucun fichier sur l\'imprimante', + loadingFiles: 'Chargement...', + failedToLoad: 'Échec chargement fichiers', + toast: { + filesDeleted: '{{count}} fichier(s) supprimé(s)', + deleteFailed: 'Échec suppression : {{error}}', + }, + }, + + // Login page + login: { + title: 'Connexion Bambuddy', + subtitle: 'Connectez-vous à votre compte', + username: 'Utilisateur', + usernamePlaceholder: 'Entrez votre utilisateur', + usernameOrEmail: 'Utilisateur ou Email', + usernameOrEmailPlaceholder: 'Utilisateur ou @ Email', + password: 'Mot de passe', + passwordPlaceholder: 'Entrez votre mot de passe', + signIn: 'Se connecter', + signingIn: 'Connexion...', + forgotPassword: 'Mot de passe oublié ?', + loginSuccess: 'Connecté avec succès', + loginFailed: 'Échec de connexion', + enterCredentials: 'Entrez vos identifiants', + forgotPasswordTitle: 'Mot de passe oublié', + forgotPasswordMessage: "Contactez votre administrateur pour réinitialiser votre accès.", + forgotPasswordEmailMessage: "Entrez votre email pour recevoir un nouveau mot de passe.", + emailAddress: 'Adresse Email', + emailPlaceholder: 'votre.email@exemple.com', + cancel: 'Annuler', + sending: 'Envoi...', + sendResetEmail: 'Envoyer l\'email', + howToReset: 'Comment réinitialiser :', + resetStep1: 'Contactez votre admin Bambuddy', + resetStep2: 'Demandez une réinitialisation dans la Gestion Utilisateurs', + resetStep3: 'Il vous donnera un mot de passe temporaire', + resetStep4: 'Connectez-vous et changez-le dans les Paramètres', + gotIt: 'Compris', + }, + + // Setup page + setup: { + title: 'Configuration Bambuddy', + subtitle: 'Configurez l\'authentification', + enableAuth: 'Activer l\'authentification', + adminAccount: 'Compte Admin', + adminAccountDesc: 'Si des admins existent, ils seront utilisés. Sinon, créez-en un ci-dessous.', + adminUsername: 'Utilisateur Admin', + adminPassword: 'Mot de passe Admin', + optionalIfAdminExists: '(optionnel si admin existe)', + adminUsernamePlaceholder: 'Nom admin (optionnel)', + adminPasswordPlaceholder: 'Mdp admin (optionnel)', + confirmPassword: 'Confirmer mdp', + confirmPasswordPlaceholder: 'Confirmez mdp admin', + settingUp: 'Configuration...', + completeSetup: 'Terminer la configuration', + toast: { + authEnabledAdminCreated: 'Authentification activée et admin créé', + authEnabledExistingAdmins: 'Authentification activée avec admins existants', + setupCompleted: 'Configuration terminée', + enterBothCredentials: 'Entrez les deux ou laissez vide pour utiliser les admins existants', + passwordsDoNotMatch: 'Les mots de passe ne correspondent pas', + passwordTooShort: 'Minimum 6 caractères', + }, + }, + + // Password change + changePassword: { + title: 'Changer le mot de passe', + currentPassword: 'Mot de passe actuel', + currentPasswordPlaceholder: 'Entrez mdp actuel', + newPassword: 'Nouveau mot de passe', + newPasswordPlaceholder: 'Nouveau mdp (min 6 char)', + confirmPassword: 'Confirmer nouveau mdp', + confirmPasswordPlaceholder: 'Confirmez nouveau mdp', + passwordsDoNotMatch: 'Les mots de passe ne correspondent pas', + passwordTooShort: 'Minimum 6 caractères', + changing: 'Changement...', + success: 'Mot de passe modifié', + failed: 'Échec modification', + }, + + // Plate detection alert + plateAlert: { + title: 'Impression en Pause !', + message: 'Objets détectés sur le plateau. L\'impression a été suspendue automatiquement. Videz le plateau avant de reprendre.', + understand: 'J\'ai compris', + }, + + // Camera page + camera: { + title: 'Vue Caméra', + invalidPrinterId: 'ID imprimante invalide', + live: 'Direct', + snapshot: 'Instantané', + restartStream: 'Redémarrer le flux', + refreshSnapshot: 'Rafraîchir l\'image', + fullscreen: 'Plein écran', + exitFullscreen: 'Quitter plein écran', + connectingToCamera: 'Connexion caméra...', + capturingSnapshot: 'Capture...', + connectionLost: 'Connexion perdue', + connectionFailed: 'Échec connexion caméra', + reconnecting: 'Reconnexion dans {{countdown}}s... (essai {{attempt}}/{{max}})', + reconnectNow: 'Reconnexion immédiate', + cameraUnavailable: 'Caméra indisponible', + cameraUnavailableDesc: 'Vérifiez que l\'imprimante est allumée.', + noCamera: 'Aucune caméra disponible', + retry: 'Réessayer', + cameraStream: 'Flux caméra', + zoomOut: 'Zoom arrière', + zoomIn: 'Zoom avant', + resetZoom: 'Réinitialiser zoom', + recording: 'Enregistrement', + startRecording: 'Démarrer l\'enregistrement', + stopRecording: 'Arrêter l\'enregistrement', + chamberLight: 'Basculer lumière chambre', + }, + + // Groups management + groups: { + title: 'Gestion des Groupes', + subtitle: 'Gérez les permissions pour le contrôle d\'accès', + backToSettings: 'Retour aux paramètres', + createGroup: 'Créer un groupe', + noPermission: 'Accès refusé.', + system: 'Système', + noDescription: 'Pas de description', + usersCount: '{{count}} utilisateurs', + permissionsCount: '{{count}} permissions', + edit: 'Modifier', + delete: 'Supprimer', + toast: { + created: 'Groupe créé', + updated: 'Groupe mis à jour', + deleted: 'Groupe supprimé', + enterGroupName: 'Entrez un nom de groupe', + }, + modal: { + editGroup: 'Modifier le groupe', + createGroup: 'Créer un groupe', + cancel: 'Annuler', + saving: 'Enregistrement...', + creating: 'Création...', + saveChanges: 'Enregistrer', + }, + form: { + groupName: 'Nom du groupe', + groupNamePlaceholder: 'Nom du groupe', + systemGroupWarning: 'Les groupes système sont fixes', + description: 'Description', + descriptionPlaceholder: 'Description (optionnel)', + permissions: 'Permissions ({{count}} sélectionnées)', + }, + deleteModal: { + title: 'Supprimer le groupe', + message: 'Les utilisateurs de ce groupe perdront ces permissions.', + confirm: 'Supprimer', + }, + }, + + // Users management + users: { + title: 'Gestion des Utilisateurs', + subtitle: 'Gérez les accès à Bambuddy', + backToSettings: 'Retour aux paramètres', + createUser: 'Créer un utilisateur', + noPermission: 'Accès refusé.', + admin: 'Admin', + noGroups: 'Aucun groupe', + active: 'Actif', + inactive: 'Inactif', + edit: 'Modifier', + delete: 'Supprimer', + system: 'Système', + noGroupsAvailable: 'Aucun groupe disponible', + table: { + username: 'Utilisateur', + groups: 'Groupes', + status: 'Statut', + actions: 'Actions', + }, + toast: { + created: 'Utilisateur créé', + updated: 'Utilisateur mis à jour', + deleted: 'Utilisateur supprimé', + fillRequired: 'Remplissez les champs requis', + passwordsDoNotMatch: 'Les mots de passe ne correspondent pas', + passwordTooShort: 'Minimum 6 caractères', + }, + modal: { + createUser: 'Créer utilisateur', + editUser: 'Modifier utilisateur', + cancel: 'Annuler', + creating: 'Création...', + saving: 'Enregistrement...', + saveChanges: 'Enregistrer', + advancedAuthSubtitle: 'avec Authentification Avancée', + }, + form: { + username: 'Utilisateur', + usernamePlaceholder: 'Nom utilisateur', + email: 'Email', + emailPlaceholder: 'utilisateur@exemple.com', + password: 'Mot de passe', + passwordPlaceholder: 'Mot de passe', + confirmPassword: 'Confirmer mdp', + confirmPasswordPlaceholder: 'Confirmez mdp', + newPasswordPlaceholder: 'Nouveau mdp', + confirmNewPasswordPlaceholder: 'Confirmez nouveau mdp', + leaveBlankToKeep: 'Laissez vide pour conserver l\'actuel', + groups: 'Groupes', + optional: 'optionnel', + autoGeneratedPassword: 'Un mot de passe sera généré et envoyé par email.', + passwordManagedByAdvancedAuth: 'Géré par Auth Avancée. Utilisez "Réinitialiser" pour envoyer un nouveau mdp par email.', + resetPassword: 'Réinitialiser le mot de passe', + resettingPassword: 'Réinitialisation...', + }, + deleteModal: { + title: 'Supprimer utilisateur', + message: 'Cette action est irréversible.', + confirm: 'Supprimer', + }, + }, + + // Stream overlay + streamOverlay: { + title: 'Superposition Flux', + invalidPrinterId: 'ID invalide', + cameraStream: 'Flux caméra', + progress: 'Progression', + eta: 'Fin estimée', + tomorrow: 'Demain', + printerIdle: 'Imprimante inactive', + printerOffline: 'Imprimante hors ligne', + status: { + printing: 'Impression', + paused: 'En pause', + finished: 'Terminée', + failed: 'Échouée', + idle: 'Inactive', + unknown: 'Inconnue', + }, + }, + + // Profiles + profiles: { + title: 'Profils', + subtitle: 'Gérez vos presets slicer et calibrations Pressure Advance', + tabs: { + cloud: 'Profils Cloud', + local: 'Profils Locaux', + kprofiles: 'K-Profiles', + }, + localProfiles: { + title: 'Profils Locaux', + subtitle: 'Gérez vos presets OrcaSlicer', + import: 'Importer Profils', + importDesc: 'Déposez les fichiers .bbscfg, .bbsflmt, .orca_filament, .zip ou .json', + importing: 'Importation...', + search: 'Chercher un preset...', + noPresets: 'Aucun preset local', + badge: 'Local', + edit: 'Modifier', + delete: 'Supprimer', + cancel: 'Annuler', + deleteConfirmTitle: 'Supprimer Preset', + deleteConfirm: 'Supprimer définitivement ce preset ?', + source: 'Source', + inheritsFrom: 'Hérite de', + filamentType: 'Type', + vendor: 'Vendeur', + compatiblePrinters: 'Imprimantes', + nozzleTemp: 'Temp Buse', + cost: 'Coût', + density: 'Densité', + pressureAdvance: 'Pressure Advance', + filament: 'Filament', + process: 'Processus', + printer: 'Imprimante', + toast: { + importSuccess: '{{count}} profil(s) importé(s)', + importSkipped: '{{count}} profil(s) ignoré(s) (doublons)', + importError: '{{count}} erreur(s) d\'import', + deleted: 'Preset supprimé', + updated: 'Preset mis à jour', + }, + }, + connectedAs: 'Connecté en tant que', + logout: 'Déconnexion', + noLogoutPermission: 'Pas d\'autorisation de déconnexion', + failedToLoad: 'Échec chargement profils', + retry: 'Réessayer', + time: { + justNow: 'À l\'instant', + minsAgo: 'Il y a {{count}}m', + hoursAgo: 'Il y a {{count}}h', + daysAgo: 'Il y a {{count}}j', + }, + toast: { + loggedOut: 'Déconnecté', + }, + login: { + title: 'Connexion Bambu Cloud', + subtitle: 'Synchronisez vos presets slicer', + email: 'Email', + password: 'Mot de passe', + region: 'Région', + regionGlobal: 'Global', + regionChina: 'Chine', + verificationCode: 'Code de vérification', + totpCode: 'Code Authenticator', + checkEmail: 'Code envoyé à {{email}}', + enterTotpHint: 'Entrez le code 2FA', + accessToken: 'Jeton d\'accès (Access Token)', + accessTokenHint: 'Collez le jeton (depuis Bambu Studio)', + back: 'Retour', + loginButton: 'Connexion', + verifyButton: 'Vérifier', + setTokenButton: 'Définir Jeton', + useToken: 'Utiliser jeton d\'accès', + useEmail: 'Connexion par email', + toast: { + loggedIn: 'Connecté avec succès', + codeSent: 'Code envoyé par email', + enterTotp: 'Entrez le code Authenticator', + tokenSet: 'Jeton défini', + }, + }, + presets: { + myPreset: 'Mon preset (modifiable)', + duplicate: 'Dupliquer', + editable: 'Modifiable', + failedToLoadDetails: 'Échec détails preset', + deleteConfirm: 'Supprimer ce preset ?', + deleteWarning: 'Ceci supprimera "{{name}}" de Bambu Cloud définitivement.', + noDuplicatePermission: 'Pas d\'autorisation duplication', + noEditPermission: 'Pas d\'autorisation modification', + noDeletePermission: 'Pas d\'autorisation suppression', + types: { + filament: 'Preset filament', + printer: 'Preset imprimante', + process: 'Preset processus', + }, + toast: { + deleted: 'Preset supprimé', + created: 'Preset créé', + updated: 'Preset mis à jour', + duplicated: 'Preset dupliqué', + fieldAdded: 'Champ "{{key}}" ajouté', + exported: 'Preset exporté', + }, + baseLabel: 'Base : {{name}}', + currentLabel: 'Actuel : {{name}}', + newPreset: 'Nouveau Preset', + editPreset: 'Modifier Preset', + duplicatePreset: 'Dupliquer Preset', + createNewPreset: 'Créer un nouveau Preset', + customizeSettings: 'Personnalisez vos réglages', + compareWithBase: 'Comparer avec la base', + compare: 'Comparer', + basePreset: 'Preset de base', + selectBasePreset: 'Choisir preset de base...', + presetName: 'Nom du preset', + myCustomPreset: 'Mon preset personnalisé', + inheritsFrom: 'Hérite de', + dropJsonToImport: 'Glissez JSON pour importer', + tabs: { + common: 'Commun', + allFields: 'Tous les champs', + }, + availableFields: 'Champs disponibles', + searchFieldsPlaceholder: 'Chercher un champ...', + noMatchingFields: 'Aucun champ trouvé', + allFieldsAdded: 'Tous les champs sont ajoutés', + addCustomField: 'Ajouter un champ personnalisé', + yourOverrides: 'Vos modifications', + noOverridesYet: 'Aucune modification', + clickFieldsToAdd: 'Cliquez à gauche pour ajouter', + saveAsTemplate: 'Enregistrer comme modèle', + jsonTip: 'Conseil : Glissez un .json pour importer les réglages', + }, + cloudView: { + searchPlaceholder: 'Chercher presets...', + templates: 'Modèles', + refresh: 'Rafraîchir', + newPreset: 'Nouveau Preset', + clearFilters: 'Effacer filtres', + compareMode: 'Mode Comparaison', + selectAnotherPreset: 'Choisir un autre preset {{type}}', + clickTwoPresets: 'Choisissez deux presets de même type', + selectFirst: '1. Sélectionner premier', + selectSecond: '2. Sélectionner second', + compareNow: 'Comparer maintenant', + lastSynced: 'Synchronisé :', + showingCount: '{{showing}} sur {{total}} presets', + noPresetsFound: 'Aucun preset trouvé', + columns: { + filament: 'Filament', + process: 'Processus', + printer: 'Imprimante', + }, + noFilamentPresets: 'Pas de preset filament', + noProcessPresets: 'Pas de preset processus', + noPrinterPresets: 'Pas de preset imprimante', + filters: { + type: 'Type', + owner: 'Propriétaire', + printer: 'Imprimante', + nozzle: 'Buse', + filament: 'Filament', + layer: 'Couche', + all: 'Tous', + myPresets: 'Mes Presets', + builtIn: 'Inclus', + process: 'Processus', + }, + noTemplatesPermission: 'Pas d\'autorisation modèles', + noRefreshPermission: 'Pas d\'autorisation rafraîchissement', + noCreatePermission: 'Pas d\'autorisation création', + }, + templates: { + title: 'Modèles rapides', + noTemplates: 'Aucun modèle', + createFirst: 'Créez-en depuis l\'éditeur de preset', + typeFilter: 'Type :', + deleteTitle: 'Supprimer modèle', + deleteWarning: 'Action irréversible', + deleteConfirm: 'Supprimer "{{name}}" ?', + namePlaceholder: 'Nom du modèle', + descriptionPlaceholder: 'Description', + settingsJson: 'Paramètres (JSON)', + fieldsCount: '{{count}} champs', + shownInModals: 'Visible dans fenêtres', + hiddenInModals: 'Masqué dans fenêtres', + apply: 'Appliquer', + toast: { + deleted: 'Modèle supprimé', + updated: 'Modèle mis à jour', + created: 'Modèle créé', + applied: 'Modèle appliqué', + }, + }, + }, + + // Support/Debug + support: { + debugLoggingActive: 'Débogage actif', + manageLogs: 'Gérer', + collectItem7: 'Connectivité et versions firmware', + collectItem8: 'Statut intégrations (Spoolman, MQTT, HA)', + collectItem9: 'Interfaces réseau (sous-réseaux)', + collectItem10: 'Versions packages Python', + collectItem11: 'Santé base de données', + collectItem12: 'Détails environnement Docker', + }, + + // File manager + fileManager: { + title: 'Gestionnaire de fichiers', + subtitle: 'Organisez vos fichiers d\'impression', + uploadFiles: 'Téléverser fichiers', + newFolder: 'Nouveau dossier', + folderName: 'Nom du dossier', + folderNamePlaceholder: 'ex: Pièces Utiles', + renameFile: 'Renommer fichier', + renameFolder: 'Renommer dossier', + moveFiles: 'Déplacer {{count}} fichier(s)', + rootNoFolder: 'Racine (aucun dossier)', + current: 'actuel', + linkFolder: 'Lier le dossier', + linkFolderDescription: 'Lier "{{name}}" à un projet ou archive.', + project: 'Projet', + archive: 'Archive', + noProjectsFound: 'Aucun projet trouvé', + noArchivesFound: 'Aucune archive trouvée', + unlink: 'Délier', + link: 'Lier', + dragDropFiles: 'Glissez les fichiers ici', + dropFilesHere: 'Déposez ici', + orClickToBrowse: 'ou cliquez pour parcourir', + allFileTypesSupported: 'Tous types supportés. ZIP extraits.', + zipFilesDetected: 'ZIP détectés', + zipExtractOptions: 'Choix de structure pour ZIP :', + preserveZipStructure: 'Garder structure ZIP', + createFolderFromZip: 'Dossier par nom du ZIP', + stlThumbnailGeneration: 'Vignettes STL', + zipMayContainStl: 'Extraction vignettes possible pour STL.', + thumbnailsCanBeGenerated: 'Génération vignettes (peut être long).', + generateThumbnailsForStl: 'Générer vignettes STL', + threemfDetected: 'Fichiers 3MF détectés', + threemfExtractionInfo: 'Réglages extraits auto du 3MF.', + willBeExtracted: 'Sera extrait', + filesExtracted: '{{count}} fichiers extraits', + uploadComplete: 'Terminé : {{succeeded}} succès', + uploadFailed: '{{count}} échecs', + uploading: 'Téléversement...', + changeLink: 'Modifier lien...', + linkTo: 'Lier à...', + linkToProjectOrArchive: 'Lier à projet ou archive', + addToQueue: 'Ajouter à la file', + schedulePrint: 'Planifier', + generateThumbnail: 'Générer vignette', + generateThumbnails: 'Générer vignettes', + generateThumbnailsForMissing: 'Vignettes STL manquantes', + gridView: 'Grille', + listView: 'Liste', + lowDiskSpaceWarning: 'Espace disque faible', + lowDiskSpaceDetails: '{{free}} libre sur {{total}}. Seuil : {{threshold}} Go.', + files: 'Fichiers', + folders: 'Dossiers', + size: 'Taille', + free: 'Libre', + allFiles: 'Tous les fichiers', + wrap: 'Retour ligne', + enableTextWrapping: 'Activer retour ligne', + disableTextWrapping: 'Désactiver retour ligne', + dragToResizeTooltip: 'Glisser pour redimensionner, double-clic reset', + searchFiles: 'Chercher fichiers...', + allTypes: 'Tous types', + prints: 'Impressions', + ascending: 'Croissant', + descending: 'Décroissant', + resultsCount: '{{showing}} sur {{total}} fichiers', + selectAll: 'Tout sélectionner', + deselectAll: 'Tout désélectionner', + selected: '{{count}} sélectionnés', + adding: 'Ajout...', + loadingFiles: 'Chargement...', + folderIsEmpty: 'Dossier vide', + noFilesYet: 'Aucun fichier', + folderEmptyDescription: 'Téléversez ou déplacez des fichiers ici.', + noFilesDescription: 'Téléversez des fichiers pour organiser.', + noMatchingFiles: 'Aucun fichier correspondant', + noMatchingFilesDescription: 'Ajustez votre recherche.', + clearFilters: 'Effacer filtres', + printedCount: 'Imprimé {{count}}x', + uploadedBy: 'Téléversé par', + deleteFolder: 'Supprimer dossier', + deleteFile: 'Supprimer fichier', + deleteFilesCount: 'Supprimer {{count}} fichiers', + deleteFolderConfirm: 'Supprimer le dossier et son contenu ?', + deleteFileConfirm: 'Supprimer ce fichier ?', + deleteFilesConfirm: 'Supprimer {{count}} fichiers définitivement ?', + deleting: 'Suppression...', + noPermissionRenameFolder: 'Pas d\'autorisation renommage', + noPermissionLinkFolder: 'Pas d\'autorisation lien', + noPermissionDeleteFolder: 'Pas d\'autorisation suppression dossier', + noPermissionPrint: 'Pas d\'autorisation impression', + noPermissionAddToQueue: 'Pas d\'autorisation file', + noPermissionDownload: 'Pas d\'autorisation téléchargement', + noPermissionRenameFile: 'Pas d\'autorisation renommage fichier', + noPermissionGenerateThumbnail: 'Pas d\'autorisation vignettes', + noPermissionDeleteFile: 'Pas d\'autorisation suppression fichier', + noPermissionCreateFolder: 'Pas d\'autorisation nouveau dossier', + noPermissionUpload: 'Pas d\'autorisation téléversement', + noPermissionMoveFiles: 'Pas d\'autorisation déplacement', + noPermissionDeleteFiles: 'Pas d\'autorisation suppression groupée', + toast: { + folderCreated: 'Dossier créé', + folderDeleted: 'Dossier supprimé', + fileDeleted: 'Fichier supprimé', + filesDeleted: '{{count}} fichiers supprimés', + filesMoved: 'Fichiers déplacés', + folderLinked: 'Dossier lié', + folderUnlinked: 'Dossier délié', + addedToQueue: '{{count}} fichier(s) ajouté(s)', + addedToQueuePartial: '{{added}} ajoutés, {{failed}} échecs', + failedToAddToQueue: 'Échec ajout file : {{error}}', + fileRenamed: 'Fichier renommé', + folderRenamed: 'Dossier renommé', + thumbnailsGenerated: '{{count}} vignette(s) générée(s)', + thumbnailsGeneratedPartial: '{{succeeded}} succès, {{failed}} échecs', + noStlMissingThumbnails: 'Aucun STL sans vignette', + failedToGenerateThumbnails: 'Échec vignettes : {{error}}', + thumbnailGenerated: 'Vignette générée', + failedToGenerateThumbnail: 'Échec vignette : {{error}}', + }, + }, + + // Projects + projects: { + title: 'Projets', + subtitle: 'Suivez vos projets d\'impression 3D', + newProject: 'Nouveau Projet', + editProject: 'Modifier Projet', + deleteProject: 'Supprimer Projet', + projectName: 'Nom du Projet', + description: 'Description', + noProjects: 'Aucun projet', + noProjectsFiltered: 'Aucun projet {{status}}', + noProjectsFilteredHelp: 'Les projets apparaîtront ici quand leur statut changera.', + createFirst: 'Créez votre premier projet pour organiser vos builds.', + createFirstButton: 'Créer votre premier projet', + create: 'Créer', + files: 'Fichiers', + prints: 'Impressions', + plates: 'plateaux', + parts: 'pièces', + lastModified: 'Modifié le', + deleteConfirm: 'Supprimer ce projet ? Les archives seront déliées mais conservées.', + addFiles: 'Ajouter fichiers', + removeFile: 'Retirer fichier', + viewDetails: 'Détails', + namePlaceholder: 'ex: Build Voron 2.4', + descriptionPlaceholder: 'Description optionnelle...', + color: 'Couleur', + targetPlates: 'Plateaux cibles', + targetPlatesPlaceholder: 'ex: 25', + targetPlatesHelp: 'Nombre total de jobs', + targetParts: 'Pièces cibles', + targetPartsPlaceholder: 'ex: 150', + targetPartsHelp: 'Nombre total d\'objets', + tagsLabel: 'Tags (séparés par virgules)', + tagsPlaceholder: 'ex: voron, cadeau', + dueDate: 'Échéance', + priority: 'Priorité', + priorityLow: 'Basse', + priorityNormal: 'Normale', + priorityHigh: 'Haute', + priorityUrgent: 'Urgente', + statusActive: 'Actif', + statusCompleted: 'Terminé', + statusArchived: 'Archivé', + done: 'Fait', + completed: 'terminé', + failed: 'échoué', + inQueue: 'en file', + noPrintsYet: 'Aucune impression', + printJobs: 'Jobs (plateaux)', + partsPrinted: 'Pièces imprimées', + failedParts: 'Pièces échouées', + import: 'Importer', + export: 'Exporter', + importProject: 'Importer projet', + exportAll: 'Exporter tous les projets', + loading: 'Chargement des projets...', + noEditPermission: 'Pas d\'autorisation de modification', + noDeletePermission: 'Pas d\'autorisation de suppression', + noCreatePermission: 'Pas d\'autorisation de création', + noImportPermission: 'Pas d\'autorisation d\'import', + noExportPermission: 'Pas d\'autorisation d\'export', + toast: { + created: 'Projet créé', + updated: 'Projet mis à jour', + deleted: 'Projet supprimé', + imported: 'Projet importé', + multipleImported: '{{count}} projets importés', + importFailed: 'Échec d\'import', + exported: 'Projets exportés (métadonnées)', + }, + }, + + // Project detail page + projectDetail: { + notFound: 'Projet non trouvé', + backToProjects: 'Retour aux Projets', + export: 'Exporter', + exportProject: 'Exporter projet', + noExportPermission: 'Pas d\'autorisation export', + noEditPermission: 'Pas d\'autorisation modification', + partOf: 'Fait partie de :', + priorityLabel: 'Priorité :', + noPrints: 'Aucune impression dans ce projet', + status: { + active: 'Actif', + completed: 'Terminé', + archived: 'Archivé', + }, + priority: { + low: 'Basse', + normal: 'Normale', + high: 'Haute', + urgent: 'Urgente', + }, + dueDate: { + overdue: 'En retard', + today: 'Aujourd\'hui', + daysLeft: '{{count}} jours restants', + }, + progress: { + platesProgress: 'Progression Plateaux', + partsProgress: 'Progression Pièces', + printJobs: 'jobs d\'impression', + parts: 'pièces', + percentComplete: '{{percent}}% terminé', + remaining: '{{count}} restant(s)', + }, + stats: { + printJobs: 'Jobs d\'Impression', + total: 'total', + failed: '{{count}} échecs', + partsPrinted: '{{count}} pièces imprimées', + printTime: 'Temps d\'Impression', + filamentUsed: 'Filament utilisé', + }, + cost: { + title: 'Suivi des coûts', + filamentCost: 'Coût Filament', + energy: 'Énergie', + budget: 'Budget', + remaining: 'Restant', + }, + subProjects: { + title: 'Sous-projets ({{count}})', + }, + notes: { + title: 'Notes', + noEditPermission: 'Pas d\'autorisation modification', + placeholder: 'Ajouter des notes...', + empty: 'Aucune note. Cliquez sur modifier.', + }, + files: { + title: 'Fichiers', + linkFolders: 'Liez des dossiers depuis le gestionnaire', + forQuickAccess: 'pour un accès rapide.', + fileCount: '{{count}} fichier(s)', + empty: 'Aucun dossier lié.', + }, + bom: { + title: 'BOM (Liste matériel)', + acquired: '{{completed}}/{{total}} acquis', + showAll: 'Tout afficher', + hideDone: 'Masquer acquis', + addPart: 'Ajouter matériel', + noAddPermission: 'Pas d\'autorisation ajout', + partNamePlaceholder: 'Nom (ex: Vis M3x8)', + partName: 'Nom de pièce', + qty: 'Qté', + price: 'Prix ({{currency}})', + sourcingUrlPlaceholder: 'Lien d\'achat (optionnel)', + remarksPlaceholder: 'Remarques (optionnel)', + deletePart: 'Supprimer pièce', + deleteConfirm: 'Supprimer "{{name}}" ?', + noUpdatePermission: 'Pas d\'autorisation mise à jour', + noEditPermission: 'Pas d\'autorisation modification', + noDeletePermission: 'Pas d\'autorisation suppression', + totalCost: 'Coût total :', + empty: 'BOM vide. Ajoutez du matériel ou de l\'électronique.', + }, + timeline: { + title: 'Historique d\'activité', + empty: 'Aucune activité.', + }, + template: { + saveAsTemplate: 'Enregistrer comme modèle', + noCreatePermission: 'Pas d\'autorisation modèle', + }, + queue: { + title: 'File d\'attente', + viewAll: 'Tout voir', + printing: '{{count}} en cours', + queued: '{{count}} en file', + }, + prints: { + title: 'Impressions ({{count}})', + }, + toast: { + projectUpdated: 'Projet mis à jour', + partAdded: 'Pièce ajoutée', + partRemoved: 'Pièce retirée', + exportFailed: 'Échec export', + projectExported: 'Projet exporté', + templateCreated: 'Modèle créé', + }, + }, + + // System info + system: { + title: 'Informations Système', + version: 'Version', + uptime: 'Temps de fonctionnement', + cpuUsage: 'Utilisation CPU', + memoryUsage: 'Utilisation RAM', + diskUsage: 'Utilisation Disque', + networkInfo: 'Infos Réseau', + logs: 'Journaux', + debugMode: 'Mode Débogage', + enableDebug: 'Activer débogage', + disableDebug: 'Désactiver débogage', + downloadLogs: 'Télécharger logs', + clearLogs: 'Effacer logs', + dockerInfo: 'Infos Docker', + containerName: 'Nom conteneur', + imageName: 'Nom image', + platform: 'Plateforme', + architecture: 'Architecture', + }, + + // Library (K Profiles) + library: { + title: 'Bibliothèque Filament', + addFilament: 'Ajouter Filament', + editFilament: 'Modifier Filament', + deleteFilament: 'Supprimer Filament', + vendor: 'Vendeur', + material: 'Matériau', + color: 'Couleur', + kFactor: 'Facteur K', + temperature: 'Température', + noFilaments: 'Bibliothèque vide', + deleteConfirm: 'Supprimer ce filament ?', + importFromPrinter: 'Importer de l\'imprimante', + exportToFile: 'Exporter vers fichier', + }, + + // Spoolman + spoolman: { + title: 'Intégration Spoolman', + enabled: 'Spoolman Activé', + url: 'URL Spoolman', + connected: 'Connecté', + disconnected: 'Déconnecté', + testConnection: 'Tester connexion', + sync: 'Synchroniser', + syncing: 'Sync...', + lastSync: 'Dernière Sync', + linkToSpoolman: 'Lier à Spoolman', + openInSpoolman: 'Ouvrir Spoolman', + unlinkSpool: 'Délier bobine', + selectSpool: 'Choisir bobine', + noUnlinkedSpools: 'Pas de bobine libre', + linkSuccess: 'Lien réussi', + linkFailed: 'Échec lien', + spoolId: 'ID Bobine', + fillSourceLabel: '(Spoolman)', + weight: 'Poids', + remaining: 'Restant', + disableWeightSync: 'Désactiver Sync poids estimé AMS', + disableWeightSyncDesc: 'Ne pas utiliser les estimations AMS. Utile si vous préférez le suivi de consommation Spoolman.', + reportPartialUsage: 'Rapporter consommation partielle pour échecs', + reportPartialUsageDesc: 'Si l\'impression échoue, rapporte le filament consommé selon les couches.', + }, + + // Timelapse + timelapse: { + title: 'Timelapse', + create: 'Créer Timelapse', + download: 'Télécharger', + delete: 'Supprimer', + preview: 'Aperçu', + frameRate: 'Images/sec', + quality: 'Qualité', + processing: 'Traitement...', + noTimelapses: 'Aucun timelapse', + }, + + // AMS + ams: { + title: 'AMS', + slot: 'Slot', + empty: 'Vide', + emptySlot: 'Slot vide', + unknown: 'Inconnu', + humidity: 'Humidité', + temperature: 'Température', + filamentType: 'Type filament', + filamentColor: 'Couleur', + remaining: 'Restant', + history: 'Historique AMS', + noHistory: 'Aucun historique', + configureSlot: 'Configurer Slot', + externalSpool: 'Bobine externe', + profile: 'Profil', + kFactor: 'Facteur K', + fill: 'Remplir', + configure: 'Configurer', + }, + + // Print modal + printModal: { + title: 'Lancer l\'impression', + selectPrinter: 'Choisir l\'imprimante', + selectPlate: 'Choisir le plateau', + filamentMapping: 'Mapping Filament', + printSettings: 'Réglages d\'impression', + bedLeveling: 'Nivellement plateau', + flowCalibration: 'Calibration débit', + vibrationCalibration: 'Vibration (Input Shaper)', + layerInspection: 'Inspection 1ère couche', + timelapse: 'Timelapse', + startPrint: 'Démarrer', + addToQueue: 'Ajouter à la file', + cancel: 'Annuler', + noPrintersAvailable: 'Aucune imprimante disponible', + printerBusy: 'L\'imprimante est occupée', + printerOffline: 'L\'imprimante est hors ligne', + sameTypeDifferentColor: 'Même type, couleur différente', + filamentTypeNotLoaded: 'Type de filament non chargé', + openCalendar: 'Ouvrir calendrier', + }, + + // Backup + backup: { + title: 'Sauvegarde & Restauration', + createBackup: 'Créer Sauvegarde', + restoreBackup: 'Restaurer Sauvegarde', + restoreDescription: 'Remplace les données par un fichier de sauvegarde', + downloadBackup: 'Télécharger Sauvegarde', + uploadBackup: 'Téléverser Sauvegarde', + lastBackup: 'Dernière sauvegarde', + autoBackup: 'Sauvegarde auto', + backupNow: 'Sauvegarder maintenant', + restoreWarning: 'Attention : Écrase TOUTES les données actuelles.', + includeArchives: 'Inclure Archives', + includeSettings: 'Inclure Paramètres', + includeProfiles: 'Inclure Profils', + backupSuccess: 'Sauvegarde réussie', + restoreSuccess: 'Restauration réussie', + backupFailed: 'Échec sauvegarde', + restoreFailed: 'Échec restauration', + restoreNote: 'L\'imprimante virtuelle sera arrêtée pendant la restauration', + }, + + // Tags + tags: { + title: 'Tags', + addTag: 'Ajouter Tag', + editTag: 'Modifier Tag', + deleteTag: 'Supprimer Tag', + tagName: 'Nom du Tag', + tagColor: 'Couleur du Tag', + noTags: 'Aucun tag', + deleteConfirm: 'Supprimer ce tag ?', + manageTags: 'Gérer les Tags', + }, + + // Upload modal (archives) + uploadModal: { + title: 'Téléverser des fichiers 3MF', + dragDrop: 'Glissez les fichiers .3mf ici', + or: 'ou', + browseFiles: 'Parcourir', + extractionInfo: 'Le modèle d\'imprimante est extrait des métadonnées 3MF.', + uploaded: 'téléversé', + failed: 'échoué', + uploading: 'En cours...', + upload: 'Téléverser', + uploadFailed: 'Échec du téléversement', + }, + + // Edit Archive Modal + editArchive: { + title: 'Modifier l\'archive', + name: 'Nom', + namePlaceholder: 'Nom de l\'impression', + printer: 'Imprimante', + noPrinter: 'Aucune imprimante', + project: 'Projet', + noProject: 'Aucun projet', + itemsPrinted: 'Nombre de pièces', + itemsPrintedHelp: 'Nombre d\'objets produits', + notes: 'Notes', + notesPlaceholder: 'Notes sur l\'impression...', + externalLink: 'Lien externe', + externalLinkPlaceholder: 'https://...', + externalLinkHelp: 'Lien vers Printables, Thingiverse, etc.', + tags: 'Tags', + tagsPlaceholder: 'Ajouter des tags...', + addMoreTags: 'Plus de tags...', + matchingTags: 'Correspondant à "{{query}}"', + existingTags: 'Tags existants', + clickToAdd: '(cliquer pour ajouter)', + status: 'Statut', + failureReason: 'Raison de l\'échec', + selectReason: 'Choisir raison...', + photos: 'Photos du résultat', + photosHelp: 'Cliquez sur + pour ajouter des photos', + printResult: 'Résultat d\'impression', + saving: 'Enregistrement...', + failureReasons: { + adhesionFailure: 'Défaut d\'adhésion', + spaghettiDetached: 'Spaghetti / Détaché', + layerShift: 'Décalage de couche', + cloggedNozzle: 'Buse bouchée', + filamentRunout: 'Filament fini', + warping: 'Warping (Déformation)', + stringing: 'Stringing (Cheveux d\'ange)', + underExtrusion: 'Sous-extrusion', + powerFailure: 'Coupure courant', + userCancelled: 'Annulé par l\'utilisateur', + other: 'Autre', + }, + statuses: { + completed: 'Réussie', + failed: 'Échouée', + aborted: 'Annulée', + printing: 'Impression', + }, + }, + + // K-Profiles + kProfiles: { + title: 'K-Profiles', + noPrintersConfigured: 'Aucune imprimante configurée', + addPrinterInSettings: 'Ajoutez une imprimante pour gérer les K-profiles', + noActivePrinters: 'Aucune imprimante active', + enablePrinterConnection: 'Activez la connexion pour voir les K-profiles', + loadingProfiles: 'Chargement des K-Profiles...', + printerOffline: 'Imprimante hors ligne', + printerOfflineDesc: 'L\'imprimante doit être allumée.', + noMatchingProfiles: 'Aucun profil correspondant', + noMatchingProfilesDesc: 'Ajustez votre recherche', + noKProfiles: 'Aucun K-Profile', + noKProfilesDesc: 'Aucun profil trouvé pour une buse de {{diameter}}mm', + createFirstProfile: 'Créer le premier profil', + printer: 'Imprimante', + nozzle: 'Buse', + refresh: 'Rafraîchir', + addProfile: 'Ajouter Profil', + export: 'Exporter', + import: 'Importer', + select: 'Choisir', + selectAll: 'Tout sélectionner', + delete: 'Supprimer', + searchPlaceholder: 'Nom ou filament...', + allExtruders: 'Tous les extrudeurs', + leftOnly: 'Gauche uniquement', + rightOnly: 'Droite uniquement', + allFlow: 'Tout débit', + hfOnly: 'HF uniquement', + sOnly: 'S uniquement', + sortName: 'Tri : Nom', + sortKValue: 'Tri : Valeur K', + sortFilament: 'Tri : Filament', + leftExtruder: 'Extrudeur gauche', + rightExtruder: 'Extrudeur droit', + modal: { + addTitle: 'Ajouter K-Profile', + editTitle: 'Modifier K-Profile', + profileName: 'Nom du profil', + profileNamePlaceholder: 'ex: Mon profil PLA', + kValue: 'Valeur K', + kValuePlaceholder: '0.020', + kValueHelp: 'Plage type : 0.01-0.06 (PLA), 0.02-0.10 (PETG)', + filament: 'Filament', + selectFilament: 'Choisir filament...', + noFilamentsHelp: 'Créez d\'abord un profil dans Bambu Studio.', + flowType: 'Type de débit', + highFlow: 'Haut Débit (HF)', + standard: 'Standard', + nozzleSize: 'Taille buse', + extruder: 'Extrudeur', + extruders: 'Extrudeurs', + left: 'Gauche', + right: 'Droite', + notes: 'Notes (locales)', + notesPlaceholder: 'Notes sur ce profil...', + notesHelp: 'Enregistré dans Bambuddy, pas sur l\'imprimante', + syncing: 'Sync avec l\'imprimante...', + savingExtruder: 'Sauvegarde extrudeur {{current}}/{{total}}...', + pleaseWait: 'Patientez...', + }, + deleteConfirm: { + title: 'Supprimer profil', + cannotUndo: 'Action irréversible', + message: 'Supprimer "{{name}}" de l\'imprimante ?', + }, + bulkDelete: { + title: 'Supprimer les profils', + cannotUndo: 'Action irréversible', + message: 'Supprimer les {{count}} profils de l\'imprimante ?', + }, + toast: { + profileSaved: 'Profil K enregistré', + profilesSaved: 'Profil K enregistré sur {{count}} extrudeur(s)', + selectAtLeastOneExtruder: 'Sélectionnez un extrudeur', + profileDeleted: 'Profil K supprimé', + profilesDeleted: '{{count}} profils supprimés', + exportedProfiles: '{{count}} profils exportés', + importedProfiles: '{{count}} sur {{total}} profils importés', + noProfilesToExport: 'Rien à exporter', + invalidFileFormat: 'Format invalide', + failedToParseImport: 'Échec analyse fichier', + failedToSaveBatch: 'Échec enregistrement groupé', + noteSaved: 'Note enregistrée', + failedToSaveNote: 'Échec note', + }, + permission: { + noRead: 'Pas d\'autorisation lecture', + noCreate: 'Pas d\'autorisation création', + noUpdate: 'Pas d\'autorisation mise à jour', + noDelete: 'Pas d\'autorisation suppression', + noExport: 'Pas d\'autorisation export', + noImport: 'Pas d\'autorisation import', + }, + }, + + // Virtual Printer + virtualPrinter: { + title: 'Imprimante Virtuelle', + running: 'En cours', + stopped: 'Arrêtée', + description: { + default: 'Apparaît dans le Slicer. Les fichiers envoyés sont archivés sans impression.', + proxy: 'Relais vers une vraie imprimante pour impression à distance sécurisée.', + }, + enable: { + title: 'Activer l\'imprimante virtuelle', + visibleInSlicer: 'Visible comme "Bambuddy" dans le Slicer', + proxyingTo: 'Proxy vers {{name}}', + notActive: 'Inactive', + }, + model: { + title: 'Modèle d\'imprimante', + description: 'Choisissez le modèle à émuler.', + restartWarning: 'Changer le modèle redémarrera le service', + }, + accessCode: { + title: 'Code d\'accès', + isSet: 'Code défini', + notSet: 'Code requis pour activer', + placeholder: 'Code 8 char', + placeholderChange: 'Entrez nouveau code', + hint: 'Exactement 8 caractères. Sert à l\'auth du Slicer.', + charCount: '({{count}}/8)', + }, + targetPrinter: { + title: 'Imprimante cible', + configured: 'Cible configurée', + notConfigured: 'Imprimante requise pour mode Proxy', + placeholder: 'Choisir imprimante...', + hint: 'L\'imprimante doit être en mode LAN.', + noPrinters: 'Ajoutez une imprimante réelle d\'abord.', + }, + remoteInterface: { + title: 'Exception Interface Réseau', + configured: 'Override actif', + optional: 'Optionnel - si IP auto est fausse (VPN, Docker, multi-NIC).', + placeholder: 'Auto (défaut)...', + hint: 'Force l\'IP annoncée via SSDP.', + }, + mode: { + title: 'Mode', + archive: 'Archiver', + archiveDesc: 'Archive immédiatement', + review: 'Revue', + reviewDesc: 'Attendre revue avant archive', + queue: 'File', + queueDesc: 'Archiver et ajouter à la file', + proxy: 'Proxy', + proxyDesc: 'Relais vers imprimante réelle', + }, + setupRequired: { + title: 'Configuration requise', + description: 'Nécessite des réglages système (ports, pare-feu).', + readGuide: 'Lire le guide de configuration', + }, + howItWorks: { + title: 'Fonctionnement', + titleProxy: 'Fonctionnement (Mode Proxy)', + step1: 'Suivez le guide pour votre plateforme', + step2: 'Activez et réglez le code d\'accès', + step3: 'Dans le Slicer, allez dans "Ajouter Imprimante"', + step4: '"Bambuddy" apparaîtra dans la découverte', + step5: 'Connectez avec votre code d\'accès', + step6: 'Imprimez vers Bambuddy : le 3MF est archivé', + proxyStep1: 'Cible réelle en mode LAN', + proxyStep2: 'Choisissez l\'interface réseau', + proxyStep3: 'Activez le proxy', + proxyStep4: 'Connectez avec le code de la vraie imprimante', + proxyStep5: 'Le trafic est relayé par Bambuddy', + proxyStep6: 'Streaming caméra : voir doc NAT/IP forwarding', + }, + status: { + title: 'Détails du statut', + printerName: 'Nom', + model: 'Modèle', + serialNumber: 'Série', + mode: 'Mode', + pendingFiles: 'Fichiers en attente', + targetPrinter: 'Cible', + ftpPort: 'Port FTP', + mqttPort: 'Port MQTT', + ftpConnections: 'Connexions FTP', + mqttConnections: 'Connexions MQTT', + }, + toast: { + updated: 'Réglages virtuels mis à jour', + failedToUpdate: 'Échec mise à jour', + accessCodeRequired: 'Code d\'accès requis', + targetPrinterRequired: 'Imprimante cible requise', + accessCodeEmpty: 'Le code ne peut pas être vide', + accessCodeLength: 'Le code doit faire 8 caractères', + }, + }, + + // Model Viewer + modelViewer: { + openInSlicer: 'Ouvrir dans le Slicer', + tabs: { + model: 'Modèle 3D', + gcode: 'Aperçu G-code', + }, + notAvailable: 'indisponible', + notSliced: 'pas découpé', + plates: 'Plateaux', + allPlates: 'Tous les plateaux', + plateNumber: 'Plateau {{number}}', + plateCount: '{{count}} plateau', + plateCount_other: '{{count}} plateaux', + objectCount: '{{count}} objet', + objectCount_other: '{{count}} objets', + filamentCount: '{{count}} filament', + filamentCount_other: '{{count}} filaments', + eta: 'Fin {{minutes}} min', + noPreview: 'Aucun aperçu pour ce fichier', + pagination: { + pageOf: 'Page {{current}} sur {{total}}', + prev: 'Préc', + next: 'Suiv', + }, + errors: { + failedToLoad: 'Échec chargement fichier', + noMeshes: 'Aucun maillage trouvé dans le 3MF', + unsupportedFormat: 'Format non supporté', + }, + }, + + // Maintenance type descriptions + maintenanceDescriptions: { + lubricateRails: 'Lubrifier les rails pour un mouvement fluide', + cleanNozzle: 'Nettoyer buse et hotend anti-bouchage', + checkBelts: 'Tension des courroies pour la précision', + cleanBuildPlate: 'Nettoyage plateau pour l\'adhésion', + checkExtruder: 'Usure des engrenages de l\'extrudeur', + checkCooling: 'Bon fonctionnement des ventilateurs', + generalInspection: 'Inspection générale de la machine', + cleanCarbonRods: 'Tiges carbone sans frottement', + checkPtfeTube: 'Usure ou dommage du tube PTFE', + replaceHepaFilter: 'Filtre HEPA pour la qualité de l\'air', + replaceCarbonFilter: 'Filtre charbon actif (odeurs)', + lubricateLeftNozzleRail: 'Rail gauche (Série H2)', + }, + + // Smart Plugs + smartPlugs: { + offline: 'Hors ligne', + admin: 'Admin', + openPlugAdminPage: 'Page admin de la prise', + deleteSmartPlug: 'Supprimer la prise', + turnOnSmartPlug: 'Allumer la prise', + turnOffSmartPlug: 'Éteindre la prise', + turnOn: 'Allumer', + turnOff: 'Éteindre', + addSmartPlug: { + scanningNetwork: 'Scan réseau...', + chooseEntity: 'Choisir une entité...', + connectionFailed: 'Échec connexion', + searchEntities: 'Chercher entités...', + searchPowerSensors: 'Capteurs puissance...', + searchEnergySensors: 'Capteurs énergie...', + placeholders: { + plugName: 'Prise Salon', + mqttStateOnValue: 'ON, true, 1', + mqttSameAsPower: 'Identique au topic puissance, ou différent', + }, + }, + }, + + // Rich Text Editor + richTextEditor: { + bold: 'Gras', + italic: 'Italique', + underline: 'Souligné', + bulletList: 'Liste à puces', + numberedList: 'Liste numérotée', + alignLeft: 'Aligner à gauche', + alignCenter: 'Centrer', + alignRight: 'Aligner à droite', + addLink: 'Ajouter lien', + removeLink: 'Retirer lien', + }, + + // External Links + externalLinks: { + noLinksConfigured: 'Aucun lien externe configuré', + deleteLink: 'Supprimer lien', + removeCustomIcon: 'Retirer icône personnalisée', + placeholders: { + linkName: 'Mon Lien', + }, + }, + + // Keyboard Shortcuts Modal + keyboardShortcuts: { + title: 'Raccourcis Clavier', + navigation: 'Navigation', + archivesSection: 'Archives', + kProfilesSection: 'K-Profiles', + generalSection: 'Général', + shortcuts: { + goToPrinters: 'Aller aux Imprimantes', + goToArchives: 'Aller aux Archives', + goToQueue: 'Aller à la File', + goToStats: 'Aller aux Stats', + goToProfiles: 'Aller aux Profils Cloud', + goToSettings: 'Aller aux Paramètres', + focusSearch: 'Focus recherche', + openUploadModal: 'Ouvrir téléversement', + clearSelection: 'Tout déselectionner', + contextMenu: 'Menu contextuel (cartes)', + refreshProfiles: 'Rafraîchir profils', + newProfile: 'Nouveau profil', + exitSelectionMode: 'Quitter mode sélection', + showHelp: 'Afficher cette aide', + }, + footer: 'Échap ou clic extérieur pour fermer', + }, + + // Notification Log + notificationLog: { + title: 'Journal de Notification', + events: { + printStarted: 'Début impression', + printComplete: 'Fin impression', + printFailed: 'Échec impression', + printStopped: 'Arrêt impression', + progress: 'Progression', + printerOffline: 'Hors ligne', + printerError: 'Erreur', + lowFilament: 'Filament bas', + maintenanceDue: 'Maintenance', + test: 'Test', + }, + timeAgo: { + justNow: 'À l\'instant', + minutesAgo: 'Il y a {{minutes}}m', + hoursAgo: 'Il y a {{hours}}h', + }, + }, + + // Restore/Backup Modal + restoreBackup: { + title: 'Restaurer Sauvegarde', + restoring: 'Restauration...', + restoreComplete: 'Restauration terminée', + restoreFailed: 'Échec restauration', + importSettings: 'Importer les réglages d\'un fichier', + pleaseWait: 'Patientez pendant la restauration', + clickToSelect: 'Fichier .json ou .zip', + howDuplicateHandling: 'Gestion des doublons :', + categories: { + printers: 'Imprimantes', + smartPlugs: 'Prises', + notificationProviders: 'Fournisseurs', + filaments: 'Filaments', + archives: 'Archives', + pendingUploads: 'Téléversements en attente', + settingsTemplates: 'Réglages & Modèles', + }, + matchingInfo: { + printers: 'par numéro de série', + smartPlugs: 'par adresse IP', + notificationProviders: 'par nom', + filaments: 'par nom+type+marque', + archives: 'par empreinte numérique (hash)', + pendingUploads: 'par nom de fichier', + settingsTemplates: 'toujours écrasés', + }, + replaceExisting: 'Remplacer existant', + keepExisting: 'Garder existant', + replaceDescription: 'Écrase les doublons avec la sauvegarde', + keepDescription: 'Ne restaure que les éléments absents', + caution: 'Attention :', + cautionText: 'L\'écrasement remplacera vos réglages. Les codes d\'accès imprimantes sont exclus par sécurité.', + itemsRestored: 'Éléments restaurés', + itemsSkipped: 'Éléments ignorés', + restored: 'Restaurés', + skipped: 'Ignorés (déjà présents)', + filesLabel: 'Fichiers (3MF, vignettes, etc.)', + newApiKeysGenerated: 'Nouvelles clés API générées', + newApiKeysWarning: 'Copiées maintenant, elles ne seront plus visibles !', + processingBackup: 'Traitement du fichier...', + noDataFound: 'Aucune donnée trouvée dans le fichier.', + failedToRestore: 'Échec restaure. Vérifiez le format.', + }, + + // Backup Export Modal + backupExport: { + title: 'Exporter Sauvegarde', + selectData: 'Données à inclure', + selectAll: 'Tout sélectionner', + selectNone: 'Ne rien sélectionner', + categoryDescriptions: { + settings: 'Langue, thèmes, préférences', + notifications: 'ntfy, Pushover, Discord, etc.', + templates: 'Modèles de messages personnalisés', + smartPlugs: 'Configuration des prises Tasmota', + externalLinks: 'Liens externes de la barre latérale', + printers: 'Infos imprimantes (codes d\'accès exclus par défaut)', + plateDetection: 'Images références des plateaux vides', + filaments: 'Types et coûts filaments', + maintenance: 'Plannings de maintenance personnalisés', + archives: 'Données impressions + fichiers (3MF, vignettes, etc.)', + projects: 'Projets, BOM, pièces jointes', + pendingUploads: 'En attente revue virtuelle', + apiKeys: 'Clés Webhook (nouvelles clés générées à l\'import)', + }, + requiresPrinters: 'Nécessite sélection des imprimantes', + zipFileWarning: 'Fichier ZIP créé.', + zipFileDescription: 'Contient tous les médias. Peut être volumineux.', + includeAccessCodes: 'Inclure Codes d\'accès', + includeAccessCodesDescription: 'Pour migrer vers une autre machine', + includeAccessCodesWarning: 'Codes en texte clair. Sécurisez ce fichier !', + categoriesSelected: '{{selectedCount}} catégories choisies', + }, + + // Pending Uploads Panel + pendingUploads: { + placeholders: { + notes: 'Notes sur l\'impression...', + }, + discardUpload: 'Rejeter', + archiveAllUploads: 'Tout archiver', + discardAllUploads: 'Tout rejeter', + archive: 'Archiver', + timeAgo: { + justNow: 'À l\'instant', + minutesAgo: 'Il y a {{minutes}}m', + hoursAgo: 'Il y a {{hours}}h', + daysAgo: 'Il y a {{days}}j', + }, + }, + + // API Browser + apiBrowser: { + placeholders: { + requestBody: 'Corps JSON...', + searchEndpoints: 'Chercher endpoints...', + }, + }, + + // Configure AMS Slot Modal + configureAmsSlot: { + searchPresets: 'Chercher presets...', + colorPlaceholder: 'Nom couleur ou hex (ex: brown, FF8800)', + clearCustomColor: 'Effacer couleur perso', + noCloudPresets: 'Profils Cloud absents. Connectez-vous.', + noMatchingPresets: 'Aucun profil trouvé.', + custom: 'Perso', + settingsSentToPrinter: 'Réglages envoyés', + filamentProfile: 'Profil Filament', + }, + + // GitHub Backup Settings + githubBackup: { + title: 'Sauvegarde GitHub', + history: 'Historique', + downloadBackup: 'Télécharger', + restoreBackup: 'Restaurer', + noBackupsYet: 'Aucune sauvegarde', + }, + + // Email Settings + emailSettings: { + placeholders: { + fromName: 'BamBuddy', + }, + }, + + // Tag Management Modal + tagManagement: { + searchTags: 'Chercher tags...', + renameTag: 'Renommer tag', + deleteTag: 'Supprimer tag', + }, + + // Notification Template Editor + notificationTemplates: { + placeholders: { + title: 'Titre notification...', + body: 'Message notification...', + }, + }, + + // Batch Tag Modal + batchTag: { + placeholders: { + newTag: 'Nouveau tag...', + }, + }, + + // Photo Gallery Modal + photoGallery: { + deletePhoto: 'Supprimer photo', + }, + + // Filament Hover Card + filamentHoverCard: { + copySpoolUuid: 'Copier UUID bobine', + }, + + // K Profiles View + kProfilesView: { + hasNote: 'A une note', + copyProfile: 'Copier profil', + }, + + // Layout/Navigation + layout: { + openMenu: 'Ouvrir menu', + noPermissionSystemInfo: 'Pas d\'autorisation système', + }, + + // Dashboard + dashboard: { + dragToReorder: 'Glisser pour réorganiser', + hideWidget: 'Masquer widget', + }, + + // Notification Provider Card + notificationProviderCard: { + deleteNotificationProvider: 'Supprimer fournisseur', + }, + + // File Manager Modal + fileManagerModal: { + closeFileManager: 'Fermer gestionnaire', + sortFiles: 'Trier fichiers', + goToParentFolder: 'Dossier parent', + threeView: 'Vue 3D', + }, + + // Embedded Camera Viewer + embeddedCameraViewer: { + refreshStream: 'Actualiser flux', + close: 'Fermer', + zoomOut: 'Zoom -', + resetZoom: 'Reset zoom', + zoomIn: 'Zoom +', + dragToResize: 'Glisser pour dimension', + }, + + // Timelapse Viewer + timelapseViewer: { + skipBack5s: '-5s', + skipForward5s: '+5s', + }, + + // Notification Providers + notificationProviders: { + descriptions: { + email: 'Notifications par email SMTP', + telegram: 'Via bot Telegram', + discord: 'Via webhook Discord', + ntfy: 'Push auto-hébergé (ntfy)', + pushover: 'Push fiable (Pushover)', + callmebot: 'WhatsApp gratuit via CallMeBot', + webhook: 'Requête HTTP POST personnalisée', + }, + }, + + // Log Viewer + logViewer: { + searchPlaceholder: 'Message ou nom...', + noLogEntries: 'Aucune entrée journal', + }, + + // Switchbar Popover + switchbarPopover: { + noSwitchesInSwitchbar: 'Aucun interrupteur', + }, + + // Project Page Modal + projectPageModal: { + placeholders: { + title: 'Titre', + designer: 'Designer', + license: 'Licence', + description: 'Description...', + profileTitle: 'Titre du profil', + profileDescription: 'Description du profil...', + }, + }, + + // Spoolman Settings + spoolmanSettings: {}, +}; \ No newline at end of file