@seliseblocks/mailcraft 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/DOCS.md +240 -12
  2. package/README.md +11 -3
  3. package/README.md.txt +134 -0
  4. package/dist/mailcraft-editor.bundle.js +51 -39
  5. package/dist/mailcraft-editor.bundle.js.map +3 -3
  6. package/examples/templates/order-confirmed.html +80 -80
  7. package/examples/vanilla.html +242 -23
  8. package/package.json +7 -2
  9. package/src/core/assets.js +10 -15
  10. package/src/core/binder.js +120 -118
  11. package/src/core/blocks.js +14 -1
  12. package/src/core/css-cascade.js +117 -117
  13. package/src/core/editor-core.js +1530 -1492
  14. package/src/core/export.js +142 -55
  15. package/src/core/i18n/ar.js +219 -177
  16. package/src/core/i18n/bg.js +196 -152
  17. package/src/core/i18n/bn.js +218 -176
  18. package/src/core/i18n/ca.js +196 -152
  19. package/src/core/i18n/cs.js +196 -152
  20. package/src/core/i18n/da.js +196 -152
  21. package/src/core/i18n/de-CH.js +196 -152
  22. package/src/core/i18n/de.js +196 -152
  23. package/src/core/i18n/dz.js +221 -179
  24. package/src/core/i18n/el.js +196 -152
  25. package/src/core/i18n/en.js +3 -10
  26. package/src/core/i18n/es.js +196 -152
  27. package/src/core/i18n/et.js +196 -152
  28. package/src/core/i18n/fi.js +196 -152
  29. package/src/core/i18n/fr.js +196 -152
  30. package/src/core/i18n/hr.js +196 -152
  31. package/src/core/i18n/hu.js +196 -152
  32. package/src/core/i18n/index.js +83 -83
  33. package/src/core/i18n/it.js +196 -152
  34. package/src/core/i18n/lt.js +196 -152
  35. package/src/core/i18n/lv.js +196 -152
  36. package/src/core/i18n/nb.js +196 -152
  37. package/src/core/i18n/nl.js +196 -152
  38. package/src/core/i18n/pl.js +196 -152
  39. package/src/core/i18n/pt.js +196 -152
  40. package/src/core/i18n/ro.js +196 -152
  41. package/src/core/i18n/ru.js +196 -152
  42. package/src/core/i18n/sk.js +196 -152
  43. package/src/core/i18n/sl.js +196 -152
  44. package/src/core/i18n/sv.js +196 -152
  45. package/src/core/i18n/tables.js +50 -50
  46. package/src/core/i18n/tr.js +196 -152
  47. package/src/core/i18n/uk.js +196 -152
  48. package/src/core/icons.js +237 -235
  49. package/src/core/ids.js +1 -1
  50. package/src/core/import-html.js +1025 -959
  51. package/src/core/layout-style.js +100 -100
  52. package/src/core/parse.js +10 -10
  53. package/src/core/placeholder.js +15 -15
  54. package/src/core/sanitize.js +141 -141
  55. package/src/core/storage-limits.js +184 -184
  56. package/src/core/storage.js +85 -85
  57. package/src/core/theme.js +1 -1
  58. package/src/core/variables.js +11 -11
  59. package/src/index.js +9 -9
  60. package/src/mailcraft-editor.js +26 -14
  61. package/src/render/block-body.js +49 -6
  62. package/src/render/canvas.js +31 -2
  63. package/src/render/fields.js +602 -588
  64. package/src/render/focus-preserve.js +158 -158
  65. package/src/render/rte.js +241 -212
  66. package/src/render/screenshot.js +132 -132
  67. package/src/render/story.js +415 -415
  68. package/src/render/style.js +8 -0
  69. package/types/index.d.ts +419 -0
