Files
ObsiGate/_i18n_final.py
T
bruno 0403be4516
CI / test (push) Has been cancelled
CI / security (push) Has been cancelled
CI / build (push) Has been cancelled
CI / e2e (push) Has been cancelled
CI / lint (push) Has been cancelled
feat: complete i18n coverage — all dynamic content translated
All remaining French strings converted to t() calls:
- ui.js: create/delete file/dir modals, rename/copy/bookmark toasts
- palette.js: confirm dialogs, error toasts
- search.js: result summary text with interpolation
- config.js: about/diagnostics section labels
- auth.js: admin panel title
- viewer.js: forge popout labels
- dashboard.js: shared widget buttons, date locale-aware

57 new locale keys for dynamic content (modals, toasts, admin, about)
Total: 597 keys per language

All 26 modules validated — 163 exports, 0 errors
2026-06-18 14:18:25 -04:00

203 lines
11 KiB
Python
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.
"""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,
'<h3 class="obsigate-modal-title">Créer un fichier</h3>',
'<h3 class="obsigate-modal-title">${t(\'modal.create_file\')}</h3>'))
R.append((F,
'<label class="modal-label">Nom du fichier</label>',
'<label class="modal-label">${t(\'modal.file_name\')}</label>'))
R.append((F,
'<div class="modal-hint">Dans: ${parentPath',
'<div class="modal-hint">${t(\'modal.in_folder\', {path: parentPath'))
R.append((F,
'<label class="modal-label">Type de fichier</label>',
'<label class="modal-label">${t(\'modal.file_type\')}</label>'))
R.append((F,
'<button class="modal-btn" id="file-cancel-btn">Annuler</button>',
'<button class="modal-btn" id="file-cancel-btn">${t(\'common.cancel\')}</button>'))
R.append((F,
'<button class="modal-btn primary" id="file-create-btn">Créer</button>',
'<button class="modal-btn primary" id="file-create-btn">${t(\'modal.create_btn\')}</button>'))
# 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,
'<h3 class="obsigate-modal-title">Supprimer le dossier</h3>',
'<h3 class="obsigate-modal-title">${t(\'modal.delete_dir\')}</h3>'))
R.append((F,
'<strong>Attention !</strong> Cette action est irréversible.\n <br>Tous les fichiers et sous-dossiers seront supprimés définitivement.',
'<strong>${t(\'modal.delete_warning\')}</strong> ${t(\'modal.delete_irreversible\')}\n <br>${t(\'modal.delete_dir_warning\')}'))
R.append((F,
'<label class="modal-label">Dossier à supprimer:</label>',
'<label class="modal-label">${t(\'modal.dir_to_delete\')}</label>'))
# 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,
'<h3 class="obsigate-modal-title">Supprimer le fichier</h3>',
'<h3 class="obsigate-modal-title">${t(\'modal.delete_file\')}</h3>'))
R.append((F,
'<strong>Attention !</strong> Cette action est irréversible.\n </div>\n </div>\n <div class="modal-form-group">\n <label class="modal-label">Fichier à supprimer:',
'<strong>${t(\'modal.delete_warning\')}</strong> ${t(\'modal.delete_irreversible\')}\n </div>\n </div>\n <div class="modal-form-group">\n <label class="modal-label">${t(\'modal.file_to_delete\')}'))
# Delete file action
R.append((F,
"confirmBtn.textContent = 'Suppression...';\n \n try {\n await api(`/api/file/${encodeURIComponent(vault)}",
"confirmBtn.textContent = t('modal.creating');\n \n try {\n await api(`/api/file/${encodeURIComponent(vault)}"))
R.append((F,
"showToast('Fichier supprimé', 'success');\n this._closeModal(overlay);\n await refreshSidebarTreePreservingState();\n \n if (state.currentVault === vault",
"showToast(t('toast.file_deleted'), 'success');\n this._closeModal(overlay);\n await refreshSidebarTreePreservingState();\n \n if (state.currentVault === vault"))
# ═══════ palette.js ═══════
F = f"{BASE}/palette.js"
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}))"))
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')"))
R.append((F,
"showToast('Aucun fichier ouvert','error')",
"showToast(t('toast.no_open_file'),'error')"))
# ═══════ search.js ═══════
F = f"{BASE}/search.js"
R.append((F,
"summaryText.textContent = `${data.total} résultat(s) pour \"${freeText}\" avec filtres`;",
"summaryText.textContent = t('search.results_filtered', {count: data.total, query: freeText});"))
R.append((F,
"summaryText.textContent = `${data.total} résultat(s) pour \"${freeText}\"`;",
"summaryText.textContent = t('search.results_for', {count: data.total, query: freeText});"))
R.append((F,
"summaryText.textContent = `${data.total} fichier(s) avec filtres`;",
"summaryText.textContent = t('search.files_filtered', {count: data.total});"))
R.append((F,
"summaryText.textContent = `${data.total} résultat(s)`;",
"summaryText.textContent = t('search.results_count', {count: data.total});"))
R.append((F,
"timeBadge.textContent = `(${data.query_time_ms} ms)`;",
"timeBadge.textContent = t('search.query_time', {time: data.query_time_ms});"))
# ═══════ config.js ═══════
F = f"{BASE}/config.js"
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"),'))
for old_lbl, 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_lbl},', f'[t("{key}"),'))
# ═══════ auth.js ═══════
F = f"{BASE}/auth.js"
R.append((F,
"Administration — Utilisateurs",
"' + t('admin.title') + '"))
R.append((F,
"+ Nouvel utilisateur",
"' + t('admin.new_user') + '"))
# ═══════ viewer.js ═══════
F = f"{BASE}/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}/dashboard.js"
R.append((F,
'📋 Copier',
"' + t('dashboard.copy_btn') + '"))
R.append((F,
'📂 Ouvrir',
"' + t('dashboard.open_btn') + '"))
# ── EXECUTE ──
ok = 0
skip = 0
for filepath, find, repl in R:
with open(filepath, "r", encoding="utf-8") as fh:
content = fh.read()
count = content.count(find)
if count == 0:
print(f"SKIP {filepath.split('/')[-1]}: not found — {find[:50]}...")
skip += 1
continue
content = content.replace(find, repl)
with open(filepath, "w", encoding="utf-8") as fh:
fh.write(content)
ok += 1
print(f"OK {filepath.split('/')[-1]}: {count}× {find[:40]}...")
print(f"\nDone: {ok} applied, {skip} skipped")