diff --git a/_batch_i18n.py b/_batch_i18n.py
deleted file mode 100644
index a123258..0000000
--- a/_batch_i18n.py
+++ /dev/null
@@ -1,190 +0,0 @@
-"""Batch i18n: replace all remaining French strings in JS modules with t() calls."""
-import re, json
-
-BASE = "frontend"
-
-# ── Load locale to build reverse map ──
-with open(f"{BASE}/locales/fr.json", encoding="utf-8") as f:
- fr = json.load(f)
-text_to_key = {}
-for k, v in fr.items():
- if k.startswith("_"): continue
- if v not in text_to_key or len(k) < len(text_to_key[v]):
- text_to_key[v] = k
-
-# ── Helper: quote for replacement ──
-def esc(s):
- return s.replace('\\', '\\\\').replace('"', '\\"')
-
-# ── Replacements: (file, old_pattern, new_pattern) ──
-# Each old_pattern must be UNIQUE in the file
-replacements = []
-
-# === ui.js ===
-f = f"{BASE}/js/ui.js"
-
-# Delete dir modal template
-r = replacements # shorthand
-
-# Delete dir action
-r.append((f,
- "confirmBtn.disabled = true;\n confirmBtn.textContent = 'Suppression...';\n \n try {\n const result = await api(`/api/directory",
- "confirmBtn.disabled = true;\n confirmBtn.textContent = t('modal.creating');\n \n try {\n const result = await api(`/api/directory"))
-
-r.append((f,
- "showToast(`Dossier supprimé (${result.deleted_count} fichiers)`, 'success');",
- "showToast(t('toast.dir_deleted', {count: result.deleted_count}), 'success');"))
-
-r.append((f,
- "showToast(err.message || 'Erreur lors de la suppression', 'error');\n confirmBtn.disabled = false;\n confirmBtn.textContent = 'Supprimer définitivement';",
- "showToast(err.message || t('toast.delete_error'), 'error');\n confirmBtn.disabled = false;\n confirmBtn.textContent = t('modal.delete_permanently');"))
-
-# Rename toasts
-r.append((f,
- "showToast(type === 'directory' ? 'Dossier renommé' : 'Fichier renommé', 'success');",
- "showToast(type === 'directory' ? t('toast.dir_renamed') : t('toast.file_renamed'), 'success');"))
-
-r.append((f,
- "showToast(err.message || 'Erreur lors du renommage', 'error');",
- "showToast(err.message || t('toast.rename_error'), 'error');"))
-
-# Copy path toast
-r.append((f,
- "showToast(`Chemin copié : ${path}`, 'success');",
- "showToast(t('toast.path_copied', {path: path}), 'success');"))
-
-r.append((f,
- "showToast('Erreur lors de la copie', 'error');",
- "showToast(t('toast.copy_error'), 'error');"))
-
-# Bookmark toast
-r.append((f,
- 'showToast(data.bookmarked ? "Ajouté aux bookmarks" : "Retiré des bookmarks", "success");',
- 'showToast(data.bookmarked ? t("toast.bookmark_added") : t("toast.bookmark_removed"), "success");'))
-
-# Dir saved search toast
-r.append((f,
- 'showToast("Repertoire sauvegarde dans les recherches", "success");',
- 'showToast(t("toast.dir_saved_search"), "success");'))
-
-# Viewer error toast
-r.append((f,
- 'showToast("Erreur lors du chargement du viewer: " + err.message, "error");',
- 'showToast(t("toast.viewer_error") + ": " + err.message, "error");'))
-
-
-# === palette.js ===
-f = f"{BASE}/js/palette.js"
-pal = text_to_key
-
-# Confirm dialogs
-r.append((f,
- 'confirm(`Supprimer le fichier \\"${path}\\" ?`)',
- 'confirm(t("confirm.delete_file_named", {path: path}))'))
-
-r.append((f,
- 'confirm(`Supprimer \\"${path}\\" et TOUT son contenu ?`)',
- 'confirm(t("confirm.delete_dir_named", {path: path}))'))
-
-# Show toasts
-r.append((f,
- "showToast('Erreur de création','error')",
- "showToast(t('toast.create_error'),'error')"))
-
-r.append((f,
- "showToast('Erreur','error')",
- "showToast(t('common.error'),'error')"))
-
-# === config.js ===
-f = f"{BASE}/js/config.js"
-
-# About sections
-r.append((f,
- 'title: "Application",',
- 'title: t("about.section_app"),'))
-r.append((f,
- 'title: "Environnement",',
- 'title: t("about.section_env"),'))
-r.append((f,
- 'title: "Composants",',
- 'title: t("about.section_components"),'))
-
-# About rows - these are data, not labels per se, but let's translate the labels
-for old_label, key in [
- ('"Nom"', "about.name"), ('"Version"', "about.version"),
- ('"Version API"', "about.api_version"), ('"Statut"', "about.status"),
- ('"Vaults configurés"', "about.vaults_configured"),
- ('"Fichiers indexés"', "about.files_indexed"),
- ('"Navigateur"', "about.browser"), ('"Plateforme"', "about.platform"),
- ('"Langue"', "about.language"), ('"Backend"', "about.backend"),
- ('"Rendu Markdown"', "about.markdown_renderer"),
- ('"Surveillance fichiers"', "about.file_watcher"),
- ('"Frontend"', "about.frontend"), ('"Icônes"', "about.icons"),
- ('"Coloration syntaxe"', "about.syntax_highlight"),
- ('"Éditeur"', "about.editor"),
-]:
- r.append((f, f'[{old_label},', f'[t("{key}"),'))
-
-# Admin-only / no webhooks
-r.append((f,
- "list.innerHTML = '
Admin uniquement
';",
- "list.innerHTML = '' + t('common.loading') + '
';"))
-r.append((f,
- "list.innerHTML = 'Aucun webhook configuré.
';",
- "list.innerHTML = '' + t('common.none') + '
';"))
-
-# === auth.js ===
-f = f"{BASE}/js/auth.js"
-r.append((f,
- 'Administration — Utilisateurs',
- "' + t('admin.title') + '"))
-r.append((f,
- '+ Nouvel utilisateur',
- "' + t('admin.new_user') + '"))
-r.append((f,
- "title=\"Fermer\"",
- "title=\"' + t('common.close') + '\""))
-
-# === viewer.js ===
-f = f"{BASE}/js/viewer.js"
-r.append((f,
- "titleInp.placeholder = 'Titre...'",
- "titleInp.placeholder = t('forge.title_placeholder')"))
-r.append((f,
- "title: \"Ouvrir dans une nouvelle fenetre\"",
- "title: t('forge.popout')"))
-r.append((f,
- 'document.createTextNode("pop-out")',
- 'document.createTextNode(t("forge.popout_label"))'))
-
-# === dashboard.js ===
-f = f"{BASE}/js/dashboard.js"
-r.append((f,
- '"Copier"',
- 't("dashboard.copy_btn")'))
-r.append((f,
- '"Ouvrir"',
- 't("dashboard.open_btn")'))
-
-# === search.js ===
-f = f"{BASE}/js/search.js"
-r.append((f,
- "summaryText.textContent = `${data.total} résultat(s)",
- "summaryText.textContent = t('search.results_count', {count: data.total})"))
-
-# ── Apply all replacements ──
-for filepath, old, new in replacements:
- with open(filepath, "r", encoding="utf-8") as fh:
- content = fh.read()
- count = content.count(old)
- if count == 0:
- print(f"SKIP {filepath}: pattern not found: {old[:60]}...")
- continue
- if count > 1:
- print(f"WARN {filepath}: {count} matches for: {old[:60]}...")
- content = content.replace(old, new)
- with open(filepath, "w", encoding="utf-8") as fh:
- fh.write(content)
- print(f"OK {filepath}: {count} replacement(s)")
-
-print(f"\nTotal replacements applied: {len(replacements)}")
diff --git a/_i18n_final.py b/_i18n_final.py
deleted file mode 100644
index 23ad980..0000000
--- a/_i18n_final.py
+++ /dev/null
@@ -1,202 +0,0 @@
-"""One-pass i18n: replace all French strings in all JS modules."""
-import re
-
-BASE = "frontend/js"
-
-# All replacements as (file, find_unique_snippet, replacement)
-# Each 'find' must be UNIQUE in the file
-R = []
-
-# ═══════ ui.js ═══════
-F = f"{BASE}/ui.js"
-
-# Create file modal template
-R.append((F,
- 'Créer un fichier
',
- '${t(\'modal.create_file\')}
'))
-R.append((F,
- '',
- ''))
-R.append((F,
- 'Dans: ${parentPath',
- '
${t(\'modal.in_folder\', {path: parentPath'))
-R.append((F,
- '',
- ''))
-R.append((F,
- '',
- ''))
-R.append((F,
- '',
- ''))
-
-# Create file action (toasts, textContent)
-R.append((F,
- "createBtn.textContent = 'Création...';\n \n try {\n await api(`/api/file",
- "createBtn.textContent = t('modal.creating');\n \n try {\n await api(`/api/file"))
-R.append((F,
- 'showToast(`Fichier "${name}" créé`, \'success\');\n this._closeModal(overlay);\n await refreshSidebarTreePreservingState();\n openFile(vault, path);',
- 'showToast(t(\'toast.file_created\', {name: name}), \'success\');\n this._closeModal(overlay);\n await refreshSidebarTreePreservingState();\n openFile(vault, path);'))
-R.append((F,
- "showToast(err.message || 'Erreur lors de la création', 'error');\n createBtn.disabled = false;\n createBtn.textContent = 'Créer';\n }\n };\n \n createBtn.addEventListener('click', create);",
- "showToast(err.message || t('toast.create_error'), 'error');\n createBtn.disabled = false;\n createBtn.textContent = t('modal.create_btn');\n }\n };\n \n createBtn.addEventListener('click', create);"))
-
-# Create dir action
-R.append((F,
- "createBtn.textContent = 'Création...';\n \n try {\n await api(`/api/directory",
- "createBtn.textContent = t('modal.creating');\n \n try {\n await api(`/api/directory"))
-R.append((F,
- 'showToast(`Dossier "${name}" créé`, \'success\');\n this._closeModal(overlay);\n await refreshSidebarTreePreservingState();',
- 'showToast(t(\'toast.dir_created\', {name: name}), \'success\');\n this._closeModal(overlay);\n await refreshSidebarTreePreservingState();'))
-R.append((F,
- "showToast(err.message || 'Erreur lors de la création', 'error');\n createBtn.disabled = false;\n createBtn.textContent = 'Créer';\n }\n };\n \n createBtn.addEventListener('click', create);\n cancelBtn.addEventListener('click', () => this._closeModal(overlay));\n \n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') create();\n if (e.key === 'Escape') this._closeModal(overlay);\n });\n },\n\n showCreateFileModal",
- "showToast(err.message || t('toast.create_error'), 'error');\n createBtn.disabled = false;\n createBtn.textContent = t('modal.create_btn');\n }\n };\n \n createBtn.addEventListener('click', create);\n cancelBtn.addEventListener('click', () => this._closeModal(overlay));\n \n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') create();\n if (e.key === 'Escape') this._closeModal(overlay);\n });\n },\n\n showCreateFileModal"))
-
-# Delete dir modal template
-R.append((F,
- '
Supprimer le dossier
',
- '${t(\'modal.delete_dir\')}
'))
-R.append((F,
- 'Attention ! Cette action est irréversible.\n
Tous les fichiers et sous-dossiers seront supprimés définitivement.',
- '${t(\'modal.delete_warning\')} ${t(\'modal.delete_irreversible\')}\n
${t(\'modal.delete_dir_warning\')}'))
-R.append((F,
- '',
- ''))
-
-# Delete dir action
-R.append((F,
- "confirmBtn.textContent = 'Suppression...';\n \n try {\n const result = await api(`/api/directory",
- "confirmBtn.textContent = t('modal.creating');\n \n try {\n const result = await api(`/api/directory"))
-R.append((F,
- "showToast(`Dossier supprimé (${result.deleted_count} fichiers)`, 'success');",
- "showToast(t('toast.dir_deleted', {count: result.deleted_count}), 'success');"))
-R.append((F,
- "showToast(err.message || 'Erreur lors de la suppression', 'error');\n confirmBtn.disabled = false;\n confirmBtn.textContent = 'Supprimer définitivement';\n }\n };\n \n confirmBtn.addEventListener('click', deleteDir);",
- "showToast(err.message || t('toast.delete_error'), 'error');\n confirmBtn.disabled = false;\n confirmBtn.textContent = t('modal.delete_permanently');\n }\n };\n \n confirmBtn.addEventListener('click', deleteDir);"))
-
-# Delete file modal template
-R.append((F,
- 'Supprimer le fichier
',
- '${t(\'modal.delete_file\')}
'))
-R.append((F,
- 'Attention ! Cette action est irréversible.\n \n
\n \n
\n \n \n \n