@@ -1,152 +1,196 @@
1
- /** French (Français) — `fr`. AI-drafted, not reviewed by a native speaker. Correctable one key at a time via `.messages` overrides. */
2
- export const FR = {
3
- 'action.undoHint': 'Annuler — ⌘Z',
4
- 'action.redoHint': 'Rétablir — ⌘⇧Z',
5
- 'action.chromeToDark': 'Sombre',
6
- 'action.chromeToLight': 'Clair',
7
- 'action.chromeHint': 'Thème de l’éditeur clair / sombre',
8
- 'action.aiCopy': 'Texte',
9
- 'action.aiCopyHint': 'Rédiger un texte avec l’IA',
10
- 'action.code': 'Code',
11
- 'action.codeHint': 'Modifier le HTML brut avec aperçu en direct',
12
- 'action.preview': 'Aperçu',
13
- 'action.export': 'Exporter',
14
- 'device.desktop': 'Bureau',
15
- 'device.desktopHint': 'Largeur bureau',
16
- 'device.mobile': 'Mobile',
17
- 'device.mobileHint': 'Largeur mobile',
18
- 'device.dark': 'Sombre',
19
- 'device.darkHint': 'Boîte de réception sombre',
20
- 'status.autosaveOn': 'sauvegarde automatique activée',
21
- 'status.saved': 'enregistré {time}',
22
- 'status.saveFailed': 'non enregistré — stockage plein',
23
- 'canvas.meta': '{rows} lignes · {blocks} blocs · {width}px',
24
- 'tab.design': 'Style',
25
- 'tab.designHint': 'Styliser la sélection',
26
- 'tab.blocks': 'Blocs',
27
- 'tab.blocksHint': 'Blocs de contenu et variables',
28
- 'tab.rows': 'Sect.',
29
- 'tab.rowsHint': 'Mises en page de section et modèle de canevas',
30
- 'tab.files': 'Fichiers',
31
- 'tab.filesHint': 'Bibliothèque de ressources',
32
- 'tab.layers': 'Structure',
33
- 'tab.layersHint': 'Structure du document',
34
- 'tab.theme': 'Thème',
35
- 'tab.themeHint': 'Styles globaux',
36
- 'tab.data': 'Var.',
37
- 'tab.dataHint': 'Variables fournies par votre code',
38
- 'inspector.blockProperties': 'Propriétés du bloc',
39
- 'inspector.sectionProperties': 'Propriétés de la section',
40
- 'inspector.title': 'Inspecteur',
41
- 'inspector.sectionLabel': 'Section',
42
- 'inspector.nothingSelected': 'Rien n’est sélectionné',
43
- 'action.duplicateHint': 'Dupliquer — ⌘D',
44
- 'action.deleteHint': 'Supprimer ',
45
- 'inspector.emptyBody':
46
- 'Sélectionnez une ligne ou un bloc sur le canevas pour le styliser ici. Glissez des blocs depuis l’onglet <strong style="color: var(--ed-text); font-weight: 600;">Blocs</strong> ; double-cliquez sur un texte pour le modifier directement.',
47
- 'inspector.shortcuts': 'Raccourcis',
48
- 'shortcut.undoRedo': '⌘Z / ⌘⇧Z annuler, rétablir',
49
- 'shortcut.duplicate': '⌘D — dupliquer la sélection',
50
- 'shortcut.delete': 'supprimer la sélection',
51
- 'shortcut.export': '⌘Eexporter le HTML',
52
- 'shortcut.escape': 'ESCdésélectionner, fermer',
53
- 'blocks.dragHint': 'Glisser sur le canevas',
54
- 'blocks.count': '{count} blocs',
55
- 'rows.sectionLayouts': 'Mises en page de section',
56
- 'rows.customMarkup': 'Balisage personnalisé',
57
- 'rows.htmlRowHint': 'Glissez pour insérer, ou cliquez pour ajouter — une ligne pleine largeur que vous remplissez de HTML brut',
58
- 'rows.rawHtmlSection': 'Section HTML brut',
59
- 'rows.rawHtmlDesc': 'Section pleine largeur, votre propre balisage, toujours déplaçable',
60
- 'rows.canvasModel': 'Modèle de canevas',
61
- 'rows.modeRowBased': 'Basé sur les lignes',
62
- 'rows.modeFreeStack': 'Pile libre',
63
- 'rows.hintRows':
64
- 'Basé sur les sections : déposez d’abord une mise en page, puis des blocs dans ses colonnes — chaque section a son propre arrière-plan, sa bordure, ses réglages flex ou grille.',
65
- 'rows.hintStack': 'Pile libre : sans mise en page — chaque bloc déposé devient sa propre section pleine largeur, empilée dans l’ordre.',
66
- 'files.libraryCount': 'Bibliothèque{count} fichiers',
67
- 'files.openManager': 'Ouvrir le gestionnaire de fichiers',
68
- 'files.dragToCanvas': 'Glissez un fichier directement sur le canevas pour le placer comme bloc image.',
69
- 'layers.structure': 'Structure',
70
- 'layers.sectionSingle': 'Section',
71
- 'layers.sectionMulti': 'Section · {count} col.',
72
- 'layers.blockCount': '{count} blocs',
73
- 'theme.globalStyles': 'Styles globaux',
74
- 'vars.title': 'Variables',
75
- 'vars.fromCode': '{count} provenant de votre code',
76
- 'vars.declaredNote': 'Déclarées par votre application — le canevas affiche toujours le jeton, jamais une valeur.',
77
- 'vars.filterPlaceholder': 'Filtrer les variables…',
78
- 'vars.insertHint': 'Cliquer pour insérer dans le texte, le titre ou le bouton sélectionné',
79
- 'vars.insert': 'insérer',
80
- 'vars.noMatch': 'Aucune variable ne correspond à ce filtre.',
81
- 'vars.noneDeclared': 'Votre application n’a encore déclaré aucune variable.',
82
- 'vars.rteHint': 'En modifiant du texte, vous pouvez aussi choisir une variable directement dans le menu de la barre d’outils.',
83
- 'modal.fileManager': 'Gestionnaire de fichiers',
84
- 'modal.assetsTitle': 'Ressources',
85
- 'modal.replaceImage': 'Remplacer l’image',
86
- 'library.searchPlaceholder': 'Rechercher des fichiers…',
87
- 'action.upload': 'Téléverser',
88
- 'library.clickToPlace': 'Cliquez sur un fichier pour le placer · ou glissez un fichier sur le canevas',
89
- 'library.clickToReplace': 'Cliquez sur un fichier pour remplacer l’image sélectionnée',
90
- 'library.storageLabel': '{count} fichiers · {size}',
91
- 'library.folders': 'Dossiers',
92
- 'library.dropHint': 'Déposez des fichiers image ici pour les téléverser — ou utilisez le bouton Téléverser.',
93
- 'library.deleteFileHint': 'Supprimer le fichier',
94
- 'library.del': 'SUPPR',
95
- 'toast.assetDeleted': '{name} supprimé',
96
- 'modal.export': 'Exporter',
97
- 'modal.exportTitle': 'HTML d’e-mail basé sur des tableaux',
98
- 'export.copy': 'Copier',
99
- 'export.copied': 'Copié',
100
- 'action.download': 'Télécharger',
101
- 'export.meta': '{kb} Ko · tableaux + styles en ligne · largeurs sûres pour Outlook',
102
- 'modal.rawHtmlTitle': 'HTML brut, aperçu en direct',
103
- 'code.statusEdited': 'Vue du code modifié aperçu en direct, pas encore appliqué',
104
- 'code.statusSynced': 'Vue du code synchronisé avec le canevas',
105
- 'action.reload': 'Recharger',
106
- 'action.reloadHint': 'Recharger la source depuis le canevas',
107
- 'action.applyToCanvas': 'Appliquer au canevas',
108
- 'action.applyToCanvasHint': 'Analyser la source pour la reconvertir en lignes modifiables',
109
- 'action.closeWithoutApplyingHint': 'Fermer sans appliquer',
110
- 'code.source': 'Source',
111
- 'code.livePreview': 'Aperçu en direct',
112
- 'code.liveHtmlPreviewTitle': 'Aperçu HTML en direct',
113
- 'code.applyNote':
114
- 'Appliquer analyse chaque ligne de tableau de premier niveau en une ligne de canevas que vous pouvez toujours sélectionner, réorganiser et supprimer le balisage écrit à la main survit à l’aller-retour.',
115
- 'code.meta': '{kb} Ko · {lines} lignes',
116
- 'toast.sourceReloaded': 'Source rechargée depuis le canevas',
117
- 'toast.sourceAppliedOne': 'Source appliquée — 1 ligne sur le canevas',
118
- 'toast.sourceAppliedMany': 'Source appliquée — {rows} lignes sur le canevas',
119
- 'toast.parseError': 'Impossible d’analyser ce HTML',
120
- 'modal.copyAssist': 'Assistant de rédaction',
121
- 'modal.draftCopyTitle': 'Rédiger le texte de cette campagne',
122
- 'ai.goal': 'Objectif',
123
- 'ai.tone': 'Ton',
124
- 'ai.briefLabel': 'De quoi parle cet e-mail ?',
125
- 'ai.briefPlaceholder': 'ex. Collection automne, 15 % pour les abonnés, livraison gratuite dès 150 €',
126
- 'ai.generate': 'Générer le texte',
127
- 'ai.writing': 'Rédaction en cours…',
128
- 'ai.kindHeadline': 'Titre',
129
- 'ai.kindBody': 'Corps du texte',
130
- 'ai.kindButton': 'Texte du bouton',
131
- 'ai.actionInsertHeading': 'Insérer comme titre',
132
- 'ai.actionInsertText': 'Insérer comme bloc de texte',
133
- 'ai.actionInsertButton': 'Insérer comme bouton',
134
- 'toast.headingAdded': 'Titre ajouté',
135
- 'toast.textBlockAdded': 'Bloc de texte ajouté',
136
- 'toast.buttonAdded': 'Bouton ajouté',
137
- 'preview.kickerMobile': 'Aperçumobile 375px',
138
- 'preview.kickerDark': 'Aperçu boîte de réception sombre',
139
- 'preview.kickerDesktop': 'Aperçu bureau {width}px',
140
- 'action.close': 'Fermer',
141
- 'toast.duplicated': 'Dupliqué',
142
- 'toast.fileUploadedOne': '1 fichier téléversé',
143
- 'toast.fileUploadedMany': '{count} fichiers téléversés',
144
- 'toast.imageReplaced': 'Image remplacée',
145
- 'toast.imageAdded': 'Image ajoutée au canevas',
146
- 'toast.htmlCopied': 'HTML copié dans le presse-papiers',
147
- 'toast.templateLoaded': '{name} chargé',
148
- 'toast.snippetDefaultLabel': 'Extrait',
149
- 'toast.snippetInserted': '{name} inséré',
150
- 'toast.snippetCopied': '{name} copié — sélectionnez un bloc de texte pour l’insérer',
151
- };
152
-
1
+ /** French (Français) — `fr`. AI-drafted, not reviewed by a native speaker. Correctable one key at a time via `.messages` overrides. */
2
+ export const FR = {
3
+ 'action.undoHint': 'Annuler — ⌘Z',
4
+ 'action.redoHint': 'Rétablir — ⌘⇧Z',
5
+ 'action.chromeToDark': 'Sombre',
6
+ 'action.chromeToLight': 'Clair',
7
+ 'action.chromeHint': 'Thème de l’éditeur clair / sombre',
8
+ 'action.chromeHintToDark': 'Mode sombre',
9
+ 'action.chromeHintToLight': 'Mode clair',
10
+ 'action.aiDraft': 'Brouillon',
11
+ 'action.aiDraftHint': 'Rédiger le contenu de l’e-mail avec l’IA',
12
+ 'action.code': 'Code',
13
+ 'action.codeHint': 'Modifier le HTML brut avec aperçu en direct',
14
+ 'action.preview': 'Aperçu',
15
+ 'action.previewHint': 'Prévisualiser l’e-mail',
16
+ 'action.export': 'Exporter',
17
+ 'action.exportHint': 'Exporter votre e-mail',
18
+ 'device.desktop': 'Bureau',
19
+ 'device.desktopHint': 'Largeur bureau',
20
+ 'device.mobile': 'Mobile',
21
+ 'device.mobileHint': 'Largeur mobile',
22
+ 'status.autosaveOn': 'sauvegarde automatique activée',
23
+ 'status.saved': 'enregistré {time}',
24
+ 'status.saveFailed': 'non enregistré — stockage plein',
25
+ 'canvas.meta': '{rows} lignes · {blocks} blocs · {width}px',
26
+ 'tab.design': 'Style',
27
+ 'tab.designHint': 'Styliser la sélection',
28
+ 'tab.blocks': 'Blocs',
29
+ 'tab.blocksHint': 'Blocs de contenu et variables',
30
+ 'tab.rows': 'Sect.',
31
+ 'tab.rowsHint': 'Mises en page de section et modèle de canevas',
32
+ 'tab.files': 'Fichiers',
33
+ 'tab.filesHint': 'Bibliothèque de ressources',
34
+ 'tab.layers': 'Structure',
35
+ 'tab.layersHint': 'Structure du document',
36
+ 'tab.settings': 'Paramètres',
37
+ 'tab.settingsHint': 'Paramètres de l’e-mail',
38
+ 'tab.data': 'Var.',
39
+ 'tab.dataHint': 'Variables fournies par votre code',
40
+ 'inspector.blockProperties': 'Propriétés du bloc',
41
+ 'inspector.sectionProperties': 'Propriétés de la section',
42
+ 'inspector.title': 'Inspecteur',
43
+ 'inspector.sectionLabel': 'Section',
44
+ 'inspector.nothingSelected': 'Rien n’est sélectionné',
45
+ 'action.duplicateHint': 'Dupliquer — ⌘D',
46
+ 'action.deleteHint': 'Supprimer ',
47
+ 'inspector.emptyBody':
48
+ 'Sélectionnez une ligne ou un bloc sur le canevas pour le styliser ici. Glissez des blocs depuis l’onglet <strong style="color: var(--ed-text); font-weight: 600;">Blocs</strong> ; double-cliquez sur un texte pour le modifier directement.',
49
+ 'inspector.shortcuts': 'Raccourcis',
50
+ 'shortcut.undoRedo': '⌘Z / ⌘⇧Z annuler, rétablir',
51
+ 'shortcut.duplicate': '⌘Ddupliquer la sélection',
52
+ 'shortcut.delete': 'supprimer la sélection',
53
+ 'shortcut.export': '⌘E exporter le HTML',
54
+ 'shortcut.escape': 'ESC — désélectionner, fermer',
55
+ 'blocks.dragHint': 'Glisser sur le canevas',
56
+ 'blocks.count': '{count} blocs',
57
+ 'rows.sectionLayouts': 'Mises en page de section',
58
+ 'rows.customMarkup': 'Balisage personnalisé',
59
+ 'rows.htmlRowHint': 'Glissez pour insérer, ou cliquez pour ajouter — une ligne pleine largeur que vous remplissez de HTML brut',
60
+ 'rows.rawHtmlSection': 'Section HTML brut',
61
+ 'rows.rawHtmlDesc': 'Section pleine largeur, votre propre balisage, toujours déplaçable',
62
+ 'rows.canvasModel': 'Modèle de canevas',
63
+ 'rows.modeRowBased': 'Basé sur les lignes',
64
+ 'rows.modeFreeStack': 'Pile libre',
65
+ 'rows.hintRows':
66
+ 'Basé sur les sections : déposez d’abord une mise en page, puis des blocs dans ses colonnes chaque section a son propre arrière-plan, sa bordure, ses réglages flex ou grille.',
67
+ 'rows.hintStack': 'Pile libre : sans mise en page — chaque bloc déposé devient sa propre section pleine largeur, empilée dans l’ordre.',
68
+ 'files.libraryCount': 'Bibliothèque {count} fichiers',
69
+ 'files.openManager': 'Ouvrir le gestionnaire de fichiers',
70
+ 'files.dragToCanvas': 'Glissez un fichier directement sur le canevas pour le placer comme bloc image.',
71
+ 'layers.structure': 'Structure',
72
+ 'layers.sectionSingle': 'Section',
73
+ 'layers.sectionMulti': 'Section · {count} col.',
74
+ 'layers.column': 'Colonne {index}',
75
+ 'layers.blockCount': '{count} blocs',
76
+ 'vars.title': 'Variables',
77
+ 'vars.fromCode': '{count} provenant de votre code',
78
+ 'vars.declaredNote': 'Déclarées par votre application le canevas affiche toujours le jeton, jamais une valeur.',
79
+ 'vars.filterPlaceholder': 'Filtrer les variables…',
80
+ 'vars.insertHint': 'Cliquer pour insérer dans le texte, le titre ou le bouton sélectionné',
81
+ 'vars.insert': 'insérer',
82
+ 'vars.noMatch': 'Aucune variable ne correspond à ce filtre.',
83
+ 'vars.noneDeclared': 'Votre application n’a encore déclaré aucune variable.',
84
+ 'vars.rteHint': 'En modifiant du texte, vous pouvez aussi choisir une variable directement dans le menu de la barre d’outils.',
85
+ 'modal.fileManager': 'Gestionnaire de fichiers',
86
+ 'modal.assetsTitle': 'Ressources',
87
+ 'modal.replaceImage': 'Remplacer l’image',
88
+ 'library.searchPlaceholder': 'Rechercher des fichiers…',
89
+ 'action.upload': 'Téléverser',
90
+ 'library.clickToPlace': 'Cliquez sur un fichier pour le placer · ou glissez un fichier sur le canevas',
91
+ 'library.clickToReplace': 'Cliquez sur un fichier pour remplacer l’image sélectionnée',
92
+ 'library.storageLabel': '{count} fichiers · {size}',
93
+ 'library.folders': 'Dossiers',
94
+ 'library.dropHint': 'Déposez des fichiers image ici pour les téléverser — ou utilisez le bouton Téléverser.',
95
+ 'library.deleteFileHint': 'Supprimer le fichier',
96
+ 'library.del': 'SUPPR',
97
+ 'toast.assetDeleted': '{name} supprimé',
98
+ 'library.allFiles': 'Tous les fichiers',
99
+ 'library.loadMore': 'Charger plus',
100
+ 'library.empty': 'Aucun fichier ici pour l’instant.',
101
+ 'storage.loading': 'Chargement des fichiers…',
102
+ 'storage.uploading': 'Envoi de {count}…',
103
+ 'storage.errLoadFailed': 'La bibliothèque de fichiers n’a pas pu être chargée {reason}',
104
+ 'storage.errNoLimits': 'Les envois sont désactivés : cette application n’a défini aucune limite d’envoi.',
105
+ 'storage.errNoAccept': 'Les envois sont désactivés : aucun format de fichier n’a été autorisé.',
106
+ 'storage.errNoMaxBytes': 'Les envois sont désactivés : aucune taille maximale de fichier n’a été définie.',
107
+ 'storage.errTooLarge': '{name} fait {size} — la limite est {max}.',
108
+ 'storage.errFormat': '{name} est un fichier {type}, non autorisé ici.',
109
+ 'storage.errSvg': '{name} est un SVG, que cette application n’accepte pas.',
110
+ 'storage.errDimensions': '{name} fait {w}×{ht}px — la limite est {maxW}×{maxH}px.',
111
+ 'storage.errTooMany': 'Seuls {max} fichiers peuvent être envoyés à la fois.',
112
+ 'storage.errUnreadable': '{name} n’est pas une image lisible.',
113
+ 'storage.errUploadFailed': '{name} n’a pas pu être envoyé — {reason}',
114
+ 'storage.errDeleteFailed': '{name} n’a pas pu être supprimé{reason}',
115
+ 'modal.export': 'Exporter',
116
+ 'modal.exportTitle': 'HTML d’e-mail basé sur des tableaux',
117
+ 'export.copy': 'Copier',
118
+ 'export.copied': 'Copié',
119
+ 'action.download': 'Télécharger',
120
+ 'export.meta': '{kb} Ko · tableaux + styles en ligne · largeurs sûres pour Outlook',
121
+ 'modal.rawHtmlTitle': 'HTML brut, aperçu en direct',
122
+ 'code.statusEdited': 'Vue du code — modifié — aperçu en direct, pas encore appliqué',
123
+ 'code.statusSynced': 'Vue du code — synchronisé avec le canevas',
124
+ 'action.reload': 'Recharger',
125
+ 'action.reloadHint': 'Recharger la source depuis le canevas',
126
+ 'action.applyToCanvas': 'Appliquer au canevas',
127
+ 'action.applyToCanvasHint': 'Analyser la source pour la reconvertir en lignes modifiables',
128
+ 'action.closeWithoutApplyingHint': 'Fermer sans appliquer',
129
+ 'code.source': 'Source',
130
+ 'code.livePreview': 'Aperçu en direct',
131
+ 'code.liveHtmlPreviewTitle': 'Aperçu HTML en direct',
132
+ 'code.applyNote':
133
+ 'Appliquer analyse chaque ligne de tableau de premier niveau en une ligne de canevas que vous pouvez toujours sélectionner, réorganiser et supprimer — le balisage écrit à la main survit à l’aller-retour.',
134
+ 'code.meta': '{kb} Ko · {lines} lignes',
135
+ 'toast.sourceReloaded': 'Source rechargée depuis le canevas',
136
+ 'toast.sourceAppliedOne': 'Source appliquée — 1 ligne sur le canevas',
137
+ 'toast.sourceAppliedMany': 'Source appliquée {rows} lignes sur le canevas',
138
+ 'toast.parseError': 'Impossible d’analyser ce HTML',
139
+ 'modal.aiDraft': 'Assistant de rédaction IA',
140
+ 'modal.aiDraftTitle': 'Rédigez votre e-mail avec l’IA',
141
+ 'ai.disclosure': 'L’IA crée des suggestions à partir de votre brief. Relisez et modifiez le résultat avant l’envoi.',
142
+ 'ai.goal': 'Objectif',
143
+ 'ai.tone': 'Ton',
144
+ 'ai.briefLabel': 'De quoi parle cet e-mail ?',
145
+ 'ai.briefPlaceholder': 'ex. Collection automne, 15 % pour les abonnés, livraison gratuite dès 150 €',
146
+ 'ai.generate': 'Générer le texte',
147
+ 'ai.writing': 'Rédaction en cours…',
148
+ 'ai.kindHeadline': 'Titre',
149
+ 'ai.kindBody': 'Corps du texte',
150
+ 'ai.kindButton': 'Texte du bouton',
151
+ 'ai.actionInsertHeading': 'Insérer comme titre',
152
+ 'ai.actionInsertText': 'Insérer comme bloc de texte',
153
+ 'ai.actionInsertButton': 'Insérer comme bouton',
154
+ 'toast.headingAdded': 'Titre ajouté',
155
+ 'toast.textBlockAdded': 'Bloc de texte ajouté',
156
+ 'toast.buttonAdded': 'Bouton ajouté',
157
+ 'preview.kickerMobile': 'Aperçu — mobile 375px',
158
+ 'preview.kickerDesktop': 'Aperçu — bureau {width}px',
159
+ 'action.close': 'Fermer',
160
+ 'toast.duplicated': 'Dupliqué',
161
+ 'toast.fileUploadedOne': '1 fichier téléversé',
162
+ 'toast.fileUploadedMany': '{count} fichiers téléversés',
163
+ 'toast.imageReplaced': 'Image remplacée',
164
+ 'toast.imageAdded': 'Image ajoutée au canevas',
165
+ 'toast.htmlCopied': 'HTML copié dans le presse-papiers',
166
+ 'toast.templateLoaded': '{name} chargé',
167
+ 'toast.snippetDefaultLabel': 'Extrait',
168
+ 'toast.snippetInserted': '{name} inséré',
169
+ 'toast.snippetCopied': '{name} copié — sélectionnez un bloc de texte pour l’insérer',
170
+ 'rte.textStyle': 'Style de texte',
171
+ 'rte.mergeTags': 'Champs de fusion',
172
+ 'rte.noMergeTags': 'Aucun champ de fusion disponible',
173
+ 'rte.textColor': 'Couleur du texte',
174
+ 'rte.highlightColor': 'Couleur de surlignage',
175
+ 'rte.removeHighlight': 'Supprimer le surlignage',
176
+ 'rte.clearFormatting': 'Effacer la mise en forme',
177
+ 'action.downloadPng': 'Télécharger le PNG',
178
+ 'action.screenshot': 'Capture',
179
+ 'action.screenshotHint': 'Voir tout le modèle sous forme d’image, puis le télécharger',
180
+ 'toast.pngSaved': 'Capture téléchargée',
181
+ 'toast.pngFailed': 'Échec de la capture — une image externe n’a pas pu être chargée',
182
+ 'toast.pngCopied': 'Capture copiée dans le presse-papiers',
183
+ 'toast.pngCopyFailed': 'Ce navigateur n’a pas accepté d’image dans le presse-papiers',
184
+ 'story.kicker': 'Capture',
185
+ 'story.rendering': 'Génération de la capture',
186
+ 'story.renderingHint': 'Chaque bloc est dessiné en 2× — sur un long modèle, cela prend un moment.',
187
+ 'story.failed': 'Échec de la capture',
188
+ 'story.failedHint': 'Une image du modèle n’a pas pu être chargée pour la capture.',
189
+ 'story.retry': 'Réessayer',
190
+ 'story.play': 'Lecture',
191
+ 'story.pause': 'Pause',
192
+ 'story.replay': 'Revoir',
193
+ 'story.copy': 'Copier',
194
+ 'story.meta': '{w}×{h} · écran {i} sur {n}',
195
+ 'footer.poweredBy': 'Propulsé par SELISE Blocks © 2026',
196
+ };