627 lines
33 KiB
Python
627 lines
33 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""Nouveau contenu du Guide d'utilisation (#105) — source unique de vérité.
|
||
|
||
Rôles :
|
||
1. ``CONTENT`` : dictionnaire i18n clé -> (fr, en). Les locales FR/EN sont
|
||
générées depuis ce dictionnaire par ``scripts/merge_guide_locales.py``
|
||
(ne jamais éditer les blocs ``guide105.*`` des JSON à la main).
|
||
2. Les constantes ``SECTION_*`` / ``EXTRA_BLOCKS`` / ``TOC_INSERT_BEFORE``
|
||
décrivent le HTML à insérer dans ``frontend/index.html`` par
|
||
``scripts/insert_guide_sections.py``. Le texte FR inline de chaque
|
||
élément portant ``data-i18n="guide105.X"`` DOIT être identique à
|
||
``CONTENT[X][0]`` (sinon ``_applyDOM`` afficherait un texte incohérent
|
||
quand la locale FR est appliquée).
|
||
|
||
Règle i18n : tout élément textuel des nouvelles sections porte une clé
|
||
``guide105.*``. Les clés préexistantes ne sont jamais réutilisées avec un
|
||
texte différent.
|
||
"""
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Dictionnaire i18n (clé -> FR, EN)
|
||
# ---------------------------------------------------------------------------
|
||
|
||
CONTENT: dict[str, tuple[str, str]] = {
|
||
# -- TOC / titres de sections ---------------------------------------------
|
||
"nav_architecture": ("🏗️ Architecture", "🏗️ Architecture"),
|
||
"nav_library": ("⭐ Bibliothèque", "⭐ Library"),
|
||
"nav_diagrams": ("📊 Diagrammes", "📊 Diagrams"),
|
||
"nav_offline": ("📴 Hors-ligne", "📴 Offline"),
|
||
"nav_collab": ("👥 Collaboration", "👥 Collaboration"),
|
||
"nav_desktop": ("🖥️ Desktop", "🖥️ Desktop"),
|
||
"nav_api": ("🔌 API", "🔌 API"),
|
||
"nav_languages": ("🌍 Multilingue", "🌍 Languages"),
|
||
|
||
# -- Section Architecture ---------------------------------------------------
|
||
"arch_intro": (
|
||
"ObsiGate est une application web complète construite en couches indépendantes, sans base"
|
||
" de données externe : les notes vivent dans vos dossiers Obsidian, l'état applicatif dans"
|
||
" des fichiers JSON de <code>data/</code>, l'index de recherche en mémoire.",
|
||
"ObsiGate is a full web application built as independent layers, with no external"
|
||
" database: notes live in your Obsidian folders, app state in JSON files under"
|
||
" <code>data/</code>, the search index in memory.",
|
||
),
|
||
"arch_diagram_note": (
|
||
"Le diagramme est interactif dans l'application : zoom, plein écran, copie SVG ou code.",
|
||
"The diagram is interactive in the app: zoom, fullscreen, copy SVG or code.",
|
||
),
|
||
"arch_h3_layers": ("Les grandes composantes", "The main components"),
|
||
"arch_lbl_fe": ("Frontend", "Frontend"),
|
||
"arch_fe": (
|
||
" — SPA en JavaScript vanilla (modules ES), sans framework ni build npm :"
|
||
" <code>frontend/js/</code> (~30 modules). Le CSS utilise des variables pour les thèmes.",
|
||
" — vanilla-JavaScript SPA (ES modules), no framework, no npm build:"
|
||
" <code>frontend/js/</code> (~30 modules). CSS variables drive the themes.",
|
||
),
|
||
"arch_lbl_be": ("Backend", "Backend"),
|
||
"arch_be": (
|
||
" — serveur FastAPI (Python 3.11) : rendu markdown (mistune + wikilinks),"
|
||
" recherche TF-IDF stemmisée (index inversé en mémoire), watchers watchdog, JWT +"
|
||
" Argon2id, webhooks HMAC, export PDF (WeasyPrint).",
|
||
" — FastAPI server (Python 3.11): markdown rendering (mistune + wikilinks), stemmed"
|
||
" TF-IDF search (in-memory inverted index), watchdog file watchers, JWT + Argon2id,"
|
||
" HMAC webhooks, PDF export (WeasyPrint).",
|
||
),
|
||
"arch_lbl_realtime": ("Temps réel & MCP", "Realtime & MCP"),
|
||
"arch_rt": (
|
||
" — passerelle WebSocket (collaboration Yjs, notifications SSE/push) et serveur MCP"
|
||
" (Streamable HTTP, <code>/mcp</code>) pour les clients externes.",
|
||
" — WebSocket gateway (Yjs collaboration, SSE/push notifications) and an MCP server"
|
||
" (Streamable HTTP, <code>/mcp</code>) for external clients.",
|
||
),
|
||
"arch_lbl_ai": ("Couche IA", "AI layer"),
|
||
"arch_ai": (
|
||
" — assistants d'édition et BooksLM multi-providers (DeepSeek, OpenRouter, Gemini,"
|
||
" Mistral…), bibliothèque d'outils (function calling, recherche web, crawl, lecture de"
|
||
" documents) et embeddings optionnels pour la recherche sémantique.",
|
||
" — editor assistant and BooksLM with multiple providers (DeepSeek, OpenRouter, Gemini,"
|
||
" Mistral…), a tool library (function calling, web search, crawl, document reading) and"
|
||
" optional embeddings for semantic search.",
|
||
),
|
||
"arch_lbl_data": ("Données", "Data"),
|
||
"arch_data": (
|
||
" — les vaults Obsidian sur disque (source de vérité), la configuration en JSON"
|
||
" (<code>data/</code>), les backups horodatés (<code>.obsigate-backup/</code>),"
|
||
" l'audit en JSON lines, les clés API chiffrées dans <code>data/api_keys.json</code>.",
|
||
" — Obsidian vaults on disk (the source of truth), JSON configuration"
|
||
" (<code>data/</code>), timestamped backups (<code>.obsigate-backup/</code>), a JSON-lines"
|
||
" audit log, encrypted API keys in <code>data/api_keys.json</code>.",
|
||
),
|
||
"arch_lbl_deploy": ("Déploiement", "Deployment"),
|
||
"arch_deploy": (
|
||
" — application desktop Tauri (Rust) embarquant le backend Python, conteneur Docker, ou"
|
||
" PWA installable dans le navigateur (mode hors-ligne).",
|
||
" — Tauri desktop app (Rust) embedding the Python backend, a Docker container, or an"
|
||
" installable PWA in the browser (offline mode).",
|
||
),
|
||
"arch_h3_flux": ("Flux typique", "Typical request flow"),
|
||
"arch_flux": (
|
||
" Un clic sur un fichier émet <code>GET /api/file/...</code> ; le backend résout le chemin"
|
||
" en sécurité, parse le frontmatter, rend le markdown et renvoie le HTML ; le frontend"
|
||
" enrichit l'affichage (Mermaid, coloration, wikilinks cliquables). Chaque écriture crée"
|
||
" un backup avant application.",
|
||
" Clicking a file issues <code>GET /api/file/...</code>; the backend resolves the path"
|
||
" safely, parses frontmatter, renders the markdown and returns HTML; the frontend"
|
||
" enriches the view (Mermaid, syntax highlighting, clickable wikilinks). Every write"
|
||
" creates a backup before applying.",
|
||
),
|
||
|
||
# -- Section Diagrammes ---------------------------------------------------------
|
||
"dia_intro": (
|
||
"Les blocs <code>```mermaid</code> de vos notes sont rendus en diagrammes interactifs"
|
||
" (Mermaid v11, chargé depuis un CDN).",
|
||
"<code>```mermaid</code> blocks in your notes render as interactive diagrams (Mermaid v11,"
|
||
" loaded from a CDN).",
|
||
),
|
||
"dia_zoom": ("Zoom : boutons + / − dans la barre d'outils du diagramme.",
|
||
"Zoom: + / − buttons in the diagram toolbar."),
|
||
"dia_fs": ("Plein écran : idéal pour les grandes matrices.",
|
||
"Fullscreen: ideal for large charts."),
|
||
"dia_copy": ("Copie : exportez le SVG ou le code source (boutons dédiés).",
|
||
"Copy: export the SVG or the source code (dedicated buttons)."),
|
||
"dia_toggle": ("Bascule Aperçu / Code pour éditer la source sans quitter la vue.",
|
||
"Preview / Code toggle to edit the source without leaving the view."),
|
||
"dia_theme": ("Thème : le diagramme suit le thème clair/sombre de l'application.",
|
||
"Theme: the diagram follows the app's light/dark theme."),
|
||
"dia_types": (
|
||
"Types supportés : flowchart, sequence, class, state, ER, gantt, pie, journey, quadrant,"
|
||
" radar, mindmap, timeline, C4, xychart, sankey — plus un préprocesseur qui comprend la"
|
||
" syntaxe Obsidian.",
|
||
"Supported types: flowchart, sequence, class, state, ER, gantt, pie, journey, quadrant,"
|
||
" radar, mindmap, timeline, C4, xychart, sankey — plus a preprocessor that understands"
|
||
" Obsidian syntax.",
|
||
),
|
||
"dia_excalidraw_ref": (
|
||
"Les dessins à main levée (<code>.excalidraw</code>, <code>.excalidraw.md</code>) sont"
|
||
" couverts dans la section 🎨 Excalidraw.",
|
||
"Hand-drawn sketches (<code>.excalidraw</code>, <code>.excalidraw.md</code>) are covered"
|
||
" in the 🎨 Excalidraw section.",
|
||
),
|
||
|
||
# -- Section Bibliothèque & signets ---------------------------------------------
|
||
"lib_h3_bookmarks": ("Signets & récents", "Bookmarks & recents"),
|
||
"lib_bookmarks": (
|
||
"Marquez un fichier d'un ★ (bouton Signet de la barre d'actions) : il rejoint la liste"
|
||
" des signets du dashboard. Les fichiers récemment ouverts sont listés automatiquement"
|
||
" dans l'onglet « Récents » de la sidebar, avec un filtre de recherche dédié.",
|
||
"Star a file with the Bookmark button in the action bar: it joins the dashboard's"
|
||
" bookmark list. Recently opened files are listed automatically in the sidebar's"
|
||
" \"Recent\" tab, with a dedicated search filter.",
|
||
),
|
||
"lib_h3_saved": ("Recherches sauvegardées", "Saved searches"),
|
||
"lib_saved": (
|
||
"Enregistrez une recherche depuis la page de résultats pour la relancer en un clic depuis"
|
||
" la sidebar : chaque recherche sauvegardée conserve ses opérateurs et filtres.",
|
||
"Save a search from the results page to rerun it in one click from the sidebar: each saved"
|
||
" search keeps its operators and filters.",
|
||
),
|
||
"lib_h3_backlinks": ("Backlinks & graphe", "Backlinks & graph"),
|
||
"lib_backlinks": (
|
||
"Le panneau Backlinks liste toutes les notes qui pointent vers le fichier ouvert. La vue"
|
||
" Graphe (bouton 🕸️) affiche les liens entre fichiers : glissez les nœuds, zoomez à la"
|
||
" molette, double-cliquez pour ouvrir une note.",
|
||
"The Backlinks panel lists every note pointing to the open file. The Graph view (🕸️"
|
||
" button) shows links between files: drag nodes, scroll to zoom, double-click a node to"
|
||
" open the note.",
|
||
),
|
||
"lib_h3_conflicts": ("Conflits de synchronisation", "Sync conflicts"),
|
||
"lib_conflicts": (
|
||
"Si vous synchronisez le vault avec Syncthing, ObsiGate détecte les fichiers de conflit"
|
||
" (copies « sync-conflict ») et propose de les comparer puis résoudre depuis la page"
|
||
" dédiée du menu Options.",
|
||
"If you sync the vault with Syncthing, ObsiGate detects conflict files"
|
||
" (\"sync-conflict\" copies) and offers to compare then resolve them from a dedicated"
|
||
" page in the Options menu.",
|
||
),
|
||
"lib_h3_attach": ("Fichiers joints & médias", "Attachments & media"),
|
||
"lib_attach": (
|
||
"Les images <code>![[image.png]]</code>, pièces jointes et médias (audio, vidéo, PDF"
|
||
" intégrés) dans les notes sont rendus dans le viewer et indexés pour la recherche ; le"
|
||
" bouton « Rescan attachments » de la configuration recrée l'index des pièces jointes.",
|
||
"Inline <code>![[image.png]]</code> images, attachments and media (audio, video, embedded"
|
||
" PDFs) are rendered in the viewer and indexed for search; the \"Rescan attachments\""
|
||
" button in Configuration rebuilds the attachment index.",
|
||
),
|
||
|
||
# -- Section Hors-ligne -----------------------------------------------------------
|
||
"off_pwa": (
|
||
"ObsiGate est une PWA : installez-la (icône d'installation de la barre d'adresse) pour"
|
||
" l'ouvrir comme une application. Le service worker met en cache l'interface et vos"
|
||
" derniers documents consultés.",
|
||
"ObsiGate is a PWA: install it (install icon in the address bar) to open it like an app."
|
||
" The service worker caches the UI and your recently viewed documents.",
|
||
),
|
||
"off_edit": (
|
||
"Hors-ligne, vous pouvez lire les documents en cache et même les éditer : les"
|
||
" modifications sont mises en file d'attente dans IndexedDB.",
|
||
"Offline you can read cached documents and even edit them: changes are queued in"
|
||
" IndexedDB.",
|
||
),
|
||
"off_sync": (
|
||
"Au retour en ligne, la file se rejoue automatiquement (badge de synchronisation dans"
|
||
" l'en-tête). Si la version serveur a divergé entre-temps, le fichier est marqué en"
|
||
" conflit et la version serveur est préservée en backup.",
|
||
"When back online the queue replays automatically (sync badge in the header). If the"
|
||
" server version diverged meanwhile, the file is flagged as conflict and the server copy"
|
||
" is kept as a backup.",
|
||
),
|
||
"off_watch": (
|
||
"Les modifications externes (Obsidian sur disque) sont détectées par le watcher : la vue"
|
||
" se recharge sans perte de position, ou signale « modifié en externe » pendant une"
|
||
" édition.",
|
||
"External changes (Obsidian on disk) are detected by the watcher: the view reloads"
|
||
" without losing your position, or flags \"modified externally\" during an edit.",
|
||
),
|
||
|
||
# -- Section Collaboration ----------------------------------------------------------
|
||
"col_intro": (
|
||
"Ouvrez un document en mode Édition : plusieurs personnes peuvent travailler"
|
||
" simultanément sur le même fichier via un WebSocket Yjs (CRDT). Les modifications"
|
||
" fusionnent sans verrou.",
|
||
"Open a document in Edit mode: several people can work on the same file simultaneously"
|
||
" over a Yjs (CRDT) WebSocket. Changes merge without locks.",
|
||
),
|
||
"col_cursors": (
|
||
"Les curseurs et sélections des collaborateurs apparaissent avec une couleur et un nom"
|
||
" par personne (awareness).",
|
||
"Collaborators' cursors and selections appear with a per-person colour and name"
|
||
" (awareness).",
|
||
),
|
||
"col_save": (
|
||
"La fusion est persistée côté serveur après 2 s d'inactivité ; chaque écriture crée un"
|
||
" backup horodaté avant application.",
|
||
"The merge is persisted server-side after 2 s of idle; every write creates a timestamped"
|
||
" backup before applying.",
|
||
),
|
||
"col_perm": (
|
||
"Accès limité aux utilisateurs authentifiés disposant de la permission sur la vault.",
|
||
"Limited to authenticated users with permission on the vault.",
|
||
),
|
||
|
||
# -- Section Desktop ------------------------------------------------------------------
|
||
"des_get": (
|
||
"L'application desktop ObsiGate (Tauri) embarque le serveur Python : aucune installation"
|
||
" de Docker nécessaire. Elle se télécharge sur la page des Releases du dépôt et se met à"
|
||
" jour automatiquement (updater signé).",
|
||
"The ObsiGate desktop app (Tauri) embeds the Python server: no Docker install needed."
|
||
" Download it from the repository's Releases page; it auto-updates (signed updater).",
|
||
),
|
||
"des_wizard": (
|
||
"Au premier lancement, un assistant demande le dossier de vos vaults (ou crée un vault de"
|
||
" démonstration). Chaque document peut être détaché en fenêtre native séparée.",
|
||
"On first launch a wizard asks for your vaults folder (or creates a demo vault). Any"
|
||
" document can be detached into its own native window.",
|
||
),
|
||
"des_data": (
|
||
"Les données desktop restent dans le répertoire applicatif ; les vaults pointent sur vos"
|
||
" dossiers existants. Toutes les fonctionnalités web (recherche, IA, partage) sont"
|
||
" disponibles.",
|
||
"Desktop data stays in the app directory; vaults point at your existing folders. Every web"
|
||
" feature (search, AI, sharing) is available.",
|
||
),
|
||
"des_native": (
|
||
"Menu système natif, raccourci global optionnel pour afficher/masquer la fenêtre et"
|
||
" jumplist des vaults récents.",
|
||
"Native system menu, optional global show/hide shortcut and a recents vault jumplist.",
|
||
),
|
||
|
||
# -- Section API ------------------------------------------------------------------------
|
||
"api_intro": (
|
||
"ObsiGate expose une API REST couvrant toute l'application (vaults, fichiers, recherche,"
|
||
" backups, export, IA, partage, admin), documentée en OpenAPI 3.1 :",
|
||
"ObsiGate exposes a REST API covering the whole application (vaults, files, search,"
|
||
" backups, export, AI, sharing, admin), documented in OpenAPI 3.1:",
|
||
),
|
||
"api_docs_url": (
|
||
"<code>/docs</code> — interface Swagger UI pour essayer les requêtes en direct.",
|
||
"<code>/docs</code> — Swagger UI to try requests live.",
|
||
),
|
||
"api_redoc": (
|
||
"<code>/redoc</code> — référence alternative plus compacte.",
|
||
"<code>/redoc</code> — compact alternative reference.",
|
||
),
|
||
"api_landing": (
|
||
"<code>/api</code> — page de garde regroupant les endpoints par catégorie.",
|
||
"<code>/api</code> — landing page grouping endpoints by category.",
|
||
),
|
||
"api_schema": (
|
||
"<code>/openapi.json</code> — le schéma machine, à importer dans Postman ou Insomnia.",
|
||
"<code>/openapi.json</code> — the machine schema, import into Postman or Insomnia.",
|
||
),
|
||
"api_h3_auth": ("Authentification", "Authentication"),
|
||
"api_auth": (
|
||
"Connectez-vous via <code>POST /api/auth/login</code> pour obtenir un token Bearer (le"
|
||
" même jeton est accepté en cookie HttpOnly, ce qui permet aux clients navigateur"
|
||
' d\'utiliser <code>credentials: "include"</code>). Toutes les routes'
|
||
" <code>/api/*</code> exigent ce jeton sauf mention contraire.",
|
||
"Log in via <code>POST /api/auth/login</code> to get a Bearer token (the same token is"
|
||
" accepted as an HttpOnly cookie, so browser clients can use"
|
||
' <code>credentials: "include"</code>). All <code>/api/*</code> routes require it unless'
|
||
" documented otherwise.",
|
||
),
|
||
"api_h3_mcp": ("Serveur MCP", "MCP server"),
|
||
"api_mcp": (
|
||
"Les outils de l'assistant IA (lire, lister, chercher, ouvrir, écrire…) sont exposés à"
|
||
" tout client MCP (Claude Desktop, Cursor, Cline…) sur"
|
||
" <code>https://votre-instance/mcp</code> avec un token d'API. Configuration et exemples :"
|
||
" <code>docs/MCP_GUIDE.md</code>.",
|
||
"The assistant's tools (read, list, search, open, write…) are exposed to any MCP client"
|
||
" (Claude Desktop, Cursor, Cline…) at <code>https://your-instance/mcp</code> with an API"
|
||
" token. Setup and examples: <code>docs/MCP_GUIDE.md</code>.",
|
||
),
|
||
"api_h3_autom": ("Automatisation", "Automation"),
|
||
"api_autom": (
|
||
"Pour automatiser depuis l'extérieur : <code>GET /api/search?q=…</code> et"
|
||
" <code>GET /api/file/{vault}?path=…</code> permettent d'indexer ou relire vos notes dans"
|
||
" un autre outil ; les webhooks sortants (section 🪝) évitent le polling.",
|
||
"To automate from outside: <code>GET /api/search?q=…</code> and"
|
||
" <code>GET /api/file/{vault}?path=…</code> let another tool index or re-read your notes;"
|
||
" outgoing webhooks (🪝 section) avoid polling.",
|
||
),
|
||
|
||
# -- Section Multilingue -------------------------------------------------------------------
|
||
"lng_how": (
|
||
"L'interface est intégralement bilingue français / anglais. Réglages → Profil → Langue :"
|
||
" le choix est enregistré sur votre compte et vous suit sur tous les appareils.",
|
||
"The interface is fully bilingual FR/EN. Settings → Profile → Language: the choice is"
|
||
" stored on your account and follows you across devices.",
|
||
),
|
||
"lng_scope": (
|
||
"Tout est traduit : menus, messages, notifications, et le présent guide. Les réponses de"
|
||
" l'assistant IA suivent la langue de vos documents.",
|
||
"Everything is translated: menus, messages, notifications, and this guide. AI assistant"
|
||
" answers follow the language of your documents.",
|
||
),
|
||
"lng_export": (
|
||
"Les boutons Markdown / PDF de ce guide téléchargent la version dans votre langue.",
|
||
"This guide's Markdown / PDF buttons download the version in your language.",
|
||
),
|
||
|
||
# -- Compléments dans sections existantes ---------------------------------------------------
|
||
"h3_semantic": ("Recherche sémantique (hybride)", "Semantic search (hybrid)"),
|
||
"sem_p1": (
|
||
"Activez le bouton « S » de la barre de recherche (ou Alt-S) pour combiner TF-IDF et"
|
||
" similarité vectorielle (fusion RRF) : les concepts approchants (« velours » trouve"
|
||
" « tissu doux ») remontent mieux.",
|
||
"Toggle the \"S\" button in the search bar (or Alt-S) to combine TF-IDF with vector"
|
||
" similarity (RRF fusion): near concepts (\"velvet\" finds \"soft fabric\") surface"
|
||
" higher.",
|
||
),
|
||
"sem_p2": (
|
||
"Le moteur d'embeddings (modèle multilingue) est optionnel : sans lui, un repli par hash"
|
||
" conserve une recherche hybride fonctionnelle. Les vecteurs sont recalculés à chaque"
|
||
" indexation du vault.",
|
||
"The embedding engine (multilingual model) is optional: without it a hash fallback keeps"
|
||
" hybrid search working. Vectors are recomputed on each vault reindex.",
|
||
),
|
||
"h3_push": ("Notifications web (push)", "Web notifications (push)"),
|
||
"push_p1": (
|
||
"Autorisez les notifications (bouton 🔔 de l'en-tête) pour être averti des fins de"
|
||
" synchronisation hors-ligne et des événements importants. La gestion des abonnements est"
|
||
" dans les Configurations.",
|
||
"Grant notification permission (🔔 button in the header) to be alerted of offline-sync"
|
||
" completions and important events. Subscription management lives in Configuration.",
|
||
),
|
||
"push_p2": (
|
||
"Basée sur la Web Push API (clés VAPID) ; fonctionne sur desktop et PWA mobile, sans"
|
||
" service tiers : le serveur émet directement vers les endpoints push des navigateurs.",
|
||
"Built on the Web Push API (VAPID keys); works on desktop and mobile PWA with no"
|
||
" third-party service: the server sends directly to browser push endpoints.",
|
||
),
|
||
"h3_panes": ("Vue multi-panneaux (split view)", "Multi-pane split view"),
|
||
"panes_p": (
|
||
"Le bouton « Diviser » de la barre d'actions ouvre le document dans un panneau jumeau ;"
|
||
" empilez plusieurs panneaux pour comparer deux notes ou lire et éditer en parallèle. Les"
|
||
" largeurs se règlent au bord des panneaux et sont mémorisées.",
|
||
"The \"Split\" button in the action bar opens the document in a twin pane; stack several"
|
||
" panes to compare two notes or read and edit side by side. Pane widths drag on the"
|
||
" border and are remembered.",
|
||
),
|
||
"h3_dupe": ("Anti-doublons à l'upload", "Duplicate-proof uploads"),
|
||
"dupe_p": (
|
||
"L'upload en masse (glisser-déposer un dossier sur la sidebar) compare chaque fichier au"
|
||
" contenu existant : un fichier déjà présent est ignoré plutôt que dupliqué avec un"
|
||
" suffixe « (1) ». Utile pour restaurer un vault sans créer de doublons.",
|
||
"Bulk upload (drag a folder onto the sidebar) compares each file with existing content: an"
|
||
" already-present file is skipped rather than duplicated with a \"(1)\" suffix. Handy"
|
||
" when restoring a vault.",
|
||
),
|
||
"h3_pdf": ("Export PDF", "PDF export"),
|
||
"pdf_p": (
|
||
"Le bouton « PDF » d'un document le rend avec le même moteur que la vue (WeasyPrint) :"
|
||
" titres, tableaux, listes et code sont conservés. Depuis un lien public, la route"
|
||
" <code>/s/{token}/pdf</code> produit le même PDF.",
|
||
"A document's \"PDF\" button renders it with the same engine as the viewer (WeasyPrint):"
|
||
" headings, tables, lists and code are preserved. From a public link, the"
|
||
" <code>/s/{token}/pdf</code> route produces the same PDF.",
|
||
),
|
||
"h3_exports": ("Export HTML / ePub / ZIP", "HTML / ePub / ZIP export"),
|
||
"exp_p": (
|
||
"Le menu « Exporter » propose trois formats : HTML autonome (fichier unique, images"
|
||
" incluses), ePub pour les liseuses et, pour un dossier, un bundle Markdown en ZIP —"
|
||
" liens et ressources résolus pendant l'export.",
|
||
"The \"Export\" menu offers three formats: standalone HTML (single file, images inlined),"
|
||
" ePub for e-readers and, for a folder, a Markdown ZIP bundle — links and resources"
|
||
" resolved during export.",
|
||
),
|
||
"h3_mfa": ("MFA : TOTP, WebAuthn, codes de secours", "MFA: TOTP, WebAuthn, recovery codes"),
|
||
"mfa_p": (
|
||
"Activez la double authentification dans Réglages → Profil : applications TOTP (Authy,"
|
||
" Aegis…), clés de sécurité et passkeys (WebAuthn, y compris Windows Hello) et 10 codes"
|
||
" de secours à conserver hors ligne. Chaque méthode s'active et se désactive"
|
||
" indépendamment.",
|
||
"Enable two-factor auth in Settings → Profile: TOTP apps (Authy, Aegis…), security keys"
|
||
" and passkeys (WebAuthn, including Windows Hello) and 10 recovery codes to keep offline."
|
||
" Each method can be enabled and disabled independently.",
|
||
),
|
||
"h3_admin": ("Tableau de bord administrateur", "Admin dashboard"),
|
||
"admin_p": (
|
||
"Le rôle admin ouvre une page dédiée <code>/admin.html</code> (bouton du menu Options) :"
|
||
" statut du serveur en direct, utilisateurs, vaults, sessions actives et journal d'audit."
|
||
" Le CRUD utilisateurs est aussi disponible dans les Configurations.",
|
||
"The admin role unlocks a dedicated <code>/admin.html</code> page (Options menu button):"
|
||
" live server status, users, vaults, active sessions and the audit log. User CRUD also"
|
||
" lives in Configuration.",
|
||
),
|
||
|
||
# -- Boutons de téléchargement ---------------------------------------------------------------
|
||
"dl_md_title": ("Télécharger ce guide en Markdown", "Download this guide as Markdown"),
|
||
"dl_pdf_title": ("Télécharger ce guide en PDF", "Download this guide as PDF"),
|
||
# -- Export MD/PDF (côté serveur) -------------------------------------------------------------
|
||
"export_title": ("Guide d'utilisation ObsiGate", "ObsiGate User Guide"),
|
||
"export_footer": (
|
||
"Généré depuis ObsiGate {version} — {date}. Ce document est la copie du guide intégré ;"
|
||
" la version la plus récente est toujours dans l'application.",
|
||
"Generated from ObsiGate {version} — {date}. This document mirrors the in-app guide; the"
|
||
" latest version always lives in the application.",
|
||
),
|
||
}
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Diagramme Mermaid de la section Architecture (également utilisé par l'export)
|
||
# ---------------------------------------------------------------------------
|
||
|
||
ARCH_MERMAID = """flowchart TB
|
||
subgraph client["Clients"]
|
||
UI["SPA vanilla JS\\n(frontend/js)"]
|
||
PWA["PWA hors-ligne\\n(service worker + IndexedDB)"]
|
||
DESK["App desktop Tauri\\n(fenêtre native)"]
|
||
end
|
||
subgraph server["Serveur FastAPI (Python 3.11)"]
|
||
API["REST /api\\nJWT + Argon2id"]
|
||
IDX["Index recherche\\nTF-IDF + embeddings"]
|
||
FS["Accès fichiers\\nwatchdog + safe paths"]
|
||
PDF["Rendu markdown\\nmistune + WeasyPrint"]
|
||
AI["Assistant IA\\nproviders + outils"]
|
||
MCP["Serveur MCP\\n/mcp (HTTP)"]
|
||
WS["WebSocket\\ncollab Yjs + SSE"]
|
||
WH["Webhooks\\nHMAC-SHA256"]
|
||
end
|
||
subgraph data["Données"]
|
||
V1["Vault 1 (dossier)"]
|
||
V2["Vault 2 (dossier)"]
|
||
CFG["data/*.json\\nconfig, users, audit"]
|
||
BK[".obsigate-backup/\\nbackups horodatés"]
|
||
end
|
||
UI -- HTTP --> API
|
||
PWA -- "cache + queue" --> API
|
||
DESK -- embarqué --> API
|
||
API --> IDX
|
||
API --> FS
|
||
API --> PDF
|
||
API --> AI
|
||
MCP --> AI
|
||
WS --> FS
|
||
FS --> V1
|
||
FS --> V2
|
||
IDX --> V1
|
||
IDX --> V2
|
||
BK --> V1
|
||
API --> CFG
|
||
API -- événements --> WH"""
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Constructeurs de HTML (FR inline == CONTENT[key][0] garanti)
|
||
# ---------------------------------------------------------------------------
|
||
|
||
|
||
def section_html(title_key: str, sec_id: str, body: str) -> str:
|
||
"""Nouvelle <section> complète avec son h2 data-i18n."""
|
||
return (
|
||
' <section class="help-section" id="%s">\n'
|
||
' <h2 data-i18n="guide105.%s">%s</h2>\n'
|
||
"%s"
|
||
" </section>\n"
|
||
"\n" % (sec_id, title_key, CONTENT[title_key][0], body)
|
||
)
|
||
|
||
|
||
def _li(key: str) -> str:
|
||
return ' <li data-i18n="guide105.%s">%s</li>\n' % (key, CONTENT[key][0])
|
||
|
||
|
||
def _bullets(keys: list) -> str:
|
||
return " <ul>\n" + "".join(_li(k) for k in keys) + " </ul>\n"
|
||
|
||
|
||
def _p(key: str) -> str:
|
||
return ' <p data-i18n="guide105.%s">%s</p>\n' % (key, CONTENT[key][0])
|
||
|
||
|
||
def _h3(key: str) -> str:
|
||
return ' <h3 data-i18n="guide105.%s">%s</h3>\n' % (key, CONTENT[key][0])
|
||
|
||
|
||
def _pair(label_key: str, text_key: str) -> str:
|
||
"""<li><strong>Label</strong><span> — texte</span></li> (deux clés i18n)."""
|
||
return (
|
||
" <li>\n"
|
||
' <strong data-i18n="guide105.%s">%s</strong>'
|
||
'<span data-i18n="guide105.%s">%s</span>\n'
|
||
" </li>\n"
|
||
% (label_key, CONTENT[label_key][0], text_key, CONTENT[text_key][0])
|
||
)
|
||
|
||
|
||
def _h3p(h3_key: str, *p_keys: str) -> str:
|
||
return _h3(h3_key) + "".join(_p(k) for k in p_keys)
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Les huit nouvelles sections
|
||
# ---------------------------------------------------------------------------
|
||
|
||
SECTION_ARCHITECTURE = section_html(
|
||
"nav_architecture",
|
||
"help-architecture",
|
||
_p("arch_intro")
|
||
+ ' <pre class="mermaid-code"><code class="language-mermaid">%s</code></pre>\n' % ARCH_MERMAID
|
||
+ _p("arch_diagram_note")
|
||
+ _h3("arch_h3_layers")
|
||
+ " <ul>\n"
|
||
+ _pair("arch_lbl_fe", "arch_fe")
|
||
+ _pair("arch_lbl_be", "arch_be")
|
||
+ _pair("arch_lbl_realtime", "arch_rt")
|
||
+ _pair("arch_lbl_ai", "arch_ai")
|
||
+ _pair("arch_lbl_data", "arch_data")
|
||
+ _pair("arch_lbl_deploy", "arch_deploy")
|
||
+ " </ul>\n"
|
||
+ _h3p("arch_h3_flux", "arch_flux"),
|
||
)
|
||
|
||
SECTION_DIAGRAMS = section_html(
|
||
"nav_diagrams",
|
||
"help-diagrams",
|
||
_p("dia_intro")
|
||
+ _bullets(["dia_zoom", "dia_fs", "dia_copy", "dia_toggle", "dia_theme"])
|
||
+ _p("dia_types")
|
||
+ _p("dia_excalidraw_ref"),
|
||
)
|
||
|
||
SECTION_LIBRARY = section_html(
|
||
"nav_library",
|
||
"help-library",
|
||
_h3p("lib_h3_bookmarks", "lib_bookmarks")
|
||
+ _h3p("lib_h3_saved", "lib_saved")
|
||
+ _h3p("lib_h3_backlinks", "lib_backlinks")
|
||
+ _h3p("lib_h3_conflicts", "lib_conflicts")
|
||
+ _h3p("lib_h3_attach", "lib_attach"),
|
||
)
|
||
|
||
SECTION_OFFLINE = section_html("nav_offline", "help-offline", _bullets(["off_pwa", "off_edit", "off_sync", "off_watch"]))
|
||
|
||
SECTION_COLLAB = section_html("nav_collab", "help-collab", _bullets(["col_intro", "col_cursors", "col_save", "col_perm"]))
|
||
|
||
SECTION_DESKTOP = section_html("nav_desktop", "help-desktop", _bullets(["des_get", "des_wizard", "des_data", "des_native"]))
|
||
|
||
SECTION_API = section_html(
|
||
"nav_api",
|
||
"help-api",
|
||
_p("api_intro")
|
||
+ _bullets(["api_docs_url", "api_redoc", "api_landing", "api_schema"])
|
||
+ _h3p("api_h3_auth", "api_auth")
|
||
+ _h3p("api_h3_mcp", "api_mcp")
|
||
+ _h3p("api_h3_autom", "api_autom"),
|
||
)
|
||
|
||
SECTION_LANG = section_html("nav_languages", "help-languages", _bullets(["lng_how", "lng_scope", "lng_export"]))
|
||
|
||
# (id de section, HTML complet, id de la section AVANT laquelle insérer)
|
||
NEW_SECTIONS: list[tuple[str, str, str]] = [
|
||
("help-architecture", SECTION_ARCHITECTURE, "help-interface"),
|
||
("help-diagrams", SECTION_DIAGRAMS, "help-edition"),
|
||
("help-library", SECTION_LIBRARY, "help-graphe"),
|
||
("help-offline", SECTION_OFFLINE, "help-partage"),
|
||
("help-collab", SECTION_COLLAB, "help-partage"),
|
||
("help-desktop", SECTION_DESKTOP, "help-partage"),
|
||
("help-api", SECTION_API, "help-plugins"),
|
||
("help-languages", SECTION_LANG, "help-plugins"),
|
||
]
|
||
|
||
# Compléments insérés À LA FIN de sections existantes (avant leur </section>) :
|
||
# section id -> bloc HTML
|
||
EXTRA_BLOCKS: list[tuple[str, str]] = [
|
||
("help-interface", _h3p("h3_push", "push_p1", "push_p2")),
|
||
("help-recherche", _h3p("h3_semantic", "sem_p1", "sem_p2")),
|
||
("help-fichiers", _h3p("h3_pdf", "pdf_p") + _h3p("h3_exports", "exp_p") + _h3p("h3_dupe", "dupe_p")),
|
||
("help-personnalisation", _h3p("h3_panes", "panes_p")),
|
||
("help-securite", _h3p("h3_mfa", "mfa_p") + _h3p("h3_admin", "admin_p")),
|
||
]
|
||
|
||
# Entrées TOC à insérer AVANT l'entrée dont l'href est la 3e valeur.
|
||
TOC_INSERT_BEFORE: list[tuple[str, str, str]] = [
|
||
("nav_architecture", "#help-architecture", "#help-interface"),
|
||
("nav_diagrams", "#help-diagrams", "#help-edition"),
|
||
("nav_library", "#help-library", "#help-graphe"),
|
||
("nav_offline", "#help-offline", "#help-partage"),
|
||
("nav_collab", "#help-collab", "#help-partage"),
|
||
("nav_desktop", "#help-desktop", "#help-partage"),
|
||
("nav_api", "#help-api", "#help-plugins"),
|
||
("nav_languages", "#help-languages", "#help-plugins"),
|
||
]
|
||
|
||
# Section « Édition mobile » dédiée (fix BUG-067) : créée par le script
|
||
# d'insertion après la section help-edition.
|
||
MOBILE_SECTION_TITLE_KEY = "help.nav_mobile_editor"
|
||
MOBILE_SECTION_TITLE_FR = "📱 Édition mobile"
|