Files
aigc-home/calliope-web/src/lib/i18n/fr.ts
T
施工员andmultica-agent 1c00587a56 feat(workflows): 工作流批量导入向导与元数据管理列表 (HEL-682 S4)
- WorkflowBatchImportWizard:目录扫描/多文件 → dry-run 逐文件报告 → 确认导入;
  warn 可补用途、需确认与 fail 项不导入不标可运行、重复导入全量 conflict 跳过
- WorkflowLibrary:view=meta 轻量列表(搜索/分类/模型/媒介/收藏/最近/启停/
  去重/批量标注),完整 JSON 仅操作时按需加载;试运行复用 WorkflowTestDialog;
  保留用途确认、输出指定、单文件导入等既有能力
- api/types:listMeta、convert、importBatch、importScanDry/Commit、touch、
  dedupe 客户端与 WorkflowMeta/转换报告类型;update 支持 favorite/tags/
  category/model_family
- i18n 130 键 ×7 语言;changelog

Co-authored-by: multica-agent <github@multica.ai>
2026-10-11 12:13:52 +08:00

2233 lines
115 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Dict } from './en';
export const fr: Dict = {
// --- Common ---
'common.add': 'Ajouter',
'common.cancel': 'Annuler',
'common.cancelButton': 'Annuler',
'common.delete': 'Supprimer',
'common.description': 'Description',
'common.edit': 'Modifier',
'common.failed': 'Échec',
'common.generating': 'Génération',
'common.loading': 'Chargement',
'common.missing': 'Manquant',
'common.name': 'Nom',
'common.pending': 'En attente',
'common.queued': 'En file',
'common.ready': 'Prêt',
'common.rename': 'Renommer',
'common.retry': 'Réessayer',
'common.running': 'En cours',
'common.save': 'Enregistrer',
'common.saved': 'Enregistré',
'common.saveFailed': "Échec de l'enregistrement",
'common.saving': 'Enregistrement',
'common.send': 'Envoyer',
'common.stop': 'Arrêter',
'common.title': 'Titre',
'common.language': 'Langue',
// --- App shell / nav ---
'nav.canvas': 'Canvas IA',
'nav.library': 'Bibliothèque d’assets',
'nav.projects': 'Projets',
'nav.buildScene': 'Composer la scène',
'nav.settings': 'Paramètres',
'nav.agents': 'Agents',
'nav.models': 'Modèles',
'nav.home': 'Accueil',
'nav.primary': 'Principal',
'nav.projectStages': 'Étapes du projet',
'nav.backProjects': 'Retour aux projets',
'nav.story': 'Histoire',
'nav.assets': 'Ressources',
'nav.script': 'Scénario',
'nav.video': 'Vidéo',
'nav.countActive': '{count} en cours',
'nav.eyebrow': 'Calliope',
'nav.unsaved': 'Modifications non enregistrées',
'nav.llm': 'LLM',
'nav.llmBlurb': "Configurez les modèles de langage utilisés par l'agent.",
'nav.comfy': 'ComfyUI',
'nav.comfyBlurb': "Où ComfyUI s'exécute.",
'nav.workflows': 'Workflows',
'nav.workflowsBlurb': 'Importez et enregistrez des workflows ComfyUI pour la génération.',
'nav.agent': 'Modèle agent',
'nav.agentBlurb': "Modèle utilisé pour la rédaction de l'histoire et les tâches de l'agent.",
'nav.skills': 'Compétences',
'nav.skillsBlurb': "Compétences de l'agent disponibles dans ce projet.",
'nav.queue': "File d'attente",
'nav.queueBlurb': 'Parallélisme et délais des tâches de génération.',
'nav.storage': 'Chemins système',
'nav.storageBlurb': "Où les fichiers sont stockés et où l'agent peut travailler.",
// --- Toast ---
'toast.dismiss': 'Ignorer',
'toast.undo': 'Annuler',
'toast.uploadFailed': "Échec de l'import",
// --- Modal ---
'modal.dialog': 'Boîte de dialogue',
'modal.closeDialog': 'Fermer la boîte de dialogue',
// --- Projects page ---
'projects.new': 'Nouveau projet',
'projects.title': 'Projets',
'projects.subtitle': "Votre espace local de l'histoire à la vidéo. Reprenez où vous en étiez.",
'projects.newReel': 'Nouveau montage',
'projects.close': 'Fermer',
'projects.titleField': 'Titre',
'projects.titlePlaceholder': 'Port au clair de lune',
'projects.ideaField': "Idée d'histoire",
'projects.ideaPlaceholder': 'Un gardien de phare découvre une bouteille lumineuse qui montre les souvenirs de marins perdus en mer…',
'projects.ideaHint': "Facultatif — vous pourrez l'affiner plus tard à l'étape Histoire.",
'projects.genre': 'Genre',
'projects.tone': 'Ton',
'projects.duration': 'Durée cible',
'projects.durationHint': "Guide le nombre de beats et de scènes à l'étape Histoire.",
'projects.cancel': 'Annuler',
'projects.create': 'Créer le projet',
'projects.searchPlaceholder': 'Rechercher des projets…',
'projects.searchLabel': 'Rechercher des projets',
'projects.filterBy': 'Filtrer par statut',
'projects.filterAll': 'Tous',
'projects.filterProgress': 'En cours',
'projects.filterCompleted': 'Terminés',
'projects.filterDraft': 'Brouillons',
'projects.loading': 'Chargement des projets',
'projects.loadError': 'Impossible de charger les projets',
'projects.loadErrorBody': "Le backend n'a pas répondu.",
'projects.emptyTitle': 'Aucun projet pour le moment',
'projects.emptyBody': "Calliope transforme une idée d'histoire en personnages, plans et vidéo finale — entièrement sur votre machine.",
'projects.firstProject': 'Créer votre premier projet',
'projects.noMatchSearch': 'Aucun projet ne correspond à « {q} »',
'projects.noMatchFilter': 'Aucun projet ne correspond au filtre actuel',
'projects.noMatchBody': 'Essayez une autre recherche ou effacez les filtres.',
'projects.clearFilters': 'Effacer les filtres',
'projects.newCard': 'Créer un nouveau projet',
'projects.newCardSub': "Commencez par une idée d'histoire",
'projects.created': 'Projet « {title} » créé',
'projects.createFailed': 'Impossible de créer le projet',
// --- Project form options (values stored in English) ---
'genres.adventure': 'Aventure / Mystère',
'genres.drama': 'Drame',
'genres.scifi': 'Science-fiction',
'genres.fantasy': 'Fantastique',
'genres.horror': 'Horreur',
'genres.romance': 'Romance',
'genres.thriller': 'Thriller',
'tones.cinematic': 'Cinématographique, atmosphérique',
'tones.dark': 'Sombre, tendu',
'tones.whimsical': 'Fantaisiste, chaleureux',
'tones.gritty': 'Cru, réaliste',
'tones.epic': 'Épique, grandiose',
'durations.30': '30 secondes',
'durations.1m': '1 minute',
'durations.2m': '2 minutes',
'durations.5m': '5 minutes',
'durations.10m': '10 minutes',
// --- Project card ---
'projectCard.actions': 'Actions du projet',
'projectCard.assets': 'Ressources',
'projectCard.changeCover': 'Changer la couverture',
'projectCard.characters': 'Personnages',
'projectCard.deleted': 'Projet supprimé',
'projectCard.deleteFailed': 'Impossible de supprimer le projet',
'projectCard.deleteMessage': 'Cela supprimera définitivement le projet et ses ressources. Cette action est irréversible.',
'projectCard.deleteTitle': 'Supprimer le projet',
'projectCard.menuLabel': 'Menu du projet',
'projectCard.noIdea': "Pas encore d'idée d'histoire",
'projectCard.open': 'Ouvrir le projet',
'projectCard.renamedTo': 'Renommé en « {title} »',
'projectCard.renameFailed': 'Impossible de renommer le projet',
'projectCard.renameTitle': 'Renommer le projet',
'projectCard.scenes': 'Scènes',
'projectCard.status.in_progress': 'En cours',
'projectCard.status.completed': 'Terminé',
'projectCard.status.draft': 'Brouillon',
'projectCard.timeJustNow': "à l'instant",
'projectCard.timeM': 'il y a {n} min',
'projectCard.timeH': 'il y a {n} h',
'projectCard.timeD': 'il y a {n} j',
'projectCard.timeMo': 'il y a {n} mois',
'projectCard.timeY': 'il y a {n} ans',
// --- Project detail page ---
'project.backToProjects': 'Retour aux projets',
'project.notFound': 'Projet introuvable',
'project.invalidIdBody': "« {id} » n'est pas un identifiant de projet valide — le lien est peut-être rompu ou le projet a été supprimé.",
'project.openVideoStage': "Ouvrir l'étape Vidéo",
'project.runningQueued': '{running} en cours · {queued} en file',
'project.queueIdle': "File d'attente inactive",
// --- API errors ---
'api.unknownError': "Une erreur s'est produite",
'api.networkError': 'Impossible de joindre le backend : vérifiez qu\'il tourne puis réessayez',
'api.httpError': 'Échec de la requête (HTTP {status}) : {detail}',
'playground.openFailed': "Échec de l'ouverture du bac à sable",
'playground.opening': 'Ouverture du bac à sable…',
'agents.opening': "Ouverture de l'agent…",
'agents.openFailed': "Échec de l'ouverture de l'agent",
// --- ActivityPanel ---
'activity.title': 'Activité',
'activity.agentLog': "Journal de l'agent",
'activity.agentWorking': "L'agent travaille…",
'activity.assetReady': 'Ressource prête',
'activity.busyCount': '{n} en cours',
'activity.connecting': 'Connexion',
'activity.reconnecting': 'Reconnexion',
'activity.quiet': 'Inactif',
'activity.quietHint': 'Aucune tâche en arrière-plan',
'activity.show': 'Afficher',
'activity.hide': 'Masquer',
'activity.done': 'Terminé',
'activity.failed': 'Échec',
'activity.files': 'Fichiers',
'activity.filesSaved': '{n} fichiers enregistrés',
'activity.finished': 'Terminé',
'activity.jobDeleted': 'Tâche supprimée',
'activity.outputSaved': 'Résultat enregistré',
'activity.queue': "File d'attente",
'activity.queueIdle': "File d'attente inactive",
'activity.queueStats': '{active} en cours · {queued} en file',
'activity.queued': 'En file',
'activity.removed': 'Supprimé',
'activity.running': 'En cours',
'activity.storylineDrafted': 'Trame rédigée',
'activity.storyReady': 'Histoire prête',
'activity.working': 'En cours…',
// --- SafeMedia ---
'safeMedia.noMedia': 'Aucun média',
// --- ImageLightbox ---
'lightbox.clickToFit': 'Cliquer pour ajuster',
'lightbox.clickToZoom': 'Cliquer pour zoomer',
'lightbox.closeEsc': 'Appuyez sur Échap pour fermer',
'lightbox.closeHint': 'Fermer',
'lightbox.closePreview': "Fermer l'aperçu",
'lightbox.download': 'Télécharger',
'lightbox.downloadMedia': 'Télécharger le média',
'lightbox.fitToScreen': "Ajuster à l'écran",
'lightbox.imagePreview': "Aperçu de l'image",
'lightbox.imageUnavailable': 'Image indisponible',
'lightbox.next': 'Suivant',
'lightbox.prev': 'Précédent',
'lightbox.openOriginal': "Ouvrir l'original",
'lightbox.videoPreview': 'Aperçu de la vidéo',
'lightbox.videoUnavailable': 'Vidéo indisponible',
'lightbox.zoom100': '100 %',
'lastFrame.export': 'Exporter la dernière image',
'lastFrame.exporting': 'Export de la dernière image…',
'lastFrame.hint': 'Enregistre la dernière image en PNG pleine taille, p. ex. comme référence de première image',
'lastFrame.fileTag': 'derniere-image',
'lastFrame.done': 'Dernière image exportée {name} ({size})',
'lastFrame.errTimeout': 'Le chargement de la vidéo a expiré. Réessayez plus tard.',
'lastFrame.errNotFound': 'Le fichier vidéo est introuvable ou a été supprimé.',
'lastFrame.errForbidden': "Vous n'avez pas l'autorisation de lire cette vidéo.",
'lastFrame.errNetwork': 'Lecture de la vidéo impossible (erreur réseau).',
'lastFrame.errDecode': 'La vidéo est endommagée ; sa fin ne peut pas être décodée.',
'lastFrame.errUnsupported': 'Ce navigateur ne prend pas en charge ce format vidéo, ou le fichier est endommagé.',
'lastFrame.errCrossOrigin':
"La vidéo provient d'un autre site qui bloque la lecture des images (cross-origin). Téléchargez d'abord la vidéo.",
'lastFrame.errNoPicture': "Ce fichier ne contient pas d'image vidéo.",
'lastFrame.errUnseekable':
"Impossible d'atteindre la fin de la vidéo (durée inconnue ou source sans recherche) ; aucune image exportée.",
'lastFrame.errBlack': 'La dernière seconde de la vidéo est noire ; aucune image exportée.',
'lastFrame.errEmpty': "Le navigateur n'a pas pu décoder la fin. Réessayez ou utilisez Chrome / Edge sur ordinateur.",
'lastFrame.errUnknown': "Échec de l'export de la dernière image : {msg}",
// --- Artifact / canvas nodes ---
'artifact.artifactLabel': 'Artefact',
'artifact.fileMissing': 'Fichier manquant',
'artifact.imageUnavailable': 'Image indisponible',
'artifact.playInViewer': 'Lire dans la visionneuse',
'artifact.playVideo': 'Lire la vidéo',
'artifact.videoUnavailable': 'Vidéo indisponible',
'artifact.viewImage': "Voir l'image",
'canvas.emptyHint': "Demandez à l'agent à droite de créer des personnages ou des scènes, ou de générer une image ou une vidéo — les résultats apparaissent ici sous forme de cartes.",
'canvas.loadFailed': 'Impossible de charger ce canevas',
'canvas.tidy': 'Ranger la disposition',
'canvas.tidyTitle': 'Réorganiser toutes les cartes en colonnes et grilles propres',
'canvas.savePosFailed': "Impossible d'enregistrer la position",
'canvas.openThatFailed': "Impossible d'ouvrir ce canevas",
'canvas.sessionCreateFailed': 'Impossible de créer la session',
'canvas.sessionDeleteFailed': 'Impossible de supprimer la session',
'canvas.renameFailed': 'Échec du renommage',
'canvas.suggestFilm': 'Créer un nouveau film',
'canvas.suggestStory': 'Rédiger une trame',
'canvas.emptyBoard': 'Tableau vide',
'canvas.noChatSelected': 'Aucune discussion sélectionnée',
'canvas.failed': 'échec',
'canvas.generating': 'génération…',
'canvas.noMedia': 'aucun média',
'canvas.openPreview': 'Ouvrir un grand aperçu',
'canvas.running': 'en cours',
'canvas.openFailed': "Échec de l'ouverture du tableau",
'canvas.opening': 'Ouverture du tableau…',
'canvas.invalidId': 'Identifiant de canevas invalide',
'canvas.confirmDeleteChat': 'Supprimer cette discussion et son historique de messages ?',
'canvas.sessionDeleted': 'Session supprimée',
'canvas.chatUnlinked': 'Discussion dissociée — déplacée vers le bac à sable',
'canvas.unlinkFailed': 'Échec de la dissociation',
'canvas.unlinkButton': 'Dissocier',
'canvas.resizePanel': 'Redimensionner le panneau de discussion (glisser ou touches fléchées), actuellement {width} pixels',
'canvas.sendFailed': "Échec de l'envoi",
'canvas.runCancelled': 'Exécution annulée',
'canvas.cancelFailed': "Échec de l'annulation",
'canvas.tidied': '{count} cartes rangées en colonnes',
'canvas.tidyFailed': 'Échec du rangement',
'canvas.rename': 'Renommer le canevas',
'canvas.waitFinish': "Attendez la fin de l'exécution",
'canvas.unlinkFrom': 'Dissocier cette discussion de {title}',
'canvas.noChatYet': 'Pas encore de discussion sur ce canevas',
'canvas.collapseChat': 'Réduire la discussion',
'canvas.expandChat': 'Développer la discussion',
'canvas.deleteBlocked': 'Les assets de projet et les jobs en cours ne peuvent pas être supprimés ici – remplacez-les depuis les assets du projet',
'canvas.deleteFailed': 'Impossible de supprimer {count} carte(s)',
'canvas.deletedWithFile': '{count} carte(s) et fichier(s) supprimés de la bibliothèque d’assets',
'canvas.deletedCardOnly': '{count} carte(s) retirée(s) – fichier conservé (données du projet)',
'canvas.deletedMixed': '{files} fichier(s) supprimé(s), {kept} conservé(s) (données du projet)',
"global.somethingWentWrong": "Une erreur s'est produite.",
// --- Memory ---
'memory.title': 'Mémoire',
'memory.lead': "Faits persistants que l'agent retient d'une session à l'autre.",
'memory.empty': 'Rien enregistré pour le moment',
'memory.loading': 'Chargement de la mémoire',
'memory.placeholder': "Ajouter un fait que l'agent doit retenir…",
'memory.saveFailed': "Impossible d'enregistrer la mémoire",
'memory.saved': 'Enregistré',
'memory.deleteFailed': 'Impossible de supprimer',
'memory.forget': 'Oublier',
'memory.chooseProject': 'Projet',
'memory.kindConvention': 'Convention',
'memory.kindCorrection': 'Correction',
'memory.kindPreference': 'Préférence',
'memory.groupGlobal': 'Global',
'memory.groupProject': 'Projet',
'memory.scopeGlobal': 'Tous les projets',
'memory.scopeProject': 'Ce projet',
'memory.sourceAgent': 'Agent',
'memory.sourceYou': 'Vous',
'memory.usedCount': 'Utilisé {n} fois',
// --- Skills ---
'skills.title': 'Compétences',
'skills.lead': "Compétences de l'agent disponibles dans ce projet.",
'skills.close': 'Fermer',
'skills.copied': 'Copié',
'skills.copy': 'Copier le chemin',
'skills.copyPath': 'Chemin copié dans le presse-papiers',
'skills.copyPathBtn': 'Copier',
'skills.couldNotRead': 'Impossible de lire la compétence',
'skills.filesIn': 'Fichiers de cette compétence',
'skills.hideFiles': 'Masquer les fichiers',
'skills.showFiles': 'Afficher les fichiers',
'skills.howto1': "Les compétences ajoutent des capacités réutilisables à l'agent.",
'skills.howto2': 'Référencez une compétence avec @name dans le composeur.',
'skills.howto3': "L'agent la charge à la demande.",
'skills.howto4': 'Ajoutez des compétences en plaçant des dossiers sous .agents/skills.',
'skills.howtoTitle': 'Fonctionnement des compétences',
'skills.loadingFile': 'Chargement du fichier…',
'skills.noFiles': 'Aucun fichier',
'skills.noSkills': 'Aucune compétence disponible',
'skills.note': 'Remarque',
'skills.refresh': 'Actualiser',
'skills.refreshed': 'Compétences actualisées',
'skills.truncated': 'Aperçu tronqué',
// --- Reasoning ---
'reasoning.title': 'Raisonnement',
'reasoning.thinking': 'Réflexion…',
'reasoning.show': 'Afficher le raisonnement',
// --- Agent chat/composer ---
'agentChat.approveRender': 'Approuver le rendu',
'agentChat.approveReplace': 'Approuver le remplacement',
'agentChat.emptyHint': "L'agent est prêt. Demandez-lui de rédiger des trames, de modifier des ressources ou de composer des scènes.",
'agentChat.emptyTitle': 'Démarrer une conversation',
'agentChat.loading': 'Chargement de la conversation',
'agentChat.pickOption': 'Choisir une option',
'agentChat.working': "L'agent travaille…",
'agent.task.story': 'Rédiger la trame',
'agent.task.script': 'Régénérer le scénario',
'agentComposer.aria': 'Composeur de message',
'agentComposer.attach': 'Joindre un fichier',
'agentComposer.attachLimit': 'Limite de pièces jointes atteinte',
'agentComposer.attachments': 'Pièces jointes',
'agentComposer.mentionLock': 'Verrouillé sur ce projet',
'agentComposer.message': 'Message',
'agentComposer.placeholder': "Demandez à l'agent ou @mentionnez une compétence…",
'agentComposer.remove': 'Retirer la pièce jointe',
'agentComposer.sendTitle': 'Envoyer le message',
'agentComposer.stopTitle': "Arrêter l'agent",
'agentComposer.working': 'Envoi…',
'agentComposer.steer': 'Piloter',
'agentComposer.steerTitle': "Envoyer une correction pendant que l'agent travaille",
'agentComposer.steerPlaceholder': "Pilotez l'agent pendant qu'il travaille…",
'agentChat.steering': 'Pilotage',
'agentPlan.planner': 'Plan',
'agentPlan.skipped': 'Ignoré',
'agentTool.args': 'Arguments',
'agentTool.done': 'Terminé',
'agentTool.failed': 'Échec',
'agentTool.result': 'Résultat',
'agentTool.running': 'En cours…',
'mentionMenu.noSkill': 'Aucune compétence correspondante',
'mentionMenu.noWorkflow': 'Aucun workflow correspondant',
'mentionMenu.skills': 'Compétences',
'mentionMenu.workflows': 'Workflows',
// --- Agent session sidebar ---
'sessionSidebar.collapse': 'Réduire la barre latérale',
'sessionSidebar.expand': 'Développer la barre latérale',
'sessionSidebar.deleteSession': 'Supprimer la session',
'sessionSidebar.newProjectChat': 'Nouvelle discussion de projet',
'sessionSidebar.newSandbox': 'Nouveau bac à sable',
'sessionSidebar.newSandboxButton': 'Nouvelle session bac à sable',
'sessionSidebar.noSessions': 'Aucune session pour le moment',
'sessionSidebar.open': 'Ouvrir la session',
'sessionSidebar.projectFallback': 'Discussion de projet',
'sessionSidebar.sandbox': 'Bac à sable',
// --- Story stage ---
'story.stageTitle': 'Histoire',
'story.ideaTitle': "Idée d'histoire",
'story.ideaPlaceholder': "Décrivez l'histoire que vous voulez raconter…",
'story.targetLength': 'Durée cible',
'story.lengthsHint': 'Quelle durée doit avoir la vidéo finale ?',
'story.lengthHint': 'Guide le nombre de beats et de scènes.',
'story.draftStoryline': 'Rédiger la trame',
'story.draftPromptTitle': 'Prompt de rédaction',
'story.promptExplain': "Le brief final que l'agent utilise pour structurer l'histoire.",
'story.showPrompt': 'Afficher le prompt',
'story.hidePrompt': 'Masquer le prompt',
'story.promptCollapsedHint': 'Modifiez le prompt de rédaction avant de générer les beats.',
'story.addBeat': 'Ajouter un beat',
'story.addBeatManual': 'Ajouter un beat manuellement',
'story.addBeatFailed': "Impossible d'ajouter le beat",
'story.beatAdded': 'Beat ajouté',
'story.beatDeleted': 'Beat supprimé',
'story.beatSaved': 'Beat enregistré',
'story.deleteBeat': 'Supprimer le beat',
'story.deleteBeatFailed': 'Impossible de supprimer le beat',
'story.beats': 'Beats',
'story.editBeatTitle': 'Modifier le beat',
'story.editCharTitle': 'Modifier le personnage',
'story.editLocTitle': 'Modifier le lieu',
'story.editItemTitle': "Modifier l'objet",
'story.fieldAge': 'Âge',
'story.fieldAppearance': 'Apparence',
'story.fieldConsistency': 'Cohérence',
'story.fieldDescription': 'Description',
'story.fieldName': 'Nom',
'story.fieldPersonality': 'Personnalité',
'story.fieldRole': 'Rôle',
'story.fieldTitle': 'En-tête',
'story.noBeats': 'Aucun beat pour le moment',
'story.noBeatsBody': "Ajoutez des beats manuellement ou laissez l'agent rédiger une trame.",
'story.continueAssets': 'Continuer vers les ressources',
'story.confirmDeleteBeatMsg': 'Ce beat sera définitivement supprimé. Continuer ?',
'story.confirmDeleteBeatTitle': 'Supprimer le beat ?',
'story.confirmExampleMsg': "Cela remplace votre idée d'histoire actuelle par l'exemple.",
'story.confirmExampleTitle': "Charger l'exemple ?",
'story.exampleLoaded': 'Exemple chargé',
'story.extracted': "Extrait de l'histoire",
'story.charTag': 'PERSONNAGE',
'story.envTag': 'LIEU',
'story.itemTag': 'OBJET',
'story.beatsTitle': "Beats de l'histoire",
'story.characterSaved': 'Personnage enregistré',
'story.locationSaved': 'Lieu enregistré',
'story.itemSaved': 'Objet enregistré',
'story.openAssets': 'Ouvrir les ressources',
'story.loadExample': "Charger l'exemple",
'story.saveBeatFailed': "Impossible d'enregistrer le beat",
'story.saveCharacterFailed': "Impossible d'enregistrer le personnage",
'story.saveItemFailed': "Impossible d'enregistrer l'objet",
'story.saveLocationFailed': "Impossible d'enregistrer le lieu",
'story.saveSettingsFailed': "Impossible d'enregistrer les paramètres",
'story.settingsTitle': "Paramètres de l'histoire",
'story.llmBanner': "L'étape Histoire utilise le LLM actif pour rédiger et affiner les beats.",
'story.newBeat': 'Nouveau beat {n}',
// --- Assets stage ---
'assets.title': 'Ressources',
'assets.lead': 'Personnages, lieux et objets générés pour votre histoire.',
'assets.tabCharacters': 'Personnages',
'assets.tabEnvironments': 'Lieux',
'assets.tabItems': 'Objets',
'assets.tabAria': 'Onglets de type de ressource',
'assets.kind.character': 'Personnage',
'assets.kind.environment': 'Lieu',
'assets.kind.item': 'Objet',
'assets.charSheets': 'Feuilles de personnage',
'assets.envRefs': 'Références de lieu',
'assets.itemRefs': "Références d'objet",
'assets.charSheetPlaceholder': 'Feuille de référence',
'assets.optionEnvironment': 'Référence de lieu',
'assets.optionItem': "Référence d'objet",
'assets.optionSheet': 'Feuille de personnage',
'assets.generateImage': 'Générer une image',
'assets.generateSheet': 'Générer une feuille',
'assets.replaceImage': "Remplacer l'image",
'assets.regenImage': "Régénérer l'image",
'assets.regenSheet': 'Régénérer la feuille',
'assets.regenImageFor': "Régénérer l'image de « {name} »",
'assets.regenSheetFor': 'Régénérer la feuille de « {name} »',
'assets.generating': 'Génération…',
'assets.generatingEllipsis': 'Génération',
'assets.queuing': 'Mise en file…',
'assets.generateMissing': 'Générer les manquants',
'assets.generateMissingTitle': 'Générer les ressources manquantes',
'assets.editPrompt': 'Modifier le prompt',
'assets.savePrompt': 'Enregistrer le prompt',
'assets.resetSheetTemplate': 'Réinitialiser le modèle de feuille',
'assets.resetEnvTemplate': 'Réinitialiser le modèle de lieu',
'assets.resetItemTemplate': "Réinitialiser le modèle d'objet",
'assets.noCharsTitle': 'Aucun personnage pour le moment',
'assets.noCharsBody': "Les personnages apparaissent ici une fois définis par l'histoire.",
'assets.noEnvsTitle': 'Aucun lieu pour le moment',
'assets.noEnvsBody': "Les lieux apparaissent ici une fois définis par l'histoire.",
'assets.noItemsTitle': 'Aucun objet pour le moment',
'assets.noItemsBody': "Les objets apparaissent ici une fois définis par l'histoire.",
'assets.confirmDeleteTitle': 'Supprimer la ressource',
'assets.confirmDeleteLabel': 'Supprimer',
'assets.confirmDeleteBody': 'Cette ressource et ses images générées seront supprimées. Continuer ?',
'assets.confirmDeleteFallback': 'Supprimer cette ressource ?',
'assets.deleteCharacter': 'Supprimer le personnage',
'assets.deleteEnvironment': 'Supprimer le lieu',
'assets.deleteItem': "Supprimer l'objet",
'assets.deleteFor': 'Supprimer « {name} »',
'assets.description': 'Description',
'assets.appearance': 'Apparence',
'assets.personality': 'Personnalité',
'assets.cover': 'Couverture',
'assets.removeCover': 'Retirer la couverture',
'assets.removeCoverChar': 'Retirer la couverture du personnage',
'assets.removeCoverRef': 'Retirer la couverture de référence',
'assets.setCover': 'Définir comme couverture',
'assets.setCoverChar': 'Définir comme couverture du personnage',
'assets.setCoverRef': 'Définir comme couverture de référence',
'assets.refPlaceholder': 'Référence',
'assets.sentToComfy': 'Envoyé à ComfyUI',
'assets.uploadImage': 'Importer une image',
'assets.viewCharFull': 'Voir le personnage en entier',
'assets.viewRefFull': 'Voir la référence en entier',
'assets.viewFull': 'Voir en taille réelle',
'assets.charSheetAlt': 'Feuille de personnage pour {name}',
'assets.goToStory': "Aller à l'Histoire",
'assets.genSettings': 'Paramètres de génération',
'assets.toast.addImageFailed': "Impossible d'ajouter l'image",
'assets.toast.chooseImage': 'Choisissez une image',
'assets.toast.coverFail': 'Impossible de définir la couverture',
'assets.toast.coverRemoved': 'Couverture retirée',
'assets.toast.coverUpdated': 'Couverture mise à jour',
'assets.toast.deleted': 'Ressource supprimée',
'assets.toast.deleteFailed': 'Impossible de supprimer la ressource',
'assets.toast.imageAdded': 'Image ajoutée',
'assets.toast.jobRequeued': 'Demandé à nouveau',
'assets.toast.nothingMissing': 'Rien ne manque',
'assets.toast.notImage': "Ce fichier n'est pas une image",
'assets.toast.queued': 'Image mise en file',
'assets.toast.queuedMany': '{n} images mises en file',
'assets.toast.queuedOne': 'Image mise en file',
'assets.toast.retryFailed': 'Impossible de réessayer',
'assets.toast.savedPrompt': 'Prompt enregistré',
'assets.toast.savePromptFailed': "Impossible d'enregistrer le prompt",
'assets.wf.sheet': 'Workflow de feuille de personnage',
'assets.wf.environment': 'Workflow de référence de lieu',
'assets.wf.item': "Workflow de référence d'objet",
'assets.wf.selectSheet': 'Sélectionner un workflow de feuille',
'assets.wf.selectEnv': 'Sélectionner un workflow de lieu',
'assets.wf.selectItem': "Sélectionner un workflow d'objet",
'assets.wf.needWorkflow': "Configurez d'abord un workflow dans les Paramètres.",
'assets.wf.missingInputs': 'Ce workflow a des entrées obligatoires manquantes.',
'assets.wf.none': 'Aucun workflow sélectionné',
'assets.wf.noPromptPre': "Ce workflow n'a pas d'entrée de prompt.",
'assets.wf.noPromptPost': "Ajoutez un champ prompt pour l'utiliser ici.",
'assets.noWorkflowPre': 'La génération nécessite un workflow.',
'assets.noWorkflowPost': 'Configurez-en un dans les Paramètres.',
'assets.noWorkflowLink': 'Ouvrir les Paramètres',
// --- Build scene ---
'buildScene.title': 'Composer la scène',
'buildScene.builderBadge': 'Éditeur 3D',
'buildScene.preparing': 'Préparation de la scène…',
'buildScene.stillLoading': 'Scène en cours de chargement…',
'buildScene.expandChat': 'Développer la discussion',
'buildScene.collapseChat': 'Réduire la discussion',
'buildScene.videoExported': 'Vidéo exportée',
'buildScene.legacyNeedsViewport': 'Viewport pas prêt pour l\'export',
'buildScene.videoExportFailed': "Échec de l'export vidéo",
'buildScene.captureSaved': 'Capture enregistrée',
'buildScene.createSceneFailed': 'Impossible de créer la scène',
'buildScene.deleteSceneFailed': 'Impossible de supprimer la scène',
'buildScene.sendFailed': "Impossible d'envoyer le message",
'buildScene.runCancelled': 'Exécution annulée',
'buildScene.cancelFailed': "Impossible d'annuler",
'buildScene.openCompositionFailed': "Impossible d'ouvrir la composition",
'buildScene.uploadSizeFail': 'Fichier trop volumineux',
// --- Script stage ---
'script.actionField': 'Action',
'script.actionPlaceholder': 'Ce qui se passe dans cette scène…',
'script.dialogField': 'Dialogue',
'script.dialogPlaceholder': 'Qui dit quoi…',
'script.headingField': 'En-tête',
'script.headingPlaceholder': 'INT. PORT — NUIT',
'script.sceneNumber': 'Scène {n}',
'script.edit': 'Modifier la scène',
'script.editScene': 'Modifier la scène',
'script.editSceneNumbered': 'Modifier la scène {n}',
'script.durationField': 'Durée',
'script.addScene': 'Ajouter une scène',
'script.deleteSceneTitle': 'Supprimer la scène',
'script.deleteSceneMessage': 'Cette scène et ses plans seront supprimés. Continuer ?',
'script.delete': 'Supprimer la scène',
'script.loadingScenes': 'Chargement des scènes',
'script.noScenesTitle': 'Aucune scène pour le moment',
'script.noScenesBody': 'Découpez votre histoire en scènes pour commencer le tournage.',
'script.regenerate': 'Régénérer le scénario',
'script.break': 'Découper en plans',
'script.breakTitle': 'Découper la scène en plans',
'script.rebreak': 'Redécouper les plans',
'script.rebreakTitle': 'Redécouper les plans de cette scène',
'script.breakAllIntoShots': 'Tout découper en plans',
'script.breakAllTitle': 'Découper chaque scène en plans',
'script.chainOn': 'Activer le chaînage',
'script.chainOff': 'Désactiver le chaînage',
'script.chainTitle': 'Basculer le chaînage des clips',
'script.save': 'Enregistrer',
'script.untitledScene': 'Scène sans titre',
'script.untitledShot': 'Plan sans titre',
'script.justAdded': 'Ajouté',
'script.rendering': 'Rendu en cours…',
'script.renderedCount': '{n} clips rendus',
'script.clipDone': 'Clip terminé',
'script.noActionYet': 'Aucune action écrite pour le moment',
'script.shotClipSingular': '1 clip',
'script.shotClipPlural': '{n} clips',
'script.moveSceneUp': 'Déplacer la scène vers le haut',
'script.moveSceneDown': 'Déplacer la scène vers le bas',
'script.deleteShotAria': 'Supprimer le plan',
'script.deleteShotTitle': 'Supprimer le plan',
'script.status.rendering': 'Rendu',
'script.status.renderFailed': 'Échec',
'script.status.clipReady': 'Prêt',
'script.status.noClip': 'Aucun clip',
'script.toast.addSceneFail': "Impossible d'ajouter la scène",
'script.toast.boardExpanded': 'Scène ouverte sur le tableau',
'script.toast.breakAllConfirm': 'Découper toutes les scènes en plans ?',
'script.toast.breakAllFail': 'Impossible de découper les scènes',
'script.toast.breakFail': 'Impossible de découper la scène',
'script.toast.breakIntoShots': 'Scène découpée en plans',
'script.toast.deleteClipFail': 'Impossible de supprimer le clip',
'script.toast.deleted': 'Scène supprimée',
'script.toast.deletedShot': 'Plan supprimé',
'script.toast.deleteFailed': 'Impossible de supprimer',
'script.toast.saveSceneFail': "Impossible d'enregistrer la scène",
'script.toast.sceneAdded': 'Scène ajoutée',
'script.toast.sceneSaved': 'Scène enregistrée',
'script.toast.updateSceneFail': 'Impossible de mettre à jour la scène',
// --- Script drawer ---
'scriptDrawer.script': 'Scénario',
'scriptDrawer.heading': 'En-tête',
'scriptDrawer.action': 'Action',
'scriptDrawer.dialog': 'Dialogue',
'scriptDrawer.characters': 'Personnages',
'scriptDrawer.noAction': 'Aucune action écrite',
'scriptDrawer.noDialog': 'Aucun dialogue',
'scriptDrawer.regionAria': 'Zone du scénario',
'scriptDrawer.untitled': 'Sans titre',
'scriptDrawer.untitledScene': 'Scène sans titre',
// --- Queue stage ---
'queue.sceneLabel': 'Scène',
'queue.clipLabel': 'Clip n° {n}',
'queue.jobLabel': 'Tâche n° {n}',
'queue.scene': 'Scène {n}',
'queue.sceneRef': 'Référence de scène',
'queue.clipRef': 'Référence de clip',
'queue.clipQueued': 'Clip mis en file',
'queue.clipsDoneSummary': '{done}/{total} clips terminés',
'queue.clipsMissing': "Certains plans n'ont pas encore de clip",
'queue.clipRenderUpdated': 'Rendu du clip mis à jour',
'queue.clipsChanged': 'Clips modifiés',
'queue.blockoutLabel': 'Blockout',
'queue.blockoutSuffix': 'blockout',
'queue.blockoutClipSuffix': 'clip blockout',
'queue.uploadSuffix': 'import',
'queue.generateAllTitle': 'Générer tous les clips',
'queue.generateMissing': 'Générer les manquants',
'queue.regenerateAll': 'Tout régénérer',
'queue.queueingProgress': '{n}/{total} tâches mises en file',
'queue.queued': 'En file',
'queue.queuedInSequence': "S'exécutera en séquence",
'queue.pauseQueue': "Mettre la file en pause",
'queue.resumeQueue': "Reprendre la file",
'queue.paused': "File en pause",
'queue.pausedText': 'Les nouvelles tâches attendent que vous repreniez.',
'queue.resumeNow': 'Reprendre maintenant',
'queue.editTab': 'Scènes',
'queue.filmTab': 'Film',
'queue.filmViewAria': 'Vue film',
'queue.viewAria': "Vue de la file",
'queue.emptyHeader': 'Rien en file pour le moment',
'queue.noTimeline': 'Aucune timeline pour le moment',
'queue.noTimelineBody': "Générez d'abord des clips, puis exportez le film.",
'queue.savedDrafts': 'Brouillons enregistrés ici',
'queue.exportFilm': 'Exporter le film',
'queue.downloadFilm': 'Télécharger le film',
'queue.exporting': 'Export en cours…',
'queue.exportingTitle': 'Export du film',
'queue.exportingSub': 'Combinaison de {n} clips en une seule vidéo.',
'queue.exportQueued': 'Export mis en file',
'queue.exportedAgo': 'Exporté {ago}',
'queue.exportFailed': "Échec de l'export",
'queue.retryExport': "Réessayer l'export",
'queue.exportUnavailable': "Export pas encore disponible",
'queue.notExported': 'Non exporté',
'queue.notExportedTitle': 'Aucun export pour le moment',
'queue.slateSub': '{clips} clips · {time} · fondus de 0,5 s · volume homogénéisé',
'queue.staleBanner': "Clips modifiés depuis l'export",
'queue.exportDisabledTitle': 'Ajoutez au moins un clip à exporter',
'queue.chainDisabledReason': "Sélectionnez d'abord une scène ou un clip",
'queue.editInTimeline': 'Modifier dans la timeline',
'queue.inThisFilm': 'Dans ce film',
'queue.filmMeta': '{scenes} scènes · {clips} clips · {duration}',
'queue.reexport': 'Réexporter',
// --- Job / job drawer ---
'job.title': 'Tâche',
'job.status.generating': 'Génération',
'job.status.generatingPulse': 'Génération',
'job.status.queued': 'En file',
'job.status.running': 'En cours',
'job.status.done': 'Terminé',
'job.status.failed': 'Échec',
'job.cancelJob': 'Annuler la tâche',
'job.cancelFailed': "Impossible d'annuler la tâche",
'job.cancelled': 'Annulée',
'job.requeued': 'Remise en file',
'job.retryJob': 'Réessayer la tâche',
'job.retryFailed': 'Impossible de réessayer la tâche',
'job.exportFilm': 'Exporter le film',
'jobDrawer.title': 'Détails de la tâche',
'jobDrawer.historyAria': 'Historique des tâches',
'jobDrawer.noJobs': 'Aucune tâche pour le moment',
'jobDrawer.noPrompt': 'Aucun prompt pour cette tâche',
'jobDrawer.output': 'Résultat',
'jobDrawer.prompt': 'Prompt',
'jobDrawer.references': 'Références',
'jobDrawer.characterRef': 'Référence de personnage',
'jobDrawer.locationRef': 'Référence de lieu',
'jobDrawer.audioInput': 'Entrée audio',
'jobDrawer.videoInput': 'Entrée vidéo',
'jobDrawer.refImage': 'Image de référence',
'jobDrawer.currentClip': 'Clip actuel',
'jobDrawer.otherInputs': 'Autres entrées',
'jobDrawer.copy': 'Copier',
'jobDrawer.copied': 'Copié',
'jobDrawer.copySettings': 'Copier les paramètres',
'jobDrawer.applying': 'Application…',
'jobDrawer.applyToScene': 'Appliquer à la scène',
'jobDrawer.h3Hint': 'La sélection ci-dessus a été utilisée pour cette tâche.',
// --- Filmstrip ---
'filmstrip.title': 'Pellicule',
'filmstrip.clipTitle': '{scene} · plan {shot} · {time}',
'filmstrip.scene': 'Scène',
'filmstrip.sceneClips': '{n} clips',
'filmstrip.prev': 'Clip précédent',
'filmstrip.next': 'Clip suivant',
// --- Clip monitor / clip source ---
'clipMonitor.untitled': 'Clip sans titre',
'clipMonitor.id': 'ID du clip',
'clipMonitor.sceneId': 'ID de la scène',
'clipMonitor.generating': 'Génération…',
'clipMonitor.generationFailed': 'Échec de la génération',
'clipMonitor.queued': 'En file',
'clipMonitor.noRenderHint': "Ce clip n'a pas encore de rendu.",
'clipMonitor.downloadClip': 'Télécharger le clip',
'clipMonitor.videoUnavailable': 'Vidéo indisponible',
'clipMonitor.showDetails': 'Afficher les détails',
'clipMonitor.hideDetails': 'Masquer les détails',
'clipSource.title': 'Source du clip',
'clipSource.projectClips': 'Clips du projet',
'clipSource.noClips': 'Aucun clip disponible',
'clipSource.autoName': 'Auto',
'clipSource.autoDesc': 'Libellé automatique',
'clipSource.uploadName': 'Importer',
'clipSource.uploadDesc': 'Importer un fichier',
// --- Video edit workspace ---
'videoEdit.clipId': 'ID du clip',
'videoEdit.sceneId': 'ID de la scène',
'videoEdit.generateLabel': 'Générer',
'videoEdit.videoSource': 'Source vidéo',
'videoEdit.noVideoInputWf': "Ce workflow n'a pas d'entrée vidéo",
'videoEdit.noWf': 'Aucun workflow sélectionné',
'videoEdit.wfLink': 'Configurer les workflows dans les Paramètres',
'videoEdit.enableWfPre': 'Effectuer le rendu avec le workflow actif ?',
'videoEdit.enableWfPost': 'Il détermine le format de sortie.',
'videoEdit.assetHint': 'Choisissez la cible de génération',
'videoEdit.continueHint': 'Continuer avec le workflow sélectionné',
'videoEdit.viewPrompt': 'Voir le prompt',
'videoEdit.dockAria': 'Entrées de génération du clip',
// --- Shot brief ---
'shotBrief.copyTitle': 'Copier la description du plan',
'shotBrief.copied': 'Copié',
'shotBrief.copy': 'Copier',
'shotBrief.collapse': 'Réduire le brief du plan',
'shotBrief.expand': 'Développer le brief du plan',
'shotBrief.noDesc': 'Aucune description de plan — ce clip a hérité des valeurs par défaut de la scène.',
'shotBrief.notePre': "Ce clip n'a pas encore de description propre au plan — le texte ci-dessus est l'action complète de la scène. Utilisez",
'shotBrief.breakIntoShots': 'Découper en plans',
'shotBrief.notePost': "à l'étape Scénario pour le diviser en couverture.",
'shotBrief.dialogKey': 'Dialogue dans ce plan',
'shotBrief.characters': 'Personnages',
// --- Prompt preview modal ---
'promptPreview.title': 'Aperçu du prompt',
'promptPreview.generate': 'Générer',
'promptPreview.regenerate': 'Régénérer',
'promptPreview.resolving': 'Résolution du prompt…',
'promptPreview.saveDraft': 'Enregistrer le brouillon',
'promptPreview.draftSaved': 'Brouillon enregistré',
'promptPreview.promptEmpty': 'Rien à prévisualiser pour le moment',
'promptPreview.noClip': 'Aucun clip',
'promptPreview.noClipSelected': 'Aucun clip sélectionné',
'promptPreview.untitled': 'Sans titre',
'promptPreview.failedHint': "Échec de la résolution du prompt — affichage d'une solution de repli.",
'promptPreview.staleHint': 'La résolution est obsolète — renvoyez pour obtenir le prompt actuel.',
'promptPreview.fromDraftHint': 'Basé sur votre brouillon, pas sur le workflow actuel.',
'promptPreview.proseHint': 'Prompt en prose modifiable — les modifications restent locales.',
'promptPreview.h3Hint': 'Prompt construit à partir de la sélection ci-dessus.',
'promptPreview.criticTitle': 'Contrôle de continuité',
'promptPreview.h3Rewrite': 'Réécrit',
'promptPreview.editorAria': 'Éditeur de prompt',
'promptPreview.defaultWorkflow': 'par défaut',
'promptPreview.sceneMeta': 'Scène n° {index} · {heading}',
'promptPreview.shotMeta': 'Plan {label} · {heading}',
// --- Workflows (wf) ---
'wf.title': 'Workflows',
'wf.lead': 'Importez et enregistrez des workflows ComfyUI pour la génération.',
'wf.loadingWorkflows': 'Chargement des workflows',
'wf.noWorkflows': 'Aucun workflow enregistré',
'wf.noWorkflowsHint': 'Déposez un fichier JSON de workflow ci-dessous pour commencer.',
'wf.detectedInputs': 'Entrées détectées',
'wf.detectedOutputs': 'Sorties détectées',
'wf.inputs': 'Entrées',
'wf.outputs': 'Sorties',
'wf.inputsCount': '{n} entrées',
'wf.outputsCount': '{n} sorties',
'wf.kind': 'Type',
'wf.kindImage': 'Image',
'wf.kindVideo': 'Vidéo',
'wf.enable': 'Activer',
'wf.disable': 'Désactiver',
'wf.disabled': 'Désactivé',
'wf.stateEnabled': 'Activé',
'wf.stateDisabled': 'Désactivé',
'wf.enabledState': 'Activé',
'wf.hideIo': 'Masquer les entrées/sorties',
'wf.viewIo': 'Afficher les entrées/sorties',
'wf.dropHint': 'Déposez le JSON du workflow ici',
'wf.dropSub': 'ou cliquez pour parcourir',
'wf.namePlaceholder': 'Nom du workflow',
'wf.descPlaceholder': 'Brève description (facultatif)',
'wf.invalidJson': "Ce fichier n'est pas un JSON de workflow valide",
'wf.jsonLocked': 'Verrouillé par une tâche active',
'wf.jsonPreview': 'JSON du workflow',
'wf.reanalyze': 'Réanalyser',
'wf.saveToLibrary': 'Enregistrer dans la bibliothèque',
'wf.savedWorkflows': 'Workflows enregistrés',
'wf.savedToLibrary': 'Enregistré dans la bibliothèque',
'wf.saveFailed': "Impossible d'enregistrer le workflow",
'wf.updateFailed': 'Impossible de mettre à jour le workflow',
'wf.updated': 'Workflow mis à jour',
'wf.deleted': 'Workflow supprimé',
'wf.deleteFailed': 'Impossible de supprimer le workflow',
'wf.deleteTitle': 'Supprimer le workflow',
'wf.deleteMessage': 'Ce workflow et son JSON enregistré seront supprimés.',
'wf.analyzeRegister': 'Analyser et enregistrer',
'wf.countImage': '{n} images',
'wf.countVideo': '{n} vidéos',
'wf.countSaved': '{n} enregistrés',
'wf.profileH3': "Cas d'usage",
'wf.profileProse': 'Ce workflow génère {kind} à partir de {target}.',
'wf.promptFormat': 'Format du prompt',
'wf.noInputs': 'Aucune entrée détectée',
'wf.noInputsCached': 'Aucune entrée',
'wf.noOutputs': 'Aucune sortie détectée',
'wf.noOutputsCached': 'Aucune sortie',
// --- Comfy dynamic form (cdf) ---
'cdf.browse': 'Parcourir',
'cdf.chooseAsset': 'Choisir une ressource',
'cdf.clear': 'Effacer',
'cdf.clearAria': 'Effacer le champ',
'cdf.dropPre': 'Déposez un fichier',
'cdf.localPath': 'Chemin local',
'cdf.noAssets': 'Aucune ressource pour le moment',
'cdf.noInputs': 'Aucune entrée configurable',
'cdf.orChooseAsset': 'ou choisissez une ressource',
'cdf.required': 'obligatoire',
'cdf.requiredMsg': 'Ce champ est obligatoire',
'cdf.selectedPreviewAlt': 'Aperçu sélectionné',
'cdf.uploadedPreviewAlt': 'Aperçu importé',
'cdf.uploadFailed': "Échec de l'import",
'cdf.uploading': 'Import en cours…',
// --- Omni composer ---
'omni.advanced': 'Avancé',
'omni.assetType': 'Type de ressource',
'omni.choose': 'Choisir',
'omni.chooseReference': 'Choisir une référence',
'omni.clearSlot': "Vider l'emplacement",
'omni.decrease': 'Diminuer',
'omni.increase': 'Augmenter',
'omni.duration': 'Durée',
'omni.resolution': 'Résolution',
'omni.seed': 'Graine',
'omni.emptyCharacters': 'Aucun personnage pour le moment',
'omni.emptyLocations': 'Aucun lieu pour le moment',
'omni.emptyItems': 'Aucun objet pour le moment',
'omni.emptyShots': 'Aucun plan pour le moment',
'omni.emptyClips': 'Aucun clip pour le moment',
'omni.emptyUploads': 'Aucun import pour le moment',
'omni.emptyUploadsNew': 'Aucun import pour le moment',
'omni.generate': 'Générer',
'omni.generateAria': 'Générer',
'omni.negativeAria': 'Prompt négatif',
'omni.negativePlaceholder': 'Prompt négatif…',
'omni.negativeToggle': 'Prompt négatif',
'omni.noMatches': 'Aucun résultat',
'omni.noPromptRole': "Ce workflow n'a pas d'entrée de prompt",
'omni.promptAria': 'Prompt',
'omni.promptPlaceholder': "Décrivez l'image…",
'omni.queuing': 'Mise en file…',
'omni.removeSlot': 'Retirer',
'omni.required': 'Obligatoire',
'omni.roleAudio': 'Audio',
'omni.roleCharacter': 'Personnage',
'omni.roleLocation': 'Lieu',
'omni.roleVideo': 'Vidéo',
'omni.searchAssets': 'Rechercher des ressources',
'omni.searchIn': 'Rechercher dans',
'omni.thisList': 'cette liste',
'omni.uploadNew': 'Importer',
// --- Attach to project dialog ---
'attach.panelAria': 'Joindre au projet',
'attach.title': 'Joindre au projet',
'attach.addToProject': 'Ajouter au projet',
'attach.noScenes': 'Aucune scène pour le moment',
'attach.noCharacters': 'Aucun personnage pour le moment',
'attach.noLocations': 'Aucun lieu pour le moment',
'attach.pickProject': 'Choisir un projet',
'attach.selectProject': 'Sélectionner un projet',
'attach.selectScene': 'Sélectionner une scène',
'attach.selectCharacter': 'Sélectionner un personnage',
'attach.selectLocation': 'Sélectionner un lieu',
'attach.pickCharacter': 'Choisir un personnage',
'attach.pickLocation': 'Choisir un lieu',
'attach.pickScene': 'Choisir une scène',
'attach.projectField': 'Projet',
'attach.sceneField': 'Scène',
'attach.characterField': 'Personnage',
'attach.locationField': 'Lieu',
'attach.nameField': 'Nom',
'attach.asCharacterSheet': 'comme feuille de personnage',
'attach.asItem': 'comme objet',
'attach.asLocation': 'comme lieu',
'attach.addAs': 'Ajouter comme',
'attach.addBtn': 'Ajouter',
'attach.added': 'Joint',
'attach.addedTo': 'Ajouté à « {title} »',
'attach.failed': 'Impossible de joindre',
'attach.dismiss': 'Ignorer',
'attach.viewInProject': 'Voir dans le projet',
'attach.newItem': 'Nouvel objet',
'attach.newItemHint': 'Créer un objet à partir de ce média.',
'attach.newItemPlaceholder': "Nom de l'objet",
'attach.projectFallback': 'Projet sans titre',
'attach.scene': 'Scène',
// --- Asset Library ---
'library.selectAll': 'Tout sélectionner',
'library.deselectAll': 'Tout désélectionner',
'library.itemCount': '{count} élément(s)',
'library.loadError': 'Échec du chargement de la bibliothèque',
'library.subtitle': 'Les ressources générées au même endroit : prévisualisez, filtrez et supprimez les images et vidéos sans projet',
'library.deleteSelected': 'Supprimer ({count})',
'library.addToProject': 'Ajouter au projet',
'library.filterLabel': 'Filtrer par type',
'library.filterAll': 'Tout',
'library.filterImage': 'Images',
'library.filterVideo': 'Vidéos',
'library.loadMore': 'Charger plus ({count} restants)',
'library.loadingMore': 'Chargement…',
'library.confirmDelete': 'Supprimer {count} fichier(s) sélectionné(s) de la bibliothèque d’assets ? Cette action est irréversible.',
'library.deleted': '{count} fichier(s) supprimé(s)',
'library.deletedPartial': '{kept} fichier(s) conservé(s) – encore référencé(s) par des données du projet',
'library.deleteFailed': 'Échec de la suppression',
'library.emptyTitle': 'La bibliothèque d’assets est vide',
'library.emptyBody': 'Les images et vidéos non liées à un projet arrivent ici – via un import sur un canvas ou une génération dans un chat sandbox.',
'library.emptyFilterTitle': 'Aucun élément {kind} dans la bibliothèque',
'library.emptyFilterBody': 'Rien ne correspond à ce filtre pour l’instant – essayez « Tout » ou générez quelque chose de nouveau.',
// --- Settings ---
'settings.pageSub': 'File de génération, exécution des agents et chemins · LLM, connexions ComfyUI et Skills ont leur propre page',
'settings.secQueue': 'File et génération',
'settings.secQueueBlurb': 'Parallélisme, relances, interrogation et essai',
'settings.secAgent': 'Exécution des agents',
'settings.secAgentBlurb': 'Étapes, contexte, durcissement des prompts et shell',
'settings.secStorage': 'Chemins de stockage',
'settings.secStorageBlurb': 'Dossiers de données, ressources et espace de travail',
'settings.elsewhere': 'Géré ailleurs',
'settings.linkModelsBlurb': 'LLM et modèle par défaut de chaque agent',
'settings.linkConnectionsBlurb': 'Adresses, tests de connexion et bibliothèque de workflows',
'settings.linkAgentsBlurb': 'Skills et discussions dédiées des cinq agents',
'settings.dryRunTitle': 'Mode essai',
'settings.dryRunHint': 'Activé : ComfyUI n’est pas appelé et les tâches renvoient des images / vidéos factices ; désactivez pour générer réellement.',
'settings.agentRunSection': 'Exécution des agents',
'settings.agentRunLead': 'Limite les étapes d’outils par exécution et l’historique transmis.',
'settings.rangeHint': 'Plage {min}–{max}',
'settings.loadFailed': 'Impossible de charger les réglages : vérifiez que le serveur tourne',
'skillName.character-consistency': 'Cohérence des personnages',
'skillName.h3-video-prompt-enhancer': 'Amélioration de prompts vidéo H3',
'skillName.scene-to-video': 'Scène en vidéo',
'skillName.shot-composer-blockout': 'Pré-cadrage du plan',
'settings.loading': 'Chargement des paramètres',
'settings.allSaved': 'Toutes les modifications sont enregistrées',
'settings.unsaved': 'Modifications non enregistrées',
'settings.saveChanges': 'Enregistrer les modifications',
'settings.discard': 'Abandonner',
'settings.saved': 'Enregistré',
'settings.saveFailed': "Impossible d'enregistrer les paramètres",
'settings.savedDryRun': 'Exécution à blanc enregistrée',
'settings.current': 'Actuel',
'settings.useThis': 'Utiliser',
'settings.useActiveLlm': 'Actuellement actif',
'settings.llmSection': 'LLM',
'settings.llmLead': "Configurez les modèles de langage utilisés par l'agent.",
'settings.addLlm': 'Ajouter un LLM',
'settings.addAtLeastOneLlm': 'Ajoutez au moins un LLM.',
'settings.llmNamePlaceholder': 'Mon LLM',
'settings.llmDefaultName': 'Modèle générique',
'settings.newLlmDefault': 'Nouveau LLM',
'settings.model': 'Modèle',
'settings.baseUrl': 'URL de base',
'settings.apiKey': 'Clé API',
'settings.apiKeyOptional': 'Facultatif',
'settings.apiKeyHint': "Certains fournisseurs n'exigent aucune clé.",
'settings.apiKeySaved': 'Clé enregistrée',
'settings.requiredName': 'Le nom est obligatoire',
'settings.requiredModel': 'Le modèle est obligatoire',
'settings.requiredBaseUrl': "L'URL de base est obligatoire",
'settings.invalidValue': 'Valeur invalide',
'settings.invalidField': 'Invalide',
'settings.remove': 'Retirer',
'settings.removeLlmTitle': 'Retirer le LLM',
'settings.name': 'Nom',
'settings.active': 'Actif',
'settings.testLlm': 'Tester la connexion',
'settings.llmTestOk': 'Connexion réussie ({ms} ms)',
'settings.llmTestFail': 'Échec de connexion : {detail}',
'settings.llmTestAuth': 'Clé refusée ({detail})',
'settings.llmTestTimeout': 'Aucune réponse sous 15 s',
'settings.llmTestConnect': 'Serveur injoignable ({detail})',
'settings.agentModelsSection': 'Modèle agent',
'settings.agentModelsLead': "Modèle utilisé pour la rédaction de l'histoire et les tâches de l'agent.",
'settings.agentMaxStepsField': 'Étapes max.',
'settings.agentMaxStepsHint': "Limite d'appels d'outils par exécution de l'agent.",
'settings.queueSection': "File d'attente",
'settings.queueLead': 'Parallélisme et délais des tâches de génération et des appels d’outils de l’agent.',
'settings.concurrencyField': 'Tâches simultanées',
'settings.pollIntervalField': 'Intervalle de vérification (s)',
'settings.pollTimeoutField': 'Délai de la tâche (s)',
'settings.pollTimeoutHint': 'Durée maximale d’un job ComfyUI ou d’un appel d’outil de l’agent. 0 attend la fin.',
'settings.maxRetriesField': 'Tentatives max.',
'settings.maxError': 'Trop élevé',
'settings.minError': 'Trop faible',
'settings.notNumber': 'Doit être un nombre',
'settings.comfySection': 'ComfyUI',
'settings.comfyLead': "Où ComfyUI s'exécute.",
'settings.comfyHint': 'Doit être accessible depuis cette machine.',
'settings.storageSection': 'Chemins système',
'settings.storageLead': "Où les fichiers sont stockés et où l'agent peut travailler.",
'settings.storageCalloutStrong': 'Changer le répertoire de données',
'settings.storageCalloutBody': "déplace les ressources. Les chemins existants continuent de fonctionner jusqu'à la définition ici.",
'settings.dataDir': 'Répertoire de données',
'settings.assetsDir': 'Répertoire des ressources',
'settings.workspaceDir': "Espace de travail de l'agent",
'settings.workspaceDirHint':
"Dossier isolé où le shell de l'agent (run_command) peut travailler. Vide = DATA_DIR/workspace. L'agent ne peut rien toucher en dehors.",
'settings.shellSection': "Shell de l'agent",
'settings.shellLead': "Permet à l'agent d'exécuter des outils en ligne de commande dans son espace de travail.",
'settings.shellCalloutStrong': 'Sur activation :',
'settings.shellCalloutBody':
"les commandes s'exécutent sur cette machine, isolées dans l'espace de travail de l'agent. Les fichiers sensibles (config, base de données, identifiants) sont toujours refusés ; tout ce qui n'est pas en lecture seule vous est demandé avant.",
'settings.shellLabel': "Activer le shell de l'agent (run_command)",
'settings.shellHint':
'Désactivé par défaut. Une fois activé, l\'agent peut lancer librement des commandes d\'inspection (ffprobe) ; les commandes modifiantes ne passent qu\'après approbation via une carte de question scope="shell".',
'settings.historyBudgetSection': 'Budget d\'historique du contexte',
'settings.historyBudgetLead':
'Limite la quantité d\'historique de conversation rejouée à chaque requête de l\'agent, afin que les longues sessions ne débordent jamais de la fenêtre de contexte du modèle.',
'settings.historyBudgetField': 'Budget d\'historique (caractères)',
'settings.historyBudgetHint':
'≈4 caractères par token. Les tours les plus anciens sont d\'abord retirés ; les préréglages ci-dessous sont de bons points de départ.',
'settings.historyBudgetSmall': 'Petit · 60k',
'settings.historyBudgetMedium': 'Moyen · 120k',
'settings.historyBudgetLarge': 'Grand · 400k',
'settings.hardeningSection': 'Renforcement du prompt',
'settings.hardeningLead': 'Règles ajoutées au début des prompts de génération.',
'settings.hardeningHint': 'Sert à imposer des contraintes négatives ou des garde-fous de style.',
'settings.hardeningPlaceholder': 'Pas de violence, pas de gore, pas de contenu explicite.',
'settings.hardeningRulesLabel': 'Règles de renforcement',
'settings.hardeningCalloutStrong': "Le renforcement s'applique",
'settings.hardeningCalloutBody': 'à chaque prompt envoyé dans le pipeline.',
'settings.leaveTitle': 'Quitter sans enregistrer ?',
'settings.leaveMessage': 'Vous avez des modifications non enregistrées qui seront perdues.',
'settings.leaveConfirm': 'Quitter',
'settings.dryRunLabel': 'Valider uniquement (exécution à blanc)',
// --- Shot editor ---
'shot.scene': 'Scène',
'shot.hint': 'Ajoutez des objets, cadrez le plan, puis capturez.',
'shot.addObject': 'Ajouter un objet',
'shot.clearScene': 'Vider la scène',
'shot.visibility': 'Basculer la visibilité',
'shot.lock': 'Basculer le verrouillage',
'shot.emptyScene': 'La scène est vide',
'shot.objName.male': 'Homme',
'shot.objName.female': 'Femme',
'shot.objName.child': 'Enfant',
'shot.objName.cube': 'Cube',
'shot.objName.plane': 'Plan',
'shot.objName.cylinder': 'Cylindre',
'shot.objName.sphere': 'Sphère',
'shot.objName.capsule': 'Capsule',
'shot.objName.cone': 'Cône',
'shot.objName.torus': 'Tore',
'shot.objName.camera': 'Caméra',
'shot.selectObject': 'Sélectionner un objet',
'shot.selectObjectPose': 'Sélectionner un objet et le mettre en pose',
'shot.fov': 'Champ de vision',
'shot.transform': 'Transformation',
'shot.pose': 'Pose',
'shot.shotSection': 'Plan',
'shot.shotSize': 'Taille du plan',
'shot.angle': 'Angle de caméra',
'shot.elevation': 'Élévation',
'shot.composition': 'Composition',
'shot.center': 'Centre',
'shot.captureRef': 'Capture de référence',
'shot.railExpand': 'Développer la barre des sessions',
'shot.railCollapse': 'Réduire la barre des sessions',
'shot.railOpen': 'Ouvrir {title}',
'shot.railNoScenes': 'Aucune scène pour le moment',
'shot.railDeleteScene': 'Supprimer la scène',
'shot.newScene': 'Nouvelle scène',
'shot.captures': '{count} captures',
'shot.videoBadge': 'Vidéo',
'shot.captureAlt': 'Capture de scène',
'shot.noCaptures': 'Aucune capture pour le moment',
'shot.timelinePlay': 'Lecture',
'shot.timelinePause': 'Pause',
'shot.timelinePlayhead': 'Tête de lecture',
'shot.camKeyframe': 'Caméra à {time} s',
'shot.objKeyframe': '{name} à {time} s',
'shot.keyframeCamAdd': 'Ajouter une image clé de caméra',
'shot.keyframeCamRemove': "Supprimer l'image clé de caméra",
'shot.keyframeObjAdd': 'Ajouter une image clé pour {name}',
'shot.keyframeObjDelete': "Supprimer l'image clé",
'shot.keyframeObjSelectFirst': "Sélectionnez d'abord un objet",
'shot.exportHint': 'Objets de scène ou au moins 2 images clés de caméra requis (captures facultatives).',
'shot.exportHintNeedBeats': 'Ajoutez des objets de scène ou ≥2 images clés de caméra pour exporter. Captures facultatives.',
'shot.exportTitle': 'Exporter la timeline',
'shot.exportImage': 'Exporter l\'image',
'shot.exportVideo': 'Exporter la vidéo',
'shot.viewportTools': 'Outils',
'shot.toolSelect': 'Sélection',
'shot.toolSelectTitle': 'Outil de sélection',
'shot.toolMove': 'Déplacement',
'shot.toolMoveTitle': 'Outil de déplacement',
'shot.toolRotate': 'Rotation',
'shot.toolRotateTitle': 'Outil de rotation',
'shot.toolScale': 'Échelle',
'shot.toolScaleTitle': "Outil d'échelle",
'shot.toolPose': 'Pose',
'shot.toolPoseTitle': 'Outil de pose',
'shot.toolPoseDisabled': 'Sélectionnez un objet pour le mettre en pose',
'shot.undoTitle': 'Annuler',
'shot.redoTitle': 'Rétablir',
'shot.gridTitle': 'Basculer la grille',
'shot.grid': 'Grille',
'shot.compositionTitle': 'Basculer les guides de composition',
'shot.captureTitle': 'Capturer une image',
'shot.capture': 'Capturer',
'shot.errBlob': "Impossible de lire l'image capturée",
'shot.errRecorder': "Impossible de démarrer l'enregistreur",
'shot.errNoData': 'Aucune donnée de scène à exporter',
// Models settings page (spec-v2 §9)
'models.title': 'Modèles',
'models.subtitle': 'Ajoutez des LLM personnalisés pour vos agents · la phase 1 ne couvre que les LLM ; les modèles image / vidéo arriveront ensuite',
'models.statusCount': '{n} modèles · {m} disponibles',
'models.add': 'Ajouter un modèle',
'models.tabLlm': 'Modèles de langage',
'models.tabImage': "Modèles d'image",
'models.tabVideo': 'Modèles vidéo',
'models.comingSoon': 'À venir',
'models.empty': 'Aucun modèle pour l’instant — cliquez sur « Ajouter un modèle » en haut à droite pour connecter votre premier LLM',
'models.typeLocal': 'Local',
'models.typeLan': 'LAN',
'models.typeCloud': 'Cloud',
'models.defaultBadge': 'Par défaut',
'models.setDefault': 'Définir par défaut',
'models.defaultSetToast': 'Modèle par défaut des agents défini',
'models.test': 'Tester la connexion',
'models.testing': 'Test en cours…',
'models.edit': 'Modifier',
'models.delete': 'Supprimer',
'models.statusUntested': 'Non testé',
'models.statusConnected': 'Connecté',
'models.statusFailed': 'Échec de connexion',
'models.latency': 'latence {ms}ms',
'models.agentsUsing': 'utilisé par {n} agents',
'models.lastTestAt': 'dernier test {time}',
'models.consecutiveFails': '{n} échecs consécutifs',
'models.cloudPaused': 'Appels cloud suspendus',
'models.formTitleAdd': 'Ajouter un modèle',
'models.formTitleEdit': 'Modifier le modèle',
'models.formClose': 'Fermer',
'models.fName': 'Nom',
'models.fNamePh': 'Nommez le modèle, ex. DeepSeek officiel',
'models.fApiType': 'Type d’API',
'models.apiOpenai': 'Compatible OpenAI',
'models.apiAnthropic': 'Anthropic',
'models.apiOther': 'Autre',
'models.apiTypeHelp': 'La phase 1 ne prend en charge que les API compatibles OpenAI ; les autres protocoles arriveront avec les modèles image / vidéo',
'models.fBaseUrl': 'URL de base',
'models.baseUrlHelp': 'Avec protocole et port, ex. http://192.168.200.18:11434/v1',
'models.fModel': 'Nom du modèle',
'models.modelHelp': 'Utilisez l’identifiant de modèle fourni par votre prestataire',
'models.fApiKey': 'Clé API',
'models.keyNoEcho': 'jamais affichée',
'models.keyHelp': 'Stockée uniquement sur ce serveur ; la clé complète n’apparaît jamais dans l’interface',
'models.keyKeepHint': 'Clé enregistrée — laissez vide pour la conserver',
'models.fTimeout': 'Délai d’attente',
'models.timeoutSec': '{n}s',
'models.testOk': '✓ Test réussi · {ms}ms · {model} disponible',
'models.testFail': '✕ Échec du test · {reason}',
'models.needTest': 'Enregistrement possible après un test réussi',
'models.testBtn': 'Test connection',
'models.save': 'Enregistrer le modèle',
'models.errName': 'Veuillez nommer le modèle',
'models.errUrl': 'URL invalide — protocole et chemin requis, ex. https://api.deepseek.com/v1',
'models.errModel': 'Saisissez le nom du modèle fourni par votre prestataire',
'models.errKey': 'Saisissez la clé API',
'models.failTimeout': 'Délai dépassé ({sec}s sans réponse) : le serveur n’atteint pas cette adresse — vérifiez adresse, port et pare-feu',
'models.failAuth': 'Échec d’authentification (401) : vérifiez que la clé API est correcte et non expirée ; avec les agrégateurs, confirmez que le modèle est activé',
'models.failNotFound': 'Joignable mais modèle introuvable (404) : vérifiez l’orthographe du nom',
'models.failNotOpenai': 'Joignable mais non reconnue comme API compatible OpenAI — le chemin doit se terminer par /v1',
'models.failConnect': 'Le serveur ne peut pas se connecter à cette adresse — vérifiez adresse et port',
'models.failHttp': 'Test failed (HTTP {status})',
'models.delTitle': 'Supprimer le modèle',
'models.delConfirmUsed': '{n} agents utilisent ce modèle ; après suppression ils reviendront au modèle par défaut. Supprimer ?',
'models.delConfirmFree': 'Supprimer ce modèle ? Action irréversible.',
'models.delDefaultHint': 'Ce modèle est celui par défaut — choisissez d’abord un autre défaut',
'models.agentsTitle': 'Modèles par défaut des agents',
'models.agentsHint': 'Appliqué aux nouvelles sessions · réglage par agent sur la page Agents',
'models.agentDefault': 'Par défaut',
'models.agentStory': 'Scénario',
'models.agentStyle': 'Direction visuelle',
'models.agentScript': 'Storyboards',
'models.agentAssets': 'Bibliothèque d’assets',
'models.agentVideo': 'Plans de tournage',
'models.unavailable': '(indisponible)',
'models.noticeStrong': 'La connectivité est mesurée depuis le serveur du workbench :',
'models.noticeBody': 'une URL qui s’ouvre dans votre navigateur n’est pas forcément accessible au serveur ; les tests de connexion et les requêtes sont faits par le serveur. Les clés API restent sur le serveur et ne sont jamais affichées.',
'models.saved': 'Modèle enregistré',
'models.deleted': 'Modèle supprimé',
'models.assignSaved': 'Modèles des agents mis à jour',
'models.saveFailed': 'Échec de l’enregistrement : {detail}',
'models.loading': 'Chargement…',
'models.loadFailed': 'Impossible de charger les paramètres',
'models.idleFormHint': 'Cliquez « Modifier » sur une carte ou « Ajouter un modèle » ci-dessus',
// --- A shell + projects overview (HEL-608) ---
'shell.brand': 'Atelier Cinéma',
'shell.brandMark': 'A',
'shell.brandHome': 'Retour à l\'aperçu des projets',
'shell.navAria': 'Navigation principale',
'shell.navProjects': 'Projets',
'shell.navWorkbench': 'Atelier',
'shell.navImage': 'Génération d\'image',
'shell.navVideo': 'Génération vidéo',
'shell.navTasks': 'Tâches',
'shell.navAgents': 'Agents',
'shell.navConnections': 'Connexions ComfyUI',
'shell.navModels': 'Modèles',
'shell.navLibrary': 'Bibliothèque d’assets',
'shell.navSettings': 'Réglages',
'shell.comfy_ok': '{name} connecté',
'shell.comfy_fail': '{name} injoignable',
'shell.comfy_testing': 'Test de {name}…',
'shell.comfyUnset': 'ComfyUI · non configuré',
'shell.scopeHint': 'Changer de projet',
'shell.scopeAll': 'Tous les projets',
'shell.scopeAllList': 'Liste des projets',
'shell.scopeRecent': 'Projets récents',
'shell.scopeLoadFailed': 'Impossible de charger les projets',
'shell.scopeEmpty': 'Aucun projet — en créer un',
'shell.scopeStage': '{n}/5 validées',
'shell.queueRunning': '{n} en cours',
'shell.queueQueued': '{n} en file',
'shell.queueIdle': 'File libre',
'shell.queueActive': '{n} actifs',
'shell.trayTitle': 'Plateau des tâches',
'shell.trayRecent': 'Tâches récentes · cliquer pour tout voir',
'shell.trayEmpty': 'Aucune tâche de génération',
'shell.trayAll': 'Voir toutes les tâches',
'shell.searchTitle': 'Rechercher pages et projets',
'shell.searchPlaceholder': 'Rechercher pages, projets',
'shell.searchShortcut': 'Rechercher (Ctrl/⌘ + K)',
'shell.searchEmpty': 'Aucune page ni projet ne correspond à « {q} »',
'shell.searchGroupPages': 'Pages',
'shell.searchGroupProjects': 'Projets · ouvrir l’atelier',
'shell.searchHintMove': 'choisir',
'shell.searchHintOpen': 'ouvrir',
'shell.searchHintClose': 'fermer',
'shell.reduceMotion': 'Réduire les animations',
'shell.reduceHint': 'Coupe déplacements, zooms et halos ; garde seulement de courts fondus',
'shell.reduceSystem': 'Réglage système « Réduire les animations » appliqué',
'shell.tabAria': 'Navigation principale (étroite)',
'shell.tabProjects': 'Projets',
'shell.tabCreate': 'Créer',
'shell.tabGenerate': 'Générer',
'shell.tabMore': 'Plus',
'shell.morePages': 'Autres pages',
'shell.moreTools': 'Outils',
'home.title': 'Aperçu des projets',
'home.subtitle': 'Gérez vos projets — commencez avec une idée ou un scénario prêt.',
'home.projectCount': '{n} projets · {m} en cours',
'home.startIdea': 'Commencer avec une idée',
'home.importScript': 'Importer un scénario',
'home.entryIdeaTitle': 'Commencer avec une idée',
'home.entryIdeaBody': 'Décrivez une idée ; les agents la mènent étape par étape à travers l\'histoire, le storyboard et les plans.',
'home.entryScriptTitle': 'Importer un scénario',
'home.entryScriptBody': 'Vous avez déjà un scénario ? Collez-le, créez le projet et l\'agent scénario le découpe en scènes ordonnées.',
'home.ideaPlaceholder': 'Un petit port pluvieux où le gardien de phare découvre…',
'home.scriptField': 'Scénario complet',
'home.scriptPlaceholder': 'Collez ici le scénario complet…',
'home.scriptHint': 'Après création, la page Agents s\'ouvre et l\'agent scénario transforme le texte en scènes ordonnées.',
'home.errTitle': 'Donnez un titre au projet',
'home.errScript': 'Collez le scénario complet',
'home.myProjects': 'Mes projets',
'home.myProjectsHint': 'Cliquez sur un projet pour continuer',
'home.emptyProjects': 'Aucun projet pour le moment. Créez le premier avec « Commencer avec une idée » ou « Importer un scénario ».',
'home.noIdea': 'Pas encore de description',
'home.statScenes': '{n} scènes',
'home.statCharacters': '{n} personnages',
'home.statAssets': 'ressources {ready}/{total}',
'home.statusDraft': 'Brouillon',
'home.statusProgress': 'En cours',
'home.statusDone': 'Terminé',
'home.tasksTitle': 'Tâches',
'home.activeJobs': '{n} actives',
'home.emptyJobs': 'Aucune tâche de génération',
'home.emptyJobsSub': 'Les tâches lancées depuis un projet ou l\'atelier s\'afficheront ici.',
'home.tasksNote': 'L\'historique complet et les filtres se trouvent sur la page Tâches (navigation → 生成任务).',
'home.kindImage': 'image',
'home.kindVideo': 'vidéo',
'home.kindExport': 'film',
'home.jobDone': 'terminée',
'home.jobRunning': 'en cours',
'home.jobQueued': 'en attente',
'home.jobFailed': 'échouée',
'home.jobRequeued': 'Tâche remise en file',
'home.jobRetryFailed': 'Impossible de remettre la tâche en file',
'home.jobProject': 'Projet #{id}',
// --- ComfyUI connections page (a6, HEL-611) ---
'settings.comfyMultiHint': 'Les adresses ComfyUI prennent désormais en charge plusieurs connexions (local / LAN / cloud), associables par workflow.',
'settings.comfyGoto': 'Gérer dans « Connexions ComfyUI » →',
'conn.title': 'Connexions ComfyUI',
'conn.subtitle': 'Enregistrez des adresses API ComfyUI locales, LAN ou cloud · la connectivité est testée par le serveur',
'conn.statusCount': '{n} connexions · {m} réussies',
'conn.add': 'Ajouter une connexion',
'conn.loading': 'Chargement des connexions…',
'conn.loadFailed': 'Échec du chargement des connexions',
'conn.empty': 'Aucune connexion ComfyUI pour l\'instant — ajoutez la première adresse via « Ajouter une connexion ».',
'conn.targetsTitle': 'Cible des tâches',
'conn.targetImage': 'Image autonome',
'conn.targetVideo': 'Vidéo autonome',
'conn.targetFlow': 'Tâches du flux créatif',
'conn.targetChange': 'Modifier',
'conn.targetMixed': '{n} connexions',
'conn.targetNote': 'Les tâches suivent la liaison de chaque workflow ; sans liaison, la connexion par défaut est utilisée. Modifiez les liaisons dans la bibliothèque — les pages image / vidéo peuvent aussi changer avant génération.',
'conn.defaultBadge': 'Par défaut',
'conn.test': 'Tester la connexion',
'conn.testing': 'Test…',
'conn.edit': 'Modifier',
'conn.delete': 'Supprimer',
'conn.setDefault': 'Définir par défaut',
'conn.delDefaultHint': 'La connexion par défaut ne peut pas être supprimée ; choisissez-en une autre d\'abord',
'conn.delTitle': 'Supprimer la connexion',
'conn.delConfirmUsed': 'Les workflows liés à cette connexion reviendront à la connexion par défaut. Les instantanés existants sont conservés. Supprimer « {name} » ?',
'conn.delConfirmFree': 'Supprimer la connexion « {name} » ?',
'conn.statusUntested': 'Non testée',
'conn.statusConnected': 'Test réussi',
'conn.statusFailed': 'Échec du test',
'conn.latency': '{ms} ms de latence',
'conn.version': 'version {v}',
'conn.lastTestAt': 'dernier test {time}',
'conn.boundWorkflows': '{n} workflows liés',
'conn.tokenSaved': 'Jeton enregistré — laissez vide pour le conserver',
'conn.saved': 'Connexion enregistrée',
'conn.deleted': 'Connexion supprimée',
'conn.saveFailed': 'Échec de l\'enregistrement : {detail}',
'conn.defaultSetToast': 'Définie comme connexion par défaut',
'conn.formTitleAdd': 'Ajouter une connexion ComfyUI',
'conn.formTitleEdit': 'Modifier la connexion ComfyUI',
'conn.formClose': 'Fermer',
'conn.fName': 'Nom',
'conn.fNamePh': 'ex. ComfyUI local / machine de rendu',
'conn.fBaseUrl': 'Adresse API',
'conn.fBaseUrlPh': 'http://192.168.200.18:8188',
'conn.baseUrlHelp': 'Adresse HTTP de l\'API ComfyUI (port 8188 par défaut) ; même format pour local, LAN et cloud.',
'conn.fAuth': 'Authentification',
'conn.authNone': 'Aucune',
'conn.authBearer': 'Jeton Bearer',
'conn.authHeader': 'En-tête personnalisé',
'conn.authHelp': 'Nécessaire seulement si le point de terminaison est derrière une auth (clé de reverse proxy, etc.).',
'conn.fToken': 'Jeton d\'accès',
'conn.fHeaderName': 'Nom d\'en-tête',
'conn.fHeaderNamePh': 'X-Api-Key',
'conn.keyNoEcho': 'stocké côté serveur uniquement, jamais renvoyé',
'conn.keyHelp': 'Le jeton reste dans le fichier de configuration du serveur et n\'atteint jamais le navigateur.',
'conn.fNotes': 'Notes',
'conn.fNotesPh': 'facultatif : ce que fait la machine, VRAM…',
'conn.errName': 'Le nom est requis',
'conn.errUrl': 'L\'adresse doit être une URL http:// ou https:// valide',
'conn.errHeaderName': 'L\'en-tête personnalisé exige un nom',
'conn.testOk': '✓ Test réussi · {ms} ms · ComfyUI {v}',
'conn.testFail': '✕ {reason}',
'conn.needTest': 'Réussissez le test avant d\'enregistrer',
'conn.testBtn': 'Tester',
'conn.save': 'Enregistrer',
'conn.noticeStrong': 'C\'est le serveur qui décide de la connectivité : ',
'conn.noticeBody': 'Une adresse qui s\'ouvre dans le navigateur ne garantit pas que la génération fonctionne ; tests et requêtes sont faits par le serveur. Les jetons restent côté serveur.',
'conn.wfTitle': 'Bibliothèque de workflows',
'conn.wfHint': 'Importez le JSON au format API ComfyUI, classez-le image/vidéo, liez-le à une connexion',
'conn.wfEmpty': 'Aucun workflow importé. Activez le mode développeur dans ComfyUI, exportez en « format API » puis collez-le ici.',
'conn.wfCount': '{n} workflows · {m} image · {k} vidéo',
'conn.wfKindImage': 'Image',
'conn.wfKindVideo': 'Vidéo',
'conn.wfConnection': 'Connexion liée',
'conn.wfConnectionActive': 'Suit la connexion par défaut',
'conn.wfParams': '{n} paramètres remplissables',
'conn.wfImport': 'Importer le workflow',
'conn.wfImporting': 'Import…',
'conn.wfNodes': '{n} nœuds',
'conn.wfImportedN': 'Workflow importé : {n} paramètres détectés',
'conn.wfImportedNoParams': 'Workflow importé, mais aucun paramètre détecté : il sera exécuté avec ses réglages intégrés',
'conn.wfImportFailed': 'Échec de l\'import : {detail}',
'conn.wfImportTitle': 'Importer un workflow ComfyUI (JSON format API)',
'conn.wfImportHint': 'Collez ou choisissez un fichier ; le nom est requis, le type décide de la fenêtre image ou vidéo.',
'conn.wfJsonInvalid': 'JSON invalide au format API (attendu : objet id de nœud → {{…class_type…}})',
'conn.wfJsonPh': 'Collez ici le JSON format API ComfyUI ou choisissez un fichier',
'conn.wfDeleted': 'Workflow supprimé',
'conn.wfImportedBroken': 'Imported, but the workflow file is incomplete and must be re-exported before generating: {detail}',
'conn.wfBrokenBadge': 'Incomplete file — cannot generate',
// --- Five usages & import confirmation (HEL-636) ---
'usage.text2image': 'Text → Image',
'usage.image2image': 'Image → Image',
'usage.text2video': 'Text → Video',
'usage.image2video': 'Image → Video',
'usage.ref2video': 'Reference → Video',
'usage.pending': 'Usage pending',
'wfRole.image': 'Input image',
'wfRole.first_frame': 'First frame',
'wfRole.last_frame': 'Last frame',
'wfRole.reference_image': 'Reference',
'wfRole.mask': 'Mask',
'conn.wfImportAction': 'Import workflow',
'conn.wfConfirmTitle': 'Confirm detection',
'conn.wfStepAnalyze': 'Paste & analyze',
'conn.wfStepConfirm': 'Confirm & save',
'conn.wfChooseFile': 'Choose file',
'conn.wfAnalyze': 'Analyze',
'conn.wfAnalyzing': 'Analyzing…',
'conn.wfConfirmHint': 'Review the evidence, output nodes and image slots; correct the usage or slot roles before saving.',
'conn.wfUsageLabel': 'Usage',
'conn.wfUsageAuto': 'Auto-detected: {usage}',
'conn.wfUsageNeedPick': 'Pick manually',
'conn.wfPickUsage': 'Choose a usage first',
'conn.wfSlotsLabel': 'Image slots',
'conn.wfSlotsHint': 'Roles are inferred from wiring; override them (input image / first / last frame / reference / mask) and the manual choice sticks.',
'conn.wfBack': 'Back',
'conn.wfConfirmSave': 'Confirm & save',
'conn.wfImportedWithUsage': 'Saved as “{usage}” with {n} fillable parameters',
'conn.wfPendingCount': '{n} pending',
'conn.wfConfirmed': 'Usage confirmed: {usage} — the workflow can generate now',
'conn.wfSourceUser': 'Usage set manually; re-analysis will not overwrite it',
'conn.wfSourceAuto': 'Usage auto-detected',
'conn.wfDisabledBadge': 'Disabled',
'conn.wfConfirmAria': 'Confirm workflow usage',
'conn.wfOutputLabel': 'Nœuds de sortie',
'conn.wfOutputNeedPick': 'Nœuds de sortie personnalisés non reconnus — à désigner',
'conn.wfOutputHint': 'Cochez les nœuds qui produisent réellement les résultats et choisissez leur type de média ; la génération ne collecte les images/vidéos que sur ces nœuds.',
'conn.wfOutputPick': 'Cochez au moins un nœud de sortie',
'conn.wfOutputKindAria': 'Type de média du nœud de sortie',
'conn.wfOutputPendingBadge': 'Sortie à définir',
'conn.wfOutputNeedMap': 'Ce workflow contient des nœuds de sortie non reconnus ; désignez-les avec leur type de média pour l’activer',
'conn.wfOutputApply': 'Enregistrer le mapping de sortie',
'conn.wfMapCancel': 'Annuler',
'conn.wfOutputApplied': 'Mapping de sortie enregistré : nœud {nodes}',
'conn.wfOutputCleared': 'Mapping de sortie effacé — le workflow est de nouveau en attente',
'conn.missingMaterial': 'Un JSON de workflow Qwen Image 2.1 dédié manque encore au dépôt : exportez-le depuis ComfyUI et importez-le ici — le chemin d\'import générique est prêt.',
// --- Génération indépendante image / vidéo (a3/a4, HEL-612) ---
'studio.image.title': 'Image',
'studio.image.subtitle': 'Générez des images avec les workflows importés · connexions et file partagées avec Connexions ComfyUI',
'studio.video.title': 'Vidéo',
'studio.video.subtitle': 'Générez des vidéos avec les workflows importés · connexions et file partagées avec Connexions ComfyUI',
'studio.genParams': 'Paramètres',
'studio.modeTextToImage': 'Texte vers image',
'studio.modeTextToVideo': 'Texte vers vidéo',
'studio.video.resultsTitle': 'Aperçu',
'studio.image.historyTitle': 'Historique images',
'studio.video.historyTitle': 'Historique vidéos',
'studio.historyCount': '{n} au total',
'studio.doneAt': 'Terminé à {time}',
'studio.kindImageText': 'image',
'studio.kindVideoText': 'vidéo',
'studio.loading': 'Chargement…',
'studio.connLabel': 'Connexion',
'studio.connQueue': 'File {n}',
'studio.connUntested': 'Vérification…',
'studio.connOk': 'Connecté · {ms} ms',
'studio.connFail': 'Injoignable',
'studio.connManage': 'Gérer les connexions',
'studio.wfLabel': 'Workflow',
'studio.wfParams': '{n} paramètres remplissables',
'studio.wfBindTo': 'Lié à {name}',
'studio.wfFollowActive': 'Suit la connexion par défaut',
'studio.promptLabel': 'Prompt positif',
'studio.promptPh': 'Décrivez l’image : sujet, décor, lumière, style…',
'studio.negLabel': 'Prompt négatif',
'studio.seedLabel': 'Graine',
'studio.sizeLabel': 'Dimensions',
'studio.batchLabel': 'Lot',
'studio.durationLabel': 'Durée (s)',
'studio.fpsLabel': 'Images/s',
'studio.stepsLabel': 'Étapes',
'studio.cfgLabel': 'CFG',
'studio.paramsTitle': 'Paramètres du workflow',
'studio.chars': '{n} car.',
'studio.insertStyle': 'Insérer des mots de style',
'studio.styleSoon': 'La bibliothèque de Skills arrivera avec la fonction Agents',
'studio.generateN': 'Générer · {n} images',
'studio.generate': 'Générer',
'studio.submitting': 'Envoi…',
'studio.etaHint': 'Le temps réel dépend de la connexion et du workflow',
'studio.errNoConn': 'Sélectionnez d’abord une connexion de génération',
'studio.errConnDown': 'Cette connexion est indisponible (dernier test échoué à {time}) ; changez de connexion ou corrigez-la dans Connexions ComfyUI',
'studio.errPrompt': 'Remplissez le prompt',
'studio.errPromptLong': 'Le prompt dépasse 2000 caractères ; raccourcissez-le',
'studio.errRefImage': 'Image-vers-image nécessite une image de référence',
'studio.errFirstLast': 'La vidéo premier/dernier cadre exige les deux cadres',
'studio.errUpload': 'Téléversez {label}',
'studio.errFill': 'Remplissez {label}',
'studio.slotRef': 'Image de référence',
'studio.slotRefN': 'Référence {n}',
'studio.slotMask': 'Masque',
'studio.slotFirst': 'Premier cadre',
'studio.slotLast': 'Dernier cadre',
'studio.slotOptional': 'Facultatif',
'studio.slotRefVideo': 'Vidéo de référence',
'studio.slotAudio': 'Audio de référence',
'studio.slotPick': 'Cliquez ou déposez',
'studio.slotFromResults': 'Choisir parmi les résultats d’image',
'studio.taskCurrent': 'Tâche en cours',
'studio.taskQueued': 'En file',
'studio.taskRunning': 'Génération',
'studio.taskCancel': 'Annuler la tâche',
'studio.queuedBehind': '{n} tâche(s) devant',
'studio.stepsShort': 'Étapes {v}',
'studio.usedShort': 'Écoulé {v}',
'studio.etaShort': 'Restant {v}',
'studio.targetShort': 'Cible {name}',
'studio.renderFrames': 'Frame {done}/{total}',
'studio.noActiveTask': 'Aucune tâche active · réglez les paramètres puis lancez Générer',
'studio.resultsTitle': 'Résultats récents',
'studio.selectHint': 'Choisie',
'studio.sendToImg2Img': 'Envoyer vers img2img',
'studio.zoom': 'Agrandir',
'studio.download': 'Télécharger',
'studio.downloadMp4': 'Télécharger MP4',
'studio.copyPrompt': 'Copier le prompt',
'studio.copiedToast': 'Copié ; collez-le dans la génération image/vidéo',
'studio.sentToImg2ImgToast': 'Ajouté comme référence ; vérifiez les paramètres et lancez',
'studio.noImg2ImgWf': 'Aucun workflow image ne déclare d’entrée de référence ; importez d’abord un workflow img2img dans Connexions ComfyUI',
'studio.videoRefStrip': 'Référence premier / dernier cadre',
'studio.historyEmptyImage': 'Aucune génération d’image ; réglez les paramètres puis lancez Générer',
'studio.historyEmptyVideo': 'Aucune génération de vidéo ; réglez les paramètres puis lancez Générer',
'studio.jobName': 'Tâche #{id}',
'studio.retryLink': 'Réessayer',
'studio.retryQueuedToast': 'Tâche remise en file',
'studio.retryFailedToast': 'Échec de la remise en file : {detail}',
'studio.errNoWorkflow': 'Choisissez d\'abord un workflow',
'studio.errBlocked': 'Envoi impossible : {reason}',
'studio.queuedToast': 'Envoyé à « {name} », en file',
'studio.submitFailedToast': 'Échec de l\'envoi : {detail}',
'studio.jobFailedToast': 'Échec de la génération : {detail}',
'studio.wfNoParamsNote': 'Ce workflow n\'a aucun paramètre à remplir et sera exécuté avec son prompt et ses réglages intégrés. Pour les remplir ici, ajoutez (Input:prompt) etc. aux titres de nœuds dans ComfyUI puis réimportez.',
'studio.wfAutoParamsNote': 'Aucune balise (Input:…) : {n} paramètres détectés par type de nœud ; les champs vides gardent les valeurs du workflow.',
'studio.promptNotDeclared': 'Ce workflow n\'a pas de nœud de prompt',
'studio.modeImageEdit': 'Image edit',
'studio.modeImageToVideo': 'Image to video',
'studio.modeRefToVideo': 'Reference to video',
'studio.slotInput': 'Input image',
'studio.slotHintOne': 'Required · 1 image',
'studio.slotEmptyInput': 'Click or drop the input image',
'studio.slotEmptyFirst': 'Click or drop the first frame',
'studio.slotEmptySub': 'PNG / JPG / WebP · ≤ 20MB each',
'studio.slotFromResultsShort': 'From results',
'studio.errImageFormat': '"{name}" is not supported — use PNG / JPG / WebP; this file will not be used',
'studio.errImageSize': '"{name}" is larger than 20MB — compress it and upload again',
'studio.errNeedInputImage': 'Image edit needs an input image',
'studio.errNeedFirstFrame': 'Image to video needs a first frame',
'studio.errNeedRef': 'Reference to video needs at least 1 reference image',
'studio.errRefMax': 'At most {max} reference images: {n} selected, these {k} were not added',
'studio.refHint': 'Required · 1–{max} · {n} selected',
'studio.refAdd': 'Add reference image',
'studio.refAddSub': '{n} more · max {max}',
'studio.refReplace': 'Replace',
'studio.refRemove': 'Remove reference {n}',
'studio.refRejectedShort': 'Not added',
'studio.refFull': 'Limit of {max} reached — remove one to add another',
'studio.refStrip': 'Reference images ({n} used)',
'studio.resolutionLabel': 'Output resolution',
'studio.resolutionHint': 'About {v}×{v} px, keeps the input aspect; 0 = original size',
'studio.wfBrokenTitle': 'This workflow file is incomplete — ComfyUI cannot run it, generation is blocked',
'studio.wfBrokenHint': 'Re-export the API-format JSON from a ComfyUI that has the custom nodes installed, then import it again under ComfyUI connections.',
'studio.errWfBroken': 'Workflow file is incomplete — re-export it before generating',
'studio.cancelToast': 'Annulation demandée',
'studio.deleteBtn': 'Supprimer',
'studio.delTitle': 'Supprimer la tâche',
'studio.delConfirm': 'La suppression retire aussi les fichiers de résultats de cette tâche ; l’historique est irrécupérable. Supprimer ?',
'studio.delTitleJob': 'Supprimer la tâche « {name} »',
'studio.delConfirmMulti': 'Cette tâche a produit {n} résultats. La suppression retire la tâche entière et ses {n} fichiers de résultats ; action irréversible. Supprimer ?',
'studio.deleteFailedToast': 'Échec de la suppression : {detail}',
'studio.deletedTakeNoFilesToast': '« {name} » supprimé',
'studio.deletedTakeToast': '« {name} » et ses fichiers de résultat ont été supprimés',
'studio.deletedToast': 'Tâche supprimée avec ses fichiers de résultats',
'studio.wfDeletedTag': 'Workflow supprimé',
'studio.wfEmptyTitle': 'Pas encore de workflows {kind}',
'studio.wfEmptyBody': 'Activez le mode développeur de ComfyUI, exportez le workflow en JSON API, puis importez-le dans Connexions ComfyUI comme {kind}.',
'studio.wfEmptyGo': 'Importer dans Connexions ComfyUI',
'studio.missingQwen': 'Les JSON dédiés Qwen Image 2.1 (t2i / img2img / masque) manquent encore ; la voie d’import générique est prête — exportez-les depuis ComfyUI.',
'studio.missingFirstLast': 'Le JSON dédié MiniMax H3 premier/dernier cadre manque encore ; les exemples t2v / r2v fournis peuvent être importés en attendant.',
'studio.pickerTitle': 'Choisir un résultat d’image',
'studio.pickerEmpty': 'Aucun résultat d’image disponible',
'studio.pickerPick': 'Utiliser',
'studio.uploadFailedToast': 'Échec du téléversement : {detail}',
'studio.playAria': 'Lecture',
'studio.pauseAria': 'Pause',
'studio.fullscreenAria': 'Plein écran',
// --- Page des tâches de génération (HEL-612) ---
'tasks.title': 'Tâches de génération',
'tasks.subtitle': 'Toutes les tâches image / vidéo : fenêtres indépendantes et flux de création',
'tasks.filterAll': 'Toutes',
'tasks.filterImage': 'Images',
'tasks.filterFailed': 'Échecs',
'tasks.filterActive': 'En cours',
'tasks.filterVideo': 'Vidéos',
'tasks.count': '{n} tâches · {m} actives',
'tasks.empty': 'Aucune tâche. Lancez la première dans Image ou Vidéo.',
'tasks.emptyFiltered': 'Aucune tâche ne correspond au filtre actuel.',
'tasks.goGenerate': 'Ouvrir Image',
'tasks.sourceStudioImage': 'Image indépendante',
'tasks.sourceStudioVideo': 'Vidéo indépendante',
'tasks.sourcePlayground': 'Playground',
'tasks.sourceFlow': 'Flux de création',
'tasks.sourceOther': 'Génération',
'tasks.queued': 'En file',
'tasks.running': 'En cours',
'tasks.done': 'Terminé',
'tasks.failed': 'Échec',
'tasks.retry': 'Réessayer',
'tasks.cancel': 'Annuler',
'tasks.delete': 'Supprimer',
'tasks.download': 'Télécharger',
'tasks.delTitle': 'Supprimer la tâche',
'tasks.delConfirm': 'Les fichiers de résultats seront supprimés avec la tâche. Supprimer ?',
'tasks.searchPh': 'Rechercher des tâches…',
'tasks.outputs': '{n} résultats',
'agentsPage.title': 'Agents',
'agentsPage.subtitle': 'Discutez séparément avec les cinq agents de création ; définissez et attribuez des Skills',
'agentsPage.statusChip': '{n} Skills · {m} activés',
'agentsPage.agentsTitle': 'Cinq agents',
'agentsPage.skillLib': 'Bibliothèque de Skills',
'agentsPage.skillLibCount': '{n}',
'agentsPage.installedTitle': '{name} · Skills installés',
'agentsPage.installedCount': '{n} · {m} actifs',
'agentsPage.newSkill': 'Nouveau Skill',
'agentsPage.skillLibEmpty': 'Aucun Skill pour l’instant — créez-en un avec « Nouveau Skill ».',
'agentsPage.skillsCount': '{n} Skills',
'agentsPage.replying': 'Réponse…',
'agentsPage.idle': 'Inactif',
'agentsPage.assigned': 'attribué {n}',
'agentsPage.edit': 'Modifier',
'agentsPage.toggleSkill': 'Activer ou désactiver le Skill',
'agentsPage.independentNote': 'Chat indépendant · hors du flux de création',
'agentsPage.model': 'Modèle',
'agentsPage.modelDefault': 'Défaut de l’agent',
'agentsPage.newSessionLabel': 'Nouvelle discussion',
'agentsPage.newSession': 'Nouvelle discussion',
'agentsPage.clear': 'Vider',
'agentsPage.export': 'Exporter',
'agentsPage.skillManage': 'Gestion des Skills',
'agentsPage.composerPlaceholder': 'Continuez la discussion ou collez un fragment de scénario… (Entrée pour envoyer, Maj+Entrée pour un saut de ligne)',
'agentsPage.send': 'Envoyer',
'agentsPage.clearTitle': 'Vider la discussion',
'agentsPage.clearConfirm': 'L’historique sera perdu définitivement. Vider la discussion avec l’agent {name} ?',
'agentsPage.skillErrName': 'Donnez un nom au Skill',
'agentsPage.skillErrAssign': 'Attribuez-le à au moins un Agent, sinon il ne prendra jamais effet',
'agentsPage.skillLoadFailed': 'Échec de lecture du contenu du Skill',
'agentsPage.skillSaved': 'Skill enregistré',
'agentsPage.skillSaveFailed': 'Échec de l’enregistrement : {detail}',
'agentsPage.skillEnabled': 'Skill activé',
'agentsPage.skillDisabled': 'Skill désactivé — les nouvelles réponses ne l’utiliseront plus',
'agentsPage.skillDeleted': 'Skill supprimé',
'agentsPage.skillRestored': 'Version précédente restaurée',
'agentsPage.skillTypeTemplate': 'Modèle de prompt',
'agentsPage.skillTypeKnowledge': 'Connaissance de référence',
'agentsPage.skillTypeRules': 'Règles de processus',
'agentsPage.versions': 'Historique des versions',
'agentsPage.versionsEmpty': 'Aucune version — chaque enregistrement archive la précédente.',
'agentsPage.restore': 'Restaurer',
'agentsPage.close': 'Fermer',
'agentsPage.editSkill': 'Modifier le Skill',
'agentsPage.skillName': 'Nom',
'agentsPage.skillNamePh': 'ex. cyberpunk-style-kit',
'agentsPage.skillType': 'Type',
'agentsPage.skillDesc': 'Description',
'agentsPage.skillDescPh': 'Quand l’agent doit l’utiliser (affiché dans sa liste de Skills)',
'agentsPage.skillContent': 'Contenu',
'agentsPage.skillContentPh': 'Markdown pris en charge : modèles, références ou règles…',
'agentsPage.skillContentHint': 'Markdown pris en charge ; l’enregistrement incrémente la version et archive l’ancienne.',
'agentsPage.assignTo': 'Attribuer à',
'agentsPage.saveNext': 'Enregistrer v{v}+1',
'agentsPage.save': 'Enregistrer',
'agentsPage.disable': 'Désactiver',
'agentsPage.enable': 'Activer',
'agentsPage.delete': 'Supprimer',
'agentsPage.delSkillTitle': 'Supprimer le Skill',
'agentsPage.delSkillConfirm': 'Irréversible ; les {n} agents assignés le perdront aussi. Supprimer ?',
'agentsPage.skillIdleHint': 'Choisissez « Modifier » dans la bibliothèque ou cliquez « Nouveau Skill »',
'agentsPage.sugScript1': 'Transformer une idée en plan trois actes',
'agentsPage.sugScript1P': 'Idée : un vendeur de supérette remarque le même client à la même minute chaque nuit. Écrivez un plan en trois actes.',
'agentsPage.sugScript2': 'Peaufiner un scénario existant',
'agentsPage.sugScript2P': 'Je collerai un scénario ; lisez-le puis proposez trois améliorations de dialogue et de rythme.',
'agentsPage.sugStyle1': 'Proposer des directions visuelles',
'agentsPage.sugStyle1P': 'Court-métrage romantique urbain sous la pluie néon : trois directions visuelles distinctes avec mots-clés anglais.',
'agentsPage.sugStyle2': 'Mots-clés cinéma réaliste',
'agentsPage.sugStyle2P': 'Compilez des prompts de style cinéma réaliste (positif + négatif), anglais annoté en chinois.',
'agentsPage.sugBoard1': 'Découper le scénario en storyboard',
'agentsPage.sugBoard1P': 'Découpez ce scénario plan par plan : numéro, échelle, mouvement, contenu, réplique, durée.',
'agentsPage.sugBoard2': 'Storyboard du climax',
'agentsPage.sugBoard2P': 'Climax de poursuite de 30 secondes : une version au rythme marqué.',
'agentsPage.sugAssets1': 'Prompts de fiche personnage',
'agentsPage.sugAssets1P': 'L’héroïne est une détective de 17 ans : des prompts cohérents (face / profil / plein pied).',
'agentsPage.sugAssets2': 'Liste d’assets',
'agentsPage.sugAssets2P': 'À partir de la supérette sous la pluie, listez des prompts de décors et accessoires.',
'agentsPage.sugShot1': 'Un prompt vidéo',
'agentsPage.sugShot1P': 'Travelling avant de l’enseigne néon vers la porte vitrée : un prompt vidéo prêt à l’emploi.',
'agentsPage.sugShot2': 'Plans premier/dernier cadre',
'agentsPage.sugShot2P': 'Montrez comment écrire un prompt premier/dernier cadre : description, mouvement et durée.',
'workbench.title': 'Atelier de création',
'workbench.subtitle': 'Scénario → style → storyboard → assets → plan de tournage, cinq agents en relais',
'workbench.pickerSubtitle': 'Choisissez un projet pour reprendre son flux en cinq étapes',
'workbench.pickerEmpty': 'Aucun projet pour l\'instant',
'workbench.pickerEmptyBody': 'Retournez à la vue d\'ensemble : partez d\'une idée ou importez un scénario.',
'workbench.pickerGoHome': 'Vue d\'ensemble',
'workbench.pickerFootHint': 'Vous pouvez aussi entrer dans l\'atelier depuis la vue d\'ensemble (idée / import de scénario).',
'workbench.stageProgress': 'Progression en cinq étapes',
'workbench.activeJobs': '{n} tâches en cours',
'workbench.stage.script': 'Scénario',
'workbench.stage.style': 'Style visuel',
'workbench.stage.storyboard': 'Storyboard',
'workbench.stage.assets': 'Assets',
'workbench.stage.shot': 'Plan de tournage',
'workbench.lockedStep': 'Se déverrouille après confirmation de « {stage} »',
'workbench.state.todo': 'Non commencé',
'workbench.state.running': 'Génération',
'workbench.state.draft': 'À confirmer',
'workbench.state.confirmed': 'Confirmé',
'workbench.state.edited': 'Modifié',
'workbench.copied': 'Copié — à coller dans la génération image/vidéo',
'workbench.copyFailed': 'Échec de la copie, copiez manuellement',
'workbench.copy': 'Copier',
'workbench.charCount': '{n} caractères',
'workbench.runStage': 'Générer avec {agent}',
'workbench.runDone': '{agent} a terminé le brouillon — à valider',
'workbench.runFailed': 'Échec de génération, réessayez',
'workbench.runningHint': '{agent} rédige cette étape…',
'workbench.confirmNext': 'Confirmer et continuer',
'workbench.confirmLast': 'Confirmer l\'étape',
'workbench.confirmed': 'Étape « {agent} » confirmée',
'workbench.confirmFailed': 'Échec de confirmation, réessayez',
'workbench.restore': 'Restaurer la version confirmée',
'workbench.restored': 'Version confirmée restaurée',
'workbench.restoreFailed': 'Échec de restauration, réessayez',
'workbench.draftNotice': 'Brouillon non confirmé : l\'agent suivant ne le verra qu\'après confirmation.',
'workbench.draftSaved': 'Brouillon enregistré — confirmation requise',
'workbench.saveFailed': 'Échec de l\'enregistrement, réessayez',
'workbench.saveDraft': 'Enregistrer le brouillon',
'workbench.cancelEdit': 'Annuler',
'workbench.editDraft': 'Modifier',
'workbench.regenerate': 'Régénérer',
'workbench.regenerateHint': 'Regénérer cette étape (la version confirmée est conservée et restaurable)',
'workbench.instructionPh': 'Consignes supplémentaires (facultatif) : plus cinématographique, dialogues plus naturels…',
'workbench.jobSubmitted': 'Tâche de génération envoyée — les résultats reviennent au projet',
'workbench.jobSubmitFailed': 'Échec de l\'envoi de la tâche',
'workbench.jobRequeued': 'Tâche remise en file',
'workbench.retryJob': 'Réessayer',
'workbench.cancelJob': 'Annuler la tâche',
'workbench.openOutput': 'Voir le résultat',
'workbench.jobRunningPct': '{n} %',
'workbench.jobRunning': 'En cours',
'workbench.jobQueued': 'En file',
'workbench.jobDone': 'Terminé',
'workbench.jobFailed': 'Échec',
'workbench.generating': 'Génération…',
'workbench.progressChip': 'Étape {n}/5',
'workbench.backHome': 'Vue d\'ensemble',
'workbench.loadFailed': 'Échec du chargement de l\'atelier.',
'workbench.retryLoad': 'Réessayer',
'workbench.agentSkills': '{n} skills',
'workbench.chatWithAgent': 'Discuter en solo',
'workbench.tasksTitle': 'Tâches de l\'étape',
'workbench.tasksAll': 'Toutes les tâches',
'workbench.tasksEmpty': 'Aucune tâche. Envoyez des prompts depuis l\'étape assets ou plans.',
'workbench.flowTitle': 'Progression en cinq étapes',
'workbench.script.todoTitle': 'Commencez par le scénario : confiez votre idée à l\'agent Scénario',
'workbench.script.todoIdea': 'Votre idée :',
'workbench.script.generate': 'Rédiger le brouillon',
'workbench.script.importBtn': 'Importer un scénario',
'workbench.script.writeManually': 'Écrire manuellement',
'workbench.script.importPlaceholder': 'Collez ici un scénario existant… L\'import saute la rédaction et reprend au style visuel.',
'workbench.script.importHint': 'Le scénario importé devient la base confirmée de cette étape.',
'workbench.script.importConfirm': 'Importer et passer',
'workbench.script.importDone': 'Scénario importé — continuez au style visuel',
'workbench.script.importFailed': 'Échec de l\'import, vérifiez le texte et réessayez',
'workbench.script.editorHint': 'Modifiez le texte directement ; la confirmation reste nécessaire.',
'workbench.script.copyLabel': 'Scénario complet',
'workbench.style.todoTitle': 'Définir le style visuel du scénario',
'workbench.style.todoBody': 'L\'agent Style propose plusieurs directions, chacune avec des prompts image prêts à copier.',
'workbench.style.generate': 'Proposer des directions',
'workbench.style.namePh': 'Nom de la direction, ex. Néon Cyber',
'workbench.style.descPh': 'Description (palette / lumière / matière)',
'workbench.style.promptPh': 'Mots-clés image en anglais, séparés par des virgules',
'workbench.style.negativePh': 'Prompt négatif (facultatif, anglais)',
'workbench.style.negativeLabel': 'Prompt négatif',
'workbench.style.remove': 'Supprimer la direction',
'workbench.style.add': 'Ajouter une direction',
'workbench.style.chosen': 'Sélectionné',
'workbench.style.chooseHint': 'En confirmant, le style choisi est transmis aux étapes suivantes.',
'workbench.style.promptLabel': 'Prompt de style',
'workbench.board.scene': 'Scène',
'workbench.board.size': 'Échelle',
'workbench.board.camera': 'Caméra',
'workbench.board.duration': 'Sec',
'workbench.board.desc': 'Description',
'workbench.board.dialog': 'Dialogue/SFX',
'workbench.board.descPh': 'Ce que montre ce plan',
'workbench.board.dialogPh': 'Dialogue ou effet sonore (facultatif)',
'workbench.board.remove': 'Supprimer le plan',
'workbench.board.add': 'Ajouter un plan',
'workbench.board.todoTitle': 'Découper le scénario plan par plan',
'workbench.board.todoBody': 'L\'agent Storyboard produit numéros, échelles, mouvements et durées.',
'workbench.board.generate': 'Rédiger le storyboard',
'workbench.board.summary': '{n} plans · ~{sec} s',
'workbench.asset.kindCharacter': 'Personnage',
'workbench.asset.kindLocation': 'Lieu',
'workbench.asset.kindProp': 'Accessoire',
'workbench.asset.namePh': 'Nom de l\'asset',
'workbench.asset.descPh': 'Description (apparence, usage)',
'workbench.asset.promptPh': 'Prompt image complet en anglais',
'workbench.asset.promptLabel': 'Prompt image',
'workbench.asset.remove': 'Supprimer l\'asset',
'workbench.asset.add': 'Ajouter un asset',
'workbench.asset.todoTitle': 'Construire la liste d\'assets avec prompts',
'workbench.asset.todoBody': 'L\'agent Assets combine scénario, style et storyboard en prompts prêts à copier.',
'workbench.asset.generate': 'Rédiger la liste',
'workbench.asset.generateImage': 'Générer l\'image',
'workbench.asset.generateHint': 'Génère via le workflow ComfyUI connecté ; les résultats reviennent au projet',
'workbench.asset.summary': '{n} assets',
'workbench.vshot.noPh': 'N° de plan, ex. S1',
'workbench.vshot.descPh': 'Description du plan',
'workbench.vshot.promptPh': 'Prompt vidéo complet (anglais)',
'workbench.vshot.promptLabel': 'Prompt vidéo',
'workbench.vshot.remove': 'Supprimer le plan',
'workbench.vshot.add': 'Ajouter un plan',
'workbench.vshot.todoTitle': 'Produire le script vidéo plan par plan',
'workbench.vshot.todoBody': 'L\'agent Plans transforme le storyboard en prompts prêts pour les modèles vidéo.',
'workbench.vshot.generate': 'Rédiger les plans',
'workbench.vshot.generateVideo': 'Générer la vidéo du plan',
'workbench.vshot.generateHint': 'Génère via le workflow vidéo ComfyUI connecté ; résultats dans le projet',
'workbench.vshot.summary': '{n} plans',
'home.errScriptShort': 'Scénario trop court — vérifiez le collage (30 caractères min.)',
'home.stageProgress': 'Progression en cinq étapes',
'tasks.sourceWorkbench': 'Flux de création',
'jobst.idSuffix': ' · ID de prompt ComfyUI {id}',
'jobst.done': 'Fixé',
'jobst.doneDetail': 'ComfyUI a terminé, résultats enregistrés',
'jobst.dryRun': 'Substitut',
'jobst.dryRunDetail': 'Substitut uniquement : Dry-run actif, ComfyUI n\'a pas été appelé',
'jobst.noOutput': 'Aucune sortie',
'jobst.noOutputDetail': 'La tâche s\'est terminée sans fichier de résultat : pas une génération',
'jobst.missing': 'Fichiers manquants',
'jobst.missingDetail': 'La tâche a réussi, mais ses fichiers ne sont plus sur le serveur',
'jobst.queued': 'En attente',
'jobst.queuedDetail': 'En attente dans la file de l\'atelier avant envoi à ComfyUI',
'jobst.connecting': 'Connexion',
'jobst.connectingDetail': 'Connexion à ComfyUI et envoi des entrées',
'jobst.comfyQueued': 'Acceptée',
'jobst.comfyQueuedDetail': 'ComfyUI a accepté la tâche et l\'a mise en file',
'jobst.comfyQueuedAhead': 'ComfyUI a accepté la tâche — {n} devant dans sa file',
'jobst.comfyRunning': 'En cours',
'jobst.comfyRunningDetail': 'ComfyUI exécute la tâche',
'jobst.saving': 'Enregistrement',
'jobst.savingDetail': 'ComfyUI a renvoyé des résultats, téléchargement',
'jobst.failed': 'Échec',
'jobst.cancelled': 'Annulée',
'studio.ratioLabel': 'Format d\'image',
'studio.megapixelsLabel': 'Mégapixels',
'studio.outputSize': 'Sortie {w} × {h}',
'studio.denoiseLabel': 'Débruitage',
'studio.errNumber': '« {label} » doit être un nombre',
'studio.errInteger': '« {label} » doit être un entier',
'studio.errMin': '« {label} » doit valoir au moins {v}',
'studio.errMax': '« {label} » doit valoir au plus {v}',
'studio.errOption': '« {label} » n\'est pas une option du workflow',
'studio.reuseParams': 'Réutiliser les réglages',
'studio.reusedToast': 'Réglages de cette tâche repris : ajustez puis relancez',
'studio.reuseMissingWf': 'Le workflow de cette tâche n\'existe plus',
'studio.doneToast': 'Terminé : {n} fichier(s) (ID de prompt ComfyUI {id})',
'studio.dryRunToast': 'Substitut uniquement : Dry-run actif, ComfyUI n\'a pas été appelé',
'studio.dryRunNote': 'Dry-run actif : Générer n\'écrit que des substituts et n\'appelle jamais ComfyUI. Désactivez-le dans Réglages.',
// --- HEL-643 : vérification d'import / test réel / groupes de médias ---
'studio.errVideoFormat': "« {name} » n'est pas un format vidéo pris en charge — utilisez MP4 / WebM / MOV",
'studio.errAudioFormat': "« {name} » n'est pas un format audio pris en charge — utilisez MP3 / WAV / M4A",
'studio.errMediaSize': "« {name} » dépasse la limite de taille — compressez-le d'abord",
'studio.errNeedRefMedia': '« {label} » exige au moins {n} clips',
'studio.refHintMedia': 'Requis · 1–{max} clips · {n} sélectionnés',
'studio.refAddMedia': 'Ajouter {kind}',
'studio.refAddSubMedia': '{n} de plus · max {max}',
'studio.refRemoveMedia': 'Retirer {kind} {n}',
'studio.refFullMedia': 'Limite de {max} clips atteinte — retirez-en un pour en ajouter un autre',
'wfMedia.h3Limits': "Limites officielles MiniMax H3 Ref2VA : jusqu'à 9 images, 3 vidéos et 3 audios de référence ; chaque clip de 2–15 s, totaux ≤15 s par type ; l'audio ne peut être la seule référence ; 12 fichiers de référence au maximum.",
'wfMedia.h3TotalOver': '{n} fichiers de référence — au-delà du plafond officiel de 12 ; la génération peut échouer',
'wfMedia.h3AudioAlone': "L'audio ne peut pas être la seule référence — ajoutez au moins une image ou une vidéo",
'conn.wfCheckTitle': 'Vérification de compatibilité de la connexion',
'conn.wfCheckEndpoint': 'Cible : {name}',
'conn.wfCheckBtn': 'Revérifier',
'conn.wfChecking': 'Vérification…',
'conn.wfCheckOk': 'Cette connexion possède les nœuds et modèles requis par ce flux',
'conn.wfCheckProblems': '{n} nœud(s)/modèle(s) manquant(s) détecté(s)',
'conn.wfCheckUnreachable': "Vérification impossible (ComfyUI injoignable) — l'enregistrement reste possible ; revérifiez après avoir réparé la connexion",
'conn.wfCheckSaveHint': 'Vous pouvez enregistrer le brouillon (il ne sera pas marqué générable) ; installez le manquant puis revérifiez.',
'conn.wfTestBtn': 'Tester',
'conn.wfLastTest': 'Dernier test',
'conn.wfTestPassed': '{time} réussi ({n} fichiers)',
'conn.wfTestRunning': '{time} en cours',
'conn.wfTestFailed': '{time} échoué',
'wft.title': 'Tester le flux',
'wft.connection': 'Connexion cible',
'wft.costNote': 'Un test envoie une tâche réelle au ComfyUI choisi et mobilise son VRAM et sa file.',
'wft.submit': 'Lancer le test',
'wft.confirmTitle': 'Confirmer une exécution réelle',
'wft.confirmBody': 'Une tâche réelle sera envoyée à « {endpoint} » ({n} tâches en file). Le test ne réussit que si au moins un fichier téléchargeable du bon type revient.',
'wft.running': 'Test en cours…',
'wft.cancel': 'Annuler le test',
'wft.passed': 'Test réussi : {n} fichier(s) produit(s)',
'wft.passedShort': 'Réussi ({n} fichiers)',
'wft.failed': 'Test échoué',
'wft.failedShort': 'Échoué',
'wft.cancelledShort': 'Annulé',
'wft.reusedToast': 'Un test est déjà en cours pour ce flux — rattaché à celui-ci',
'wft.history': 'Historique des tests ({n})',
'wft.clear': "Effacer l'historique des tests",
'wft.cleared': 'Historique des tests effacé',
'wft.never': 'Jamais testé',
'wft.download': 'Télécharger',
'wft.errRequired': 'Veuillez renseigner « {label} »',
'wft.errListMin': '« {label} » exige au moins {n} {unit}',
'tasks.testBadge': 'Test',
'tasks.sourceWorkflowTest': 'Test de flux',
// --- 生成台 (HEL-653) ---
'cdf.orig': 'Original {v}',
'desk.title': 'Générer',
'desk.advanced': 'Avancé · {n} · inchangés, les valeurs du workflow s’appliquent',
'desk.chipResolution': 'Résolution {v}',
'desk.chipSeconds': '{v} s',
'desk.chipSeed': 'Graine {v}',
'desk.closeInspector': 'Fermer l’inspecteur',
'desk.countActive': '{n} en cours',
'desk.countTakes': '{n} prises',
'desk.ctxAsset': '{kind} « {name} »',
'desk.ctxShot': 'Plan {no}',
'desk.ctxBack': 'Retour à {stage}',
'desk.ctxDismiss': 'Fermer la note d’origine',
'desk.ctxFrom': 'Depuis « {project} »',
'desk.ctxNoBackfill': 'Les résultats restent dans le fil et ne sont pas renvoyés vers {stage}',
'desk.dayDate': '{d}/{m}',
'desk.download': 'Télécharger',
'desk.dropNoSlot': '{n} fichier(s) sans emplacement : ce workflow n’a pas cette entrée',
'desk.dryRun': 'Simulation',
'desk.durMin': '{m} min {s} s',
'desk.durSec': '{s} s',
'desk.elapsed': 'Durée',
'desk.emptyFailed': 'Aucune prise échouée',
'desk.emptyFeed': 'Aucune prise. Écrivez un prompt ci-dessous et cliquez sur Générer.',
'desk.filterAria': 'Filtrer les prises',
'desk.filterAll': 'Tout',
'desk.filterImage': 'Images',
'desk.filterVideo': 'Vidéos',
'desk.filterFailed': 'Échecs',
'desk.generate': 'Générer',
'desk.genHint': 'Générer (Ctrl/⌘ + Entrée)',
'desk.inputs': 'Entrées',
'desk.inspector': 'Inspecteur',
'desk.keyClose': 'Fermer',
'desk.keyInspector': 'Afficher / masquer',
'desk.keySelect': 'Choisir',
'desk.keyUse': 'Utiliser',
'desk.kvCreated': 'Soumis',
'desk.kvName': 'Nom',
'desk.kvPromptId': 'ID ComfyUI',
'desk.kvUsage': 'Usage',
'desk.loadEarlier': 'Afficher {n} prises plus anciennes',
'desk.missingSub': 'Refaire avec les mêmes paramètres, ou retirer cette prise',
'desk.missingTitle': 'Les fichiers de résultat ne sont plus sur le serveur',
'desk.needWorkflow': 'Manque : workflow',
'desk.noConn': 'Non connecté',
'desk.noPromptInput': 'Ce workflow n’a pas de prompt ; il s’exécute avec ses propres valeurs.',
'desk.notGenerated': 'Non généré',
'desk.noWorkflows': 'Aucun workflow image ou vidéo prêt',
'desk.openInDesk': 'Régler dans le générateur',
'desk.openInDeskHint': 'Ouvre le générateur avec ce prompt ; choisissez workflow et paramètres, les résultats restent dans le fil',
'desk.openInspector': 'Inspecteur',
'desk.origValue': 'Valeur du workflow',
'desk.outputN': 'Résultat {n}',
'desk.outputs': 'Tous les résultats',
'desk.paramError': 'Paramètre invalide : {msg}',
'desk.paramsAll': 'Tous les paramètres',
'desk.paramsChanged': 'Paramètres · {n} modifiés',
'desk.paramsCommon': 'Paramètres courants',
'desk.pickTake': 'Choisissez une prise pour voir son résultat',
'desk.pickWorkflow': 'Choisir un workflow',
'desk.promptOnly': 'Prompt seul',
'desk.promptPh': 'Décrivez l’image… (Ctrl/⌘ + Entrée pour générer, / pour cibler)',
'desk.restoreAll': 'Rétablir toutes les valeurs du workflow',
'desk.redo': 'Refaire avec les mêmes paramètres',
'desk.removeRecord': 'Retirer la ligne',
'desk.restoreOrig': 'Rétablir l’original',
'desk.reuse': 'Réutiliser',
'desk.reuseToComposer': 'Réutiliser dans l’éditeur',
'desk.seedRandom': 'Aléatoire',
'desk.sendToSlot': 'Envoyer vers l’emplacement image',
'desk.sent': 'Soumis',
'desk.sentToSlotToast': 'Envoyé vers l’emplacement image du workflow actuel',
'desk.slotOne': '{label} ×1',
'desk.slotRange': '{label} {min}–{max}',
'desk.specSize': 'Taille',
'desk.stillNeed': 'Manque : {what}',
'desk.tabParams': 'Paramètres',
'desk.tabResult': 'Résultat',
'desk.today': 'Aujourd’hui',
'desk.took': 'Durée {d}',
'desk.wfBroken': 'Indisponible',
'desk.wfCurrent': 'actuel',
'desk.wfDefaultConn': 'Connexion par défaut',
'desk.wfImport': 'Importer / gérer les workflows',
'desk.wfLastFailed': 'Dernier essai échoué',
'desk.wfNoMatch': 'Aucun workflow correspondant',
'desk.wfOk': 'Prêt',
'desk.wfSearchPh': 'Chercher un workflow ou un usage : image vers vidéo, référence…',
'desk.wfTesting': 'Test en cours',
'desk.wfUntested': 'Non testé',
'desk.workflow': 'Workflow',
'desk.yesterday': 'Hier',
'wfd.stepParse': 'Analyser le JSON',
'wfd.stepNodes': 'Identifier les nœuds',
'wfd.stepModels': 'Vérifier les modèles',
'wfd.stepSlots': 'Créer les slots d’entrée',
'wfd.noOutput': "Le flux n'a aucun nœud de sortie — import impossible",
'wfd.nodesAutoOk': 'Usage détecté automatiquement : {usage}',
'wfd.nodesUserOk': 'Usage confirmé : {usage}',
'wfd.modelsOk': '« {name} » possède tous les nœuds et modèles requis',
'wfd.slotsOk': "{n} slot(s) d'entrée créés ({m} média)",
'wfd.checksAria': "Résultats de la vérification d'import",
'wfd.showDetails': "Afficher les détails de l'erreur",
'wfd.hideDetails': "Masquer les détails de l'erreur",
'wfd.unreachableSuggest': "L'impossibilité de vérifier n'empêche pas l'enregistrement ; revérifiez après avoir réparé la connexion.",
'wfd.nodesPickSuggest': "Choisissez l'usage et terminez le mappage des sorties ci-dessous avant d'enregistrer.",
'wfd.showRaw': 'Voir le JSON brut',
'wfd.hideRaw': 'Masquer le JSON brut',
// --- Workflow library · batch import & management (HEL-682) ---
'wl.hint': 'Importez par lots des flux au format UI ; cherchez, filtrez, annotez — le JSON complet ne se charge qu’à l’action',
'wl.batchImport': 'Import par lot',
'wl.dedupe': 'Dédupliquer',
'wl.dedupeTitle': 'Supprimer les flux dupliqués',
'wl.dedupeConfirm': 'Les entrées au nom ET contenu identiques seront supprimées (le premier import est conservé). Même nom mais contenu différent = votre variante, intact. Continuer ?',
'wl.dedupeDone': '{n} flux dupliqués supprimés',
'wl.dedupeNone': 'Aucun flux dupliqué trouvé',
'wl.favCount': '{n} favoris',
'wl.searchPh': 'Rechercher nom, description, tags, modèle… (touche /)',
'wl.filterLabel': 'Filtres',
'wl.filterAll': 'Tous',
'wl.filterFav': 'Favoris',
'wl.filterPending': 'À confirmer',
'wl.filterDisabled': 'Désactivés',
'wl.favAria': 'Mettre en favori',
'wl.unfavAria': 'Retirer des favoris',
'wl.categoryLabel': 'Catégorie',
'wl.categoryAll': 'Toutes les catégories',
'wl.familyLabel': 'Famille de modèle',
'wl.familyAll': 'Toutes les familles',
'wl.mediaLabel': 'Média',
'wl.mediaAll': 'Tous les médias',
'wl.mediaImage': 'Image',
'wl.mediaVideo': 'Vidéo',
'wl.mediaAudio': 'Audio',
'wl.mediaIn': 'Entrée',
'wl.mediaOut': 'Sortie',
'wl.sortLabel': 'Tri',
'wl.sortRecent': 'Favoris / récents',
'wl.sortName': 'Nom',
'wl.resetFilters': 'Effacer les filtres',
'wl.noMatch': 'Aucun flux ne correspond aux filtres',
'wl.resultCount': '{n} sur {m}',
'wl.selected': '{n} sélectionnés',
'wl.batchLabel': 'Actions groupées',
'wl.batchAnnotate': 'Annoter',
'wl.batchEnable': 'Activer',
'wl.batchDisable': 'Désactiver',
'wl.clearSel': 'Effacer la sélection',
'wl.batchDone': '{n} flux mis à jour',
'wl.batchPartial': '{n} réussis, {m} échoués (usage et sortie à confirmer d’abord)',
'wl.selectAll': 'Sélectionner tous les flux listés',
'wl.rowCheckAria': 'Sélectionner {name}',
'wl.headMeta': 'Métadonnées',
'wl.headActions': 'Actions',
'wl.enableAria': 'Activer ou désactiver {name}',
'wl.enableBlocked': 'Confirmez l’usage et les nœuds de sortie avant activation',
'wl.editMeta': 'Modifier les métadonnées',
'wl.lastUsed': 'Dernière utilisation',
'wl.moreCount': 'Afficher {n} de plus ({m} au total)',
'wfCat.basic': 'Traitement de base',
'wfCat.audioTts': 'Génération de voix',
'wfCat.music': 'Génération de musique',
'wfCat.image': 'Génération d’images',
'wfCat.video': 'Génération de vidéo',
'wfCat.digitalHuman': 'Humain numérique',
'wfCat.motionTransfer': 'Transfert de mouvement',
'md.title': 'Métadonnées du flux',
'md.batchTitle': 'Annotation groupée ({n})',
'md.batchHint': 'Seuls les champs remplis sont appliqués ; renommage par rechercher→remplacer, tags ajoutés.',
'md.name': 'Nom affiché',
'md.nameFind': 'Rechercher',
'md.nameFindPh': 'Texte à remplacer…',
'md.nameReplace': 'Remplacer par',
'md.nameReplacePh': 'Texte de remplacement…',
'md.nameHint': 'Laissez « Rechercher » vide pour ne pas renommer.',
'md.description': 'Description',
'md.descriptionPh': 'Une ligne sur ce que fait ce flux…',
'md.tags': 'Tags',
'md.tagsPh': 'ex. rapide, haute qualité',
'md.tagsHint': 'Séparés par des virgules ; ajoutés en mode groupé.',
'md.category': 'Catégorie',
'md.modelFamily': 'Famille de modèle',
'md.apply': 'Appliquer',
'md.applied': '{n} flux mis à jour',
'md.appliedOne': 'Mis à jour',
'md.partial': '{n} réussis, {m} échoués',
'wiz.title': 'Import de flux par lot',
'wiz.stepSource': 'Source',
'wiz.stepReport': 'Rapport de test',
'wiz.stepResult': 'Résultat',
'wiz.sourceLabel': 'Source d’import',
'wiz.modeScan': 'Scanner un dossier serveur',
'wiz.modeFiles': 'Choisir des fichiers locaux',
'wiz.rootLabel': 'Dossier serveur',
'wiz.rootHint': 'Chemin d’un dossier sur le serveur (ex. example_ComfyUI_workflows du dépôt) ; les JSON au format UI sont scannés récursivement, le format API et les autres sont ignorés.',
'wiz.preflight': 'Pré-vérification sur un ComfyUI réel (facultatif)',
'wiz.preflightNone': 'Passer (conversion hors ligne)',
'wiz.preflightHint': 'Avec une connexion choisie, les graphes convertis sont vérifiés nœud par nœud.',
'wiz.pickFiles': 'Fichiers locaux',
'wiz.pickFilesBtn': 'Choisir des fichiers JSON (plusieurs)',
'wiz.pickFilesHint': 'Choisissez des flux ComfyUI au format UI ; sélection multiple possible.',
'wiz.parsed': '{n} fichiers lus',
'wiz.notUi': '{n} fichiers ne sont pas au format UI (pas de tableau nodes), ignorés',
'wiz.noFiles': 'Choisissez d’abord des fichiers à importer',
'wiz.runDry': 'Lancer le test (rien n’est enregistré)',
'wiz.running': 'Vérification…',
'wiz.total': '{n} fichiers',
'wiz.ok': 'OK {n}',
'wiz.warn': 'Avertissements {n}',
'wiz.fail': 'Échecs {n}',
'wiz.confirmCount': 'À vérifier {n}',
'wiz.importable': 'Importables {n}',
'wiz.reportHint': 'Le test n’écrit rien. Les avertissements s’importent activés dès qu’un usage est fourni ; les fichiers à vérifier ou en échec ne sont jamais importés.',
'wiz.filterLabel': 'Filtres du rapport',
'wiz.filterWarn': 'Avertissements seuls',
'wiz.filterBlocked': 'Non importables',
'wiz.searchPh': 'Rechercher un nom de fichier…',
'wiz.includeAria': 'Importer {name}',
'wiz.skipReason': 'Non importable : {reason}',
'wiz.issues': '{n} notes de conversion',
'wiz.usagePick': 'Usage :',
'wiz.usageNone': 'Passer pour l’instant (à confirmer après import)',
'wiz.selectedN': '{n} fichiers seront importés',
'wiz.excludedM': '{m} non importables',
'wiz.import': 'Importer',
'wiz.importing': 'Import…',
'wiz.back': 'Retour',
'wiz.imported': '{n} importés',
'wiz.skipped': '{n} ignorés',
'wiz.conflict': 'Existe déjà (doublon ignoré)',
'wiz.usageApplied': 'Usage fourni pour {n} nouveaux imports',
'wiz.done': 'Terminé',
'wiz.again': 'Importer un autre lot',
'wiz.resultNote': 'Les fichiers au contenu identique sont ignorés automatiquement — relancer ne crée jamais de doublons.',
'wiz.importedToast': '{n} flux importés',
'wiz.warnTag': 'Avertissement',
'wiz.confirmTag': 'À vérifier',
'wiz.preflightTag': 'Pré-vérification échouée',
'wiz.importedTag': 'Importé #{id}',
};