# powersync-docs Documentation ETM PowerSync — [docs.etm-powersync.fr](https://docs.etm-powersync.fr) MkDocs Material, **docs-as-code**, trois langues : `fr` (défaut) · `de` · `en`. Licence : CC-BY-4.0 pour la documentation, GPL-3.0 pour les exemples de code. --- ## La règle qui explique tout le reste **95 % du volume est GÉNÉRÉ, pas rédigé.** Mesure du 2026-10-12 : 74 013 mots générés contre 3 506 mots de prose, sur 107 pages. Tout ce qui est entre ``` … ``` est produit par un script depuis une source de vérité, et **écrasé à chaque passage**. Éditer à l'intérieur de ces marqueurs, c'est écrire quelque chose qui disparaîtra. | Générateur | Source de vérité | Produit | |---|---|---| | `scripts/gen_device_reference.py` | `PORTING_STATUS.yaml` + les `integrationplugin*.json` et `meta.json` des 5 dépôts de plugins | fiches appareils, index de catégorie, matrice de compatibilité, `appareils/SUMMARY.md` | | `scripts/gen_api_reference.py` | `introspect.json` (introspection nymea) | référence JSON-RPC (23 pages), `api/SUMMARY.md` | | `scripts/gen_optimizer_reference.py` | `docs/etm-powersync-optimizer-protocol.openrpc.json` du moteur (`etm-powersync-energy-plugin-etm`, branche par défaut) | tableaux de messages, listes fermées, règles nommées et machine de repli de `optimiseur/protocole*.md`, fiche de `optimiseur/contrat*.md`, copie servie du contrat ; garde-fou de contenu (IP privées, « cloud », « Héos ») | ## Multi-langue — où passe la frontière Deux régimes, et ils ne se traitent pas pareil : - **Le bloc de référence est en ANGLAIS, une seule fois, servi identique dans les trois langues.** Décision du 2026-10-12. La raison est une mesure, pas un goût : nymea ne sert **aucune** traduction sur notre parc — vérifié sur le banc `hems`, où `Integrations.GetThingClasses` rend la **même charge utile au sha256 près** (243 340 octets) pour `fr_FR`, `de_DE` et `en_US`. Les noms de modèles, de registres et d'unités sont donc déjà en anglais ; traduire les seuls en-têtes de colonnes autour aurait fabriqué des pages bilingues sans rien gagner. Le vocabulaire vit dans le dict `REF` de chaque générateur. **Cas particulier, la référence optimiseur** (2026-10-18) : le cadre est en anglais comme partout, mais les descriptions viennent du contrat du moteur, écrit en français. Les traduire ici ferait une seconde vérité : elles sont reprises telles quelles, et l'en-tête de colonne le dit (« from the contract, French »). - **La prose et la navigation se TRADUISENT.** Fichiers suffixés (`page.md` = fr, `page.de.md`, `page.en.md`), libellés de nav par `nav_translations` dans `mkdocs.yml`, échafaudage des pages créées par le dict `SCAFFOLD` du générateur appareils. > **Pourquoi `SCAFFOLD` existe.** Sans lui, chaque nouvel appareil ajouté créerait sa fiche > dans la seule langue par défaut, et `fallback_to_default` la servirait **en français** sous > `/de/` et `/en/`. Le générateur crée donc les trois variantes — et **ne réécrit jamais** une > page existante, pour que la prose traduite à la main survive aux régénérations. ### Localisation ≠ traduction `docs/tarifs.md` est l'exemple à connaître : la version FR parle de Tempo et du signal RTE, la DE de `§14a EnWG` et de SMARD, l'EN des deux. Ce ne sont **pas** des traductions l'une de l'autre, et c'est volontaire — les signaux tarifaires sont nationaux. Même traitement pour la ligne correspondante de `docs/fonctionnalites/index.md`. --- ## Travailler dessus ```bash python3 -m venv .venv && . .venv/bin/activate pip install -r requirements.txt # Prévisualiser (les trois langues sont construites ensemble) mkdocs serve # Régénérer la référence appareils — exige les JSON des 5 dépôts de plugins # dans .plugins-src/ (la CI les clone ; en local, copiez-les depuis le workspace) python3 scripts/gen_device_reference.py --src .plugins-src --docs docs \ --lang fr --locales fr,de,en # Régénérer la référence API python3 scripts/gen_api_reference.py --src introspect.json --docs docs # Régénérer la référence du protocole optimiseur — exige le contrat OpenRPC du moteur # (la CI clone le moteur dans .engine-src/ ; en local, --src accepte le clone, # un dossier qui contient le fichier, ou le fichier lui-même) python3 scripts/gen_optimizer_reference.py --src .engine-src/etm-powersync-energy-plugin-etm --docs docs # Ce que vérifie la CI : rien ne doit changer après régénération mkdocs build --strict python3 scripts/gen_device_reference.py --src .plugins-src --docs docs \ --lang fr --locales fr,de,en --check python3 scripts/gen_optimizer_reference.py --src .engine-src/etm-powersync-energy-plugin-etm \ --docs docs --check ``` ### Le sélecteur de langue Material affiche son icône `translate` — l'idéogramme 文 collé à un A. Elle dit « traduire », pas « vous êtes en français », et à la taille du bandeau on y voit un symbole asiatique plutôt qu'une langue. Depuis le 2026-10-15, `stylesheets/extra.css` la masque et affiche à la place **le drapeau de la langue courante plus son code**, comme sur etm-powersync.fr. La langue courante est aussi mise en évidence dans la liste déroulante, où les trois lignes étaient jusque-là identiques. Le drapeau se choisit sur `html[lang]`, que `mkdocs-static-i18n` pose déjà par locale. **Aucun gabarit du thème n'est surchargé** — rien à reprendre à chaque mise à jour de Material. Les drapeaux sont des SVG en `data:` (les emojis drapeaux ne se rendent pas sous Windows) et le `aria-label` du bouton est inchangé : c'est lui qui porte le sens pour les lecteurs d'écran, le code « FR » du `::after` restant décoratif. ⚠️ `mkdocs build --strict` **échoue sur un simple avertissement**. C'est pour cela que `navigation.instant` est retiré de `theme.features` : il est incompatible avec le lien contextuel du sélecteur de langue de `mkdocs-static-i18n`. Le commentaire est dans `mkdocs.yml`, à l'endroit du retrait. ## Déploiement CI Gitea (`.gitea/workflows/docs.yml`) sur push vers `main`, plus un passage nocturne à 3 h (les `meta.json` des dépôts de plugins bougent sans que ce dépôt-ci bouge). Pipeline : clone des 5 dépôts de plugins et du moteur → génération appareils → génération API → génération optimiseur → `mkdocs build --strict` → contrôle d'idempotence → `rsync` vers le serveur. Le build produit `site/` (fr), `site/de/` et `site/en/` en une passe ; le `rsync --delete` pousse l'ensemble.