===  FourmizzTranslate ===
Contributors: sovereigntranslate
Tags: translation, multilingual, i18n, weglot alternative, self-hosted
Requires at least: 5.8
Tested up to: 6.7
Stable tag: 1.1.30
Requires PHP: 7.4
License: MIT

Plateforme de traduction auto-hébergée — sans limite de mots, sans dépendance externe obligatoire.

== Description ==

**FourmizzTranslate** est l'alternative souveraine à Weglot.

* 🔒 **100 % auto-hébergé** — vous contrôlez vos données
* ♾️  **Sans limite de mots** — le cache SQLite est illimité
* ⚡ **Cache permanent** — les traductions déjà faites ne coûtent rien
* 🌐 **Multi-providers** : LibreTranslate (self-hosted), Anthropic Claude, DeepL
* 🎨 **Widget flottant** avec drapeaux et détection automatique de la langue
* 📎 **Shortcode** `[st_switcher]` pour placer le sélecteur n'importe où
* 🧩 **Widget sidebar** compatible avec tous les thèmes

= Prérequis =

Vous devez disposer d'une instance **FourmizzTranslate** (serveur Node.js) déployée et accessible.
Voir : https://github.com/fourmizz/weglotHomebrew

= Configuration =

1. Installez et activez le plugin.
2. Allez dans **Réglages → FourmizzTranslate**.
3. Renseignez l'URL de votre serveur et votre clé de projet (créée dans le dashboard FourmizzTranslate).
4. Choisissez la langue source et les langues cibles.
5. Enregistrez — le snippet est automatiquement injecté sur le frontend.

= Shortcodes =

`[st_switcher]` — boutons avec drapeaux (défaut)
`[st_switcher style="dropdown"]` — liste déroulante HTML native

== Installation ==

1. Téléchargez le dossier `fourmizz-translate` dans `/wp-content/plugins/`.
2. Activez le plugin dans **Extensions**.
3. Configurez via **Réglages → FourmizzTranslate**.

== Changelog ==

= 1.1.31 (serveur uniquement, redéploiement requis) =
* Traduction : le provider principal est réessayé automatiquement (2 tentatives espacées) avant tout repli — les erreurs passagères (surcharge, 429/503) ne font plus échouer le lot.
* Repli LibreTranslate : n'est tenté que si l'instance LibreTranslate prend réellement en charge la paire de langues (interrogation de GET /languages, mise en cache 1 h). Corrige les traductions arabes jamais réalisées quand le provider principal échouait : le repli vers une instance sans arabe échouait à son tour et masquait l'erreur d'origine.
* Logs : en cas d'échec du repli, c'est l'erreur du provider principal qui est remontée (la vraie cause), plus celle de LibreTranslate.

= 1.1.30 =
* Slugs : import CSV au format `slug_original;slug_traduit` (une ligne par page, un fichier par langue cible). Disponible dans WP admin (FourmizzTranslate → Slugs) et dans le dashboard serveur (section Slugs → « Importer CSV », redéploiement serveur requis). Les URLs complètes, les préfixes de langue et les slashes manquants sont nettoyés automatiquement ; les lignes vides ou identiques sont ignorées ; le cache des slugs est invalidé après import côté WP.

= 1.1.29 =
* Installation : le mode « prefix » (répertoires /en/ /es/, SEO-friendly) est désormais le mode par défaut à l'activation du plugin. Les sites existants ne sont pas affectés : leur réglage enregistré est conservé.
* Sélecteur de langues : la langue active est toujours affichée en première position — shortcode [st_switcher] (boutons et dropdown), widget sidebar et widget flottant (snippet, redéploiement serveur requis pour ce dernier). En mode prefix l'ordre est rendu côté serveur pour chaque variante de langue ; en mode storage le repositionnement se fait côté client.

= 1.1.28 =
* Mode prefix : le prewarm du contenu à la publication couvre désormais tous les types de contenu publics — pages, articles ET custom post types (même critère que la traduction des slugs). Auparavant limité à post/page, le contenu d'un CPT n'était traduit qu'à la première visite de chaque version linguistique. Les révisions et autosaves sont ignorés.

= 1.1.27 (serveur uniquement, redéploiement requis) =
* Sauvegardes automatiques de la base SQLite : snapshot cohérent quotidien (03:00 UTC par défaut) via l'API de backup en ligne de SQLite, vérification d'intégrité (PRAGMA quick_check) avant archivage, compression gzip, rotation grand-père/père/fils (14 quotidiennes, 8 hebdomadaires, 12 mensuelles). Idempotent au redémarrage : un créneau manqué (serveur éteint à 03:00) est rattrapé au prochain démarrage, sans doublon.
* Dashboard : carte « Sauvegardes » dans Réglages — statut du planificateur, sauvegarde manuelle, liste avec téléchargement et suppression.
* Configuration via variables d'environnement (BACKUP_ENABLED, BACKUP_DIR, BACKUP_HOUR_UTC, BACKUP_KEEP_*) — tout fonctionne sans configuration.

= 1.1.26 =
* Support RTL (arabe, hébreu, persan, ourdou…) : l'attribut dir="rtl" est désormais posé sur <html> quand la langue affichée est une langue droite-à-gauche — mode prefix (passe serveur PHP) comme mode storage (snippet). La mise en page se miroite correctement et les styles [dir="rtl"] des thèmes/Elementor s'activent. Le cas inverse (site source RTL traduit vers une langue LTR) repasse dir en ltr. Le widget flottant garde une direction stable (ltr interne) quelle que soit la langue de la page. Aucun changement pour les sites entièrement LTR : le HTML produit est identique. Après mise à jour en mode prefix, vider le cache de traduction si vous utilisez une langue RTL.

= 1.1.25 (serveur uniquement, redéploiement requis) =
* Glossaire : le cache ne prime plus sur le glossaire. Une traduction mise en cache AVANT l'ajout/modification d'une entrée de glossaire qui la concerne est automatiquement re-traduite (une seule fois — pas de re-traduction en boucle) au lieu d'être servie telle quelle indéfiniment.
* Glossaire : en batch, la consigne « préserver les marqueurs 【ST:N】 » n'était envoyée au provider (Gemini, Claude, Ollama) que si le PREMIER texte du lot contenait un terme du glossaire — sinon le provider traduisait/perdait les marqueurs des autres textes et le glossaire était ignoré aléatoirement. La consigne est envoyée dès qu'un texte du lot est concerné.
* Glossaire : priorité des entrées clarifiée — terme le plus long d'abord, puis entrée du projet avant entrée globale, puis entrée spécifique à la langue avant entrée « toutes langues ».
* Rappel : côté WordPress (mode prefix), le HTML traduit reste en cache transient — après une modification de glossaire, « Vider le cache » pour voir l'effet immédiatement.

= 1.1.24 =
* Correctif (serveur + snippet, redéploiement serveur requis — aucun changement de code plugin) : les animations de texte « machine à écrire » (typed.js, titres animés Elementor…) faisaient envoyer chaque état intermédiaire (« Un posic », « Un posicio »…) du texte déjà traduit à l'API, tagué langue source. Deux protections : (1) le snippet n'envoie un texte dynamique que s'il est resté stable 700 ms — les états d'animation ne se stabilisent jamais, la phrase finale est reconnue comme déjà traduite ; (2) le garde « écho » serveur détecte aussi les fragments : tout texte (8 caractères et plus) qui est un préfixe strict d'une traduction déjà produite pour la même langue cible est renvoyé tel quel, sans appel provider ni stockage.
* Serveur : la purge « écho » supprime aussi ces fragments (préfixes de 8 caractères et plus d'une traduction existante).

= 1.1.23 =
* Traçabilité : colonne « Date (UTC) » dans 📝 Traductions — permet de distinguer une ligne polluée résiduelle (antérieure aux correctifs) d'une ligne nouvellement créée.
* Serveur : date + provider affichés dans « Dernières traductions » et colonne Date dans l'onglet Traductions du dashboard.
* Serveur : le garde « écho » ne s'applique qu'aux textes de 15 caractères et plus — les mots courts identiques entre langues (« Innovation », « Design ») continuent d'être envoyés au provider normalement.

= 1.1.22 =
* Correctif majeur : retour du bug de « double traduction » (textes déjà traduits renvoyés à l'API tagués langue source). Cause : le module SEO (FT_SEO_Meta) traduit le titre et les metas via les filtres Yoast, puis la passe DOM serveur re-collectait ces mêmes balises — désormais en langue cible — et les re-soumettait comme du français. La passe DOM exclut maintenant les valeurs déjà traduites par FT_SEO_Meta.
* Serveur (redéploiement requis) : garde « écho » — tout texte soumis qui correspond à une traduction déjà produite pour la même langue cible est renvoyé tel quel, sans appel provider ni stockage. Filet de sécurité contre toute réinjection future, quelle qu'en soit l'origine.
* Serveur : bouton « Purger les traductions écho » dans Maintenance (dashboard) pour nettoyer les lignes déjà accumulées.
* Snippet : l'observateur de contenu dynamique reconnaît les textes déjà traduits même après normalisation des espaces (sliders qui re-créent les nœuds) et inclut le contenu des balises <template> dans l'instantané initial.

= 1.1.21 =
* Correctif : la recherche AJAX (Traductions / Slugs) mutilait silencieusement les termes contenant un espace, un accent ou une apostrophe — le proxy AJAX passait la query string dans `sanitize_text_field()`, qui supprime toutes les séquences percent-encodées (« piscine coque » devenait « piscinecoque » → aucun résultat). Le chemin reste validé par liste blanche et la query string est reconstruite depuis une liste blanche de paramètres.
* Amélioration (serveur, redéploiement requis) : recherche insensible aux accents et à la casse (« équipe » trouve « Équipe »), apostrophes typographiques (’) assimilées aux droites ('), recherche multi-mots (chaque mot doit matcher, « piscine coque » trouve « piscine à coque »), et les caractères % et _ sont traités littéralement.

= 1.1.20 =
* Correctif : la resynchronisation des langues et l'import des réglages renvoyaient une page blanche (redirection vers admin-post.php au lieu de la page de réglages). Les handlers utilisaient `menu_page_url()`, qui renvoie une chaîne vide sur admin-post.php. Retour désormais construit en absolu.

= 1.1.19 =
* Gouvernance : la langue source et les langues cibles sont désormais gérées exclusivement côté serveur. Elles s'affichent en lecture seule dans Réglages → FourmizzTranslate (plus aucun admin WP ne peut ajouter/retirer une langue depuis WordPress). Le plugin les synchronise depuis le serveur (endpoint `GET /api/config`) : à l'ouverture des réglages, via un bouton « Resynchroniser », et une fois par jour (cron). Ces clés ne sont plus enregistrées par le formulaire ni appliquées à l'import de réglages. La détection automatique reste, elle, modifiable côté WP.

= 1.1.18 =
* Sitemap (Yoast) : les entrées de langue ajoutées utilisaient la date de modification brute (« 2026-02-11 10:44:38 ») au lieu du format W3C Datetime exigé par le protocole sitemap. Corrige l'erreur « format du fichier sitemap » remontée par SEMrush / les validateurs. La date est désormais normalisée en ISO 8601 (« 2026-02-11T10:44:38+00:00 »).

= 1.1.17 =
* Mode prefix / SEO : la balise `og:locale` des pages traduites reflète désormais la langue cible (ex. `de_DE` sur une page allemande) au lieu de la locale source (`fr_FR`) imprimée par Yoast. Après mise à jour : vider le cache de traduction.

= 1.1.16 =
* Mode prefix / SEO : le `<link rel="canonical">` et `og:url` des pages traduites pointent désormais vers l'URL traduite elle-même (auto-référence), au lieu de l'URL source. Corrige l'alerte « Canonical to other page » (SEMrush) et évite que les moteurs traitent chaque traduction comme un doublon de la version source. Fonctionne quelle que soit la source du canonical (thème, Yoast, Rank Math…). Après mise à jour : vider le cache de traduction pour régénérer les pages déjà en cache.

= 1.1.15 =
* Mode prefix : garde anti-boucle sur les redirections. Si le re-préfixage d'une redirection tierce (plugin Redirection, SEO…) reproduit exactement l'URL demandée, on ne relance pas la boucle : redirection finie vers la langue source au lieu d'un ERR_TOO_MANY_REDIRECTS. Protège le cas d'une page renommée dont l'ancien slug source périmé partage le même slug traduit que le nouveau.

= 1.1.14 =
* Réglages : export / import des réglages du module en JSON (Réglages → FourmizzTranslate). Permet de migrer toute la configuration d'un site à l'autre (préprod → prod) en un fichier. L'import re-génère les règles de réécriture et vide le cache. Le fichier contient les clés (dont la clé secrète) — à conserver en lieu sûr.

= 1.1.13 =
* Mode prefix : la normalisation du préfixe /langue/ se fait désormais sur `setup_theme` (avant `init`). Les moteurs de redirection tiers (plugin Redirection, plugins SEO) qui matchent l'URL sur `init` voient le chemin source non préfixé et déclenchent leurs 301 normalement ; la destination est ensuite re-préfixée dans la langue. Corrige les URLs traduites d'anciennes pages supprimées qui tombaient en 404 au lieu de suivre la redirection.

= 1.1.12 =
* Mode prefix : les redirections serveur (wp_redirect / wp_safe_redirect) conservent la langue. Un thème ou plugin qui redirige (ex. contenu supprimé renvoyé vers sa page parente) ne renvoie plus le visiteur vers l'URL source sans préfixe.

= 1.0.0 =
* Version initiale
