Problèmes de traduction Polylang/WPML : pourquoi les langues se mélangent et comment réparer

Cet article vous a aidé ?

Votre page d’accueil est en anglais. Votre menu est en français. Votre page produit est à moitié en espagnol parce qu’un widget a décidé d’improviser. Ce n’est pas du « multilingue » ; c’est un mélangeur de contenu.

Quand Polylang ou WPML « mélange les langues », ce n’est rarement aléatoire. C’est un mode de défaillance prévisible : mauvais contexte de langue, mauvais IDs d’objets, clés de cache erronées, ou une migration qui a laissé les relations de traduction dans le fossé. Traitez-le comme un incident : reproduire, mesurer, isoler, et appliquer des correctifs qui tiennent après la prochaine mise à jour du plugin.

Ce que « mélange de langues » est réellement (et n’est pas)

Les gens décrivent beaucoup de bugs différents comme « WPML mélange les langues » ou « Polylang est cassé ». Sous le capot, il y a quelques classes distinctes de problèmes :

  • Bugs de contexte : WordPress rend la page en Langue A, mais un widget/requête s’exécute en Langue B parce qu’il n’a pas hérité la langue courante ou la surcharge.
  • Bugs de relations : Le site a des traductions, mais les liens entre originaux et traductions sont manquants ou erronés. Le plugin ne peut donc pas trouver le bon pendant et retombe sur un fallback.
  • Bugs de taxonomie/menu : Les articles sont traduits, mais les catégories/étiquettes/menus ne le sont pas ou ne sont pas assignés correctement. L’interface montre des pages « correctes », tandis que la navigation tire « ce qui existe ».
  • Bugs de cache : Votre cache stocke le HTML pour la Langue A et le sert à la Langue B parce que la clé de cache ne varie pas selon la langue, le cookie, l’URL ou l’en-tête.
  • Bugs de réécriture/canonique : Les URLs résolvent, mais la détection de langue choisit la mauvaise langue, ou les redirections réécrivent les préfixes de langue de manière incohérente.
  • Bugs de traduction de chaînes : Chaînes du thème, titres de widget ou labels ACF sont tirés du mauvais domaine ou de la mauvaise table de langue.

Autre point : parfois ce n’est pas le plugin de traduction. Un thème avec des requêtes personnalisées « malicieuses » et des IDs codés en dur peut produire un chaos parfait même sur un site monolingue. Ajoutez le multilingue et ça passe de « bizarrerie » à « incident ».

Une vérité opérationnelle : la sortie mixte de langues est généralement déterministe. Si vous pouvez la reproduire avec la même URL + mêmes cookies + même état de cache, vous pouvez la résoudre. Si vous ne pouvez pas la reproduire, c’est souvent une variance de cache ou une course entre plusieurs caches.

Comment WPML et Polylang stockent la langue et les traductions

WPML : groupes de traduction, codes de langue et « element IDs »

WPML suit généralement les relations de traduction dans une table qui regroupe les « éléments » (articles, termes, parfois chaînes) en groupes de traduction. Chaque élément a un code de langue et un ID de groupe de traduction. Si ce mappage est erroné ou incomplet, WPML doit deviner. Deviner, c’est comment vous obtenez des articles anglais avec des catégories allemandes et un sélecteur de langue qui ne mène nulle part.

Polylang : taxonomie de langue + post meta + relations

Polylang utilise une taxonomie de langue (des termes représentant les langues) et stocke les relations entre posts traduits. C’est simple en concept, mais cela hérite de tous les pièges habituels de WordPress : cache de termes, cache d’objets, et requêtes personnalisées qui ne respectent pas les taxonomies.

Pourquoi les deux peuvent mélanger les langues même si les « paramètres semblent corrects »

Parce que la page de paramètres est seulement le plan de contrôle. Le plan de données, c’est votre base de données, les couches de cache, les règles de réécriture et tout ce que votre thème et vos plugins font dans les requêtes. En production, le bug est généralement l’un des suivants :

  • Liens de traduction manquants (intégrité des données)
  • Mauvaise langue détectée (routage)
  • Clé de cache sans langue (caching)
  • Requête personnalisée ignorant les filtres de langue (logique applicative)

Faits intéressants et contexte historique (pourquoi c’est difficile)

  1. WordPress n’est pas né multilingue. Pendant des années, multilingue voulait dire « installer des sites séparés » ou « bricoler avec des plugins ». Le noyau suppose toujours une locale par requête.
  2. WPML a popularisé les « groupes de traduction » tôt. C’est une abstraction utilisable, mais elle exige un mappage cohérent entre types de posts, termes et méta.
  3. Polylang s’est appuyé sur les taxonomies WordPress. Astucieux : il réutilise les mécanismes natifs, mais hérite aussi des pièges du cache de termes.
  4. Le cache d’objets a changé la donne. Redis/Memcached ont rendu WordPress rapide, puis ont rendu le multilingue étrange parce que beaucoup de thèmes/plugins ne varient pas les clés de cache par langue.
  5. WooCommerce a compliqué les choses. Les produits ne sont pas seulement des posts ; ce sont des posts plus des variations, attributs et tables de lookup. Le décalage de langue peut se propager aux prix, pas seulement au texte.
  6. « Langue dans l’URL » est devenu une norme SEO. Préfixes (/fr/), sous-domaines et paramètres ont des comportements de cache et de réécriture différents. Certains sont plus faciles à raisonner ; aucun n’est gratuit.
  7. La traduction de chaînes est un second système. La traduction du contenu des posts et la traduction des chaînes d’interface utilisent des stockages et chemins de recherche différents, donc il est courant de « corriger les posts » tandis que les en-têtes et widgets restent faux.
  8. Les règles canonical et hreflang ont évolué. Les moteurs de recherche sont devenus plus stricts sur le balisage langue/région. Une mise à jour de plugin qui « corrige le SEO » peut casser des hypothèses de routage et exposer des bugs latents.
  9. Les constructeurs modernes (Elementor, WPBakery) ajoutent une autre couche. Ils stockent du contenu dans des blobs sérialisés ; les plugins de traduction s’intègrent, mais des cas limites autour des widgets globaux et des templates sont encore courants.

Méthode de diagnostic rapide

Quand les langues se mélangent, ne commencez pas par basculer des paramètres au hasard. Commencez comme un SRE : identifiez la couche qui ment.

Première étape : prouver si c’est le cache

  • Désactivez temporairement le cache de pages (ou contournez-le) et retestez la même URL dans deux langues.
  • Vérifiez si le HTML diffère lorsque vous variez le cookie de langue, le préfixe d’URL de langue, ou l’en-tête Accept-Language.
  • Si cela change quand le cache est contourné : vos caches sont mal indexés ou ne sont pas purgés par langue.

Deuxième étape : valider la détection de langue et le routage

  • Confirmez que le plugin considère la requête courante comme Langue A.
  • Vérifiez que les permaliens/règles de réécriture sont cohérents et non dupliqués par plusieurs plugins.
  • Assurez-vous de ne pas avoir WPML et Polylang activés simultanément (oui, des gens le font).

Troisième étape : vérifier les relations de traduction et la traduction des taxonomies

  • Choisissez un post cassé. Confirmez que sa traduction existe et est liée.
  • Vérifiez les équivalents traduits des catégories/étiquettes/menus.
  • Vérifiez que les requêtes du thème respectent la langue et ne codent pas d’IDs en dur.

Quatrième étape : rechercher les « optimisations utiles »

  • Drop-ins de cache d’objets (Redis), plugins de cache persistant, cache CDN full-page, et cache de fragments.
  • Caches au niveau du thème (transients, options stockant du HTML rendu, caches de templates de page builder).

Règle de décision : si la même URL sert différentes langues sans changement d’URL/cookie/en-tête, c’est presque toujours une contamination de cache ou des fragments partagés.

Tâches pratiques : commandes, sorties, décisions (12+)

Ces tâches supposent que vous avez un accès shell et WP-CLI. Si ce n’est pas le cas, vous pouvez appliquer la logique via le panneau d’hébergement — juste plus de clics et moins de certitude.

Task 1: Confirm which multilingual plugin is active (and only one)

cr0x@server:~$ wp plugin list --status=active
+-----------------------+--------+-----------+---------+
| name                  | status | update    | version |
+-----------------------+--------+-----------+---------+
| wpml-multilingual-cms | active | none      | 4.6.11  |
| wpml-string-translation | active | available | 3.2.7 |
| redis-cache           | active | none      | 2.5.4   |
+-----------------------+--------+-----------+---------+

Ce que signifie la sortie : WPML est actif, plus Redis pour le cache d’objets. Pas de Polylang. Bien.

Décision : Si vous voyez WPML et Polylang actifs, stoppez. Désactivez-en un avant de déboguer. Deux fournisseurs de contexte de langue = chaos.

Task 2: Verify WP-CLI can see the site URL and environment

cr0x@server:~$ wp option get siteurl
https://example.com

Ce que cela signifie : Vous opérez sur le site attendu (pas une DB de staging obsolète).

Décision : Si l’URL est incorrecte, corrigez-la d’abord. Des exécutions WP-CLI pointant au mauvais site transforment le « débogage » en « perte de données ».

Task 3: Check permalink structure (rewrite layer)

cr0x@server:~$ wp option get permalink_structure
/%category%/%postname%/

Ce que cela signifie : Permaliens jolis activés. Les plugins de langue vont hooker là-dessus.

Décision : Si les permaliens sont vides ou incohérents entre environnements, videz les réécritures après confirmation des paramètres de langue.

Task 4: Flush rewrite rules safely

cr0x@server:~$ wp rewrite flush --hard
Success: Rewrite rules flushed.

Ce que cela signifie : Règles de réécriture régénérées dans la base et .htaccess (si utilisé).

Décision : Si les URLs de langue renvoient 404 ou redirigent mal, retestez. Si rien ne change, le routage n’est probablement pas le problème principal.

Task 5: Identify whether a full-page cache is present (headers)

cr0x@server:~$ curl -sI https://example.com/fr/ | egrep -i 'cache|vary|set-cookie|x-cache|cf-cache|age'
cache-control: max-age=600
vary: Accept-Encoding
x-cache: HIT
age: 534

Ce que cela signifie : Il y a un cache (x-cache: HIT) et il ne varie pas par cookie de langue ou en dehors de /fr/ lui-même.

Décision : Si vous utilisez la détection de langue par cookie et que le cache ne varie pas par cookie, vous servirez la mauvaise langue. Corrigez le cache avant de toucher aux paramètres WPML/Polylang.

Task 6: Compare the same page in two languages and look for identical cache keys

cr0x@server:~$ curl -sI https://example.com/ | egrep -i 'x-cache|age|cache-control'
x-cache: HIT
age: 410

cr0x@server:~$ curl -sI https://example.com/fr/ | egrep -i 'x-cache|age|cache-control'
x-cache: HIT
age: 410

Ce que cela signifie : Age identique suggère que le cache pourrait fusionner les variantes (selon la stack, mais c’est suspect).

Décision : Si vous observez un comportement de cache identique et suspect entre langues, contournez le cache et vérifiez le contenu. Puis corrigez le keying du cache.

Task 7: Bypass cache and test language correctness (origin truth)

cr0x@server:~$ curl -sH 'Cache-Control: no-cache' https://example.com/fr/ | grep -i '

Ce que cela signifie : L’origine rend le français correctement (au moins l’attribut HTML lang).

Décision : Si l’origine est correcte mais le cache est faux, cessez de déboguer les données WPML/Polylang. Corrigez la couche de cache d’abord.

Task 8: Verify object cache is enabled (the silent saboteur)

cr0x@server:~$ wp redis status
Status: Connected
Client: PhpRedis (v5.3.7)
Database: 0
Prefix: wp_cache:

Ce que cela signifie : Le cache d’objets persistant est activé. Excellent pour la vitesse ; dangereux si le code ne varie pas par contexte de langue.

Décision : Si des problèmes multilingues sont apparus « après activation de Redis », suspectez des résultats de requêtes ou fragments mis en cache sans clé de langue.

Task 9: Clear object cache to see if the bug disappears

cr0x@server:~$ wp cache flush
Success: The cache was flushed.

Ce que cela signifie : Tous les objets/queries/fragments mis en cache sont supprimés.

Décision : Si le problème disparaît après un flush et revient plus tard, vous avez un problème de keying de cache. Ne planifiez pas des flushs horaires en guise de « correctif ».

Task 10: Inspect WPML language settings from the database (sanity check)

cr0x@server:~$ wp option get icl_sitepress_settings --format=json | head
{"icl_lang_sel_type":"dropdown","language_negotiation_type":1,"urls":{"directory_for_default_language":0}}

Ce que cela signifie : Le type de négociation WPML 1 indique couramment « langue par répertoire ». Les paramètres existent et sont lisibles.

Décision : Si la négociation est « cookie » ou « paramètre », assurez-vous que chaque couche de cache varie en conséquence. Si c’est « répertoire », assurez-vous que les réécritures et redirections canoniques le préservent.

Task 11: Check whether a post has translations linked (WPML)

cr0x@server:~$ wp db query "SELECT element_id, element_type, trid, language_code, source_language_code FROM wp_icl_translations WHERE element_id=123;"
+------------+--------------+------+---------------+----------------------+
| element_id | element_type | trid | language_code | source_language_code |
+------------+--------------+------+---------------+----------------------+
| 123        | post_post    | 9012 | en            | NULL                 |
+------------+--------------+------+---------------+----------------------+

Ce que cela signifie : Le post 123 existe en anglais, groupe de traduction 9012. Mais on ne voit pas encore son homologue français.

Décision : Interrogez pour le trid. Si aucune autre ligne n’existe, les traductions ne sont pas liées (ou n’existent pas). Le sélecteur de langue peut retomber sur la mauvaise page.

Task 12: Find all translations in that group (WPML)

cr0x@server:~$ wp db query "SELECT element_id, language_code FROM wp_icl_translations WHERE trid=9012;"
+------------+---------------+
| element_id | language_code |
+------------+---------------+
| 123        | en            |
| 456        | fr            |
+------------+---------------+

Ce que cela signifie : La traduction existe (ID post français 456) et est liée.

Décision : Si la page française affiche encore des fragments en anglais, il s’agit probablement d’un cache, de requêtes du thème, ou de taxonomies/chaînes non traduites plutôt que d’un lien de traduction manquant.

Task 13: Confirm taxonomy terms are translated and linked (WPML terms)

cr0x@server:~$ wp db query "SELECT element_id, element_type, trid, language_code FROM wp_icl_translations WHERE element_type LIKE 'tax_%' AND element_id=77;"
+------------+---------------------+------+---------------+
| element_id | element_type        | trid | language_code |
+------------+---------------------+------+---------------+
| 77         | tax_category        | 3001 | en            |
+------------+---------------------+------+---------------+

Ce que cela signifie : Le terme de catégorie 77 est enregistré uniquement pour l’anglais dans le mapping WPML.

Décision : Si les menus/catégories mélangent les langues, les traductions de termes manquantes sont un suspect principal. Ajoutez/attachez les termes traduits ou activez la traduction de termes pour cette taxonomie.

Task 14: Detect a theme/plugin custom query that ignores language filters

cr0x@server:~$ wp eval 'global $wp_query; echo "lang=".(defined("ICL_LANGUAGE_CODE")?ICL_LANGUAGE_CODE:"none")."\n";'
lang=fr

Ce que cela signifie : Le contexte WPML est français dans cet environnement de requête (utile lors d’un run en contexte web ; en CLI cela dépend du bootstrap).

Décision : Si WPML indique « fr » mais votre widget affiche des posts anglais, le widget exécute probablement une requête qui contourne les filtres WPML (par ex. suppress_filters=true) ou utilise du SQL direct.

Task 15: Find suspicious query patterns in your codebase (suppress_filters)

cr0x@server:~$ grep -R --line-number "suppress_filters" /var/www/html/wp-content | head
/var/www/html/wp-content/themes/acme/functions.php:812:  'suppress_filters' => true,
/var/www/html/wp-content/plugins/acme-widgets/widget-latest.php:55: $q = new WP_Query(['suppress_filters'=>true,'post_type'=>'post']);

Ce que cela signifie : Le code désactive explicitement les filtres. Les hooks WPML/Polylang sont des filtres. C’est votre preuve évidente.

Décision : Supprimez suppress_filters, ou ajoutez des contraintes de langue explicites via les API du plugin, ou utilisez leurs helpers de contexte « langue courante » pour cibler les requêtes. Si vous avez besoin de suppress_filters pour la performance, gérez manuellement le scope de langue et les clés de cache.

Task 16: Verify cron isn’t “helpfully” regenerating caches in the wrong language

cr0x@server:~$ wp cron event list | egrep -i 'wpml|polylang|cache|preload' | head
wpml_cache_clear         2025-12-27 03:10:00 +0000
rocket_preload_cache     2025-12-27 03:15:00 +0000

Ce que cela signifie : Un préchargeur de cache existe. S’il ne précharge que les URLs de la langue par défaut, il peut écraser des entrées de cache partagées.

Décision : Rendez le préchargement conscient des langues (préchargez toutes les variantes d’URL par langue) ou corrigez le keying du cache pour empêcher l’écrasement mutuel.

Blague #1 : Un site multilingue sans cache conscient de la langue, c’est comme une réceptionniste bilingue qui répond dans la langue qu’elle a apprise en dernier.

Les grands modes de défaillance : pourquoi les langues se mélangent

1) La clé de cache n’inclut pas la langue (cache full-page)

C’est la cause racine la plus fréquente en production parce que ça apparaît comme « aléatoire ». Ce n’est pas aléatoire ; c’est la langue qui a « chauffé » le cache en premier.

Déclencheurs typiques :

  • Passer de « langue dans l’URL » à « langue par cookie » sans mettre à jour la config du cache.
  • Ajouter un CDN ou proxy inverse qui ignore les cookies ou supprime les paramètres de requête.
  • Utiliser un plugin de cache optimisé pour sites monolingues.

Correction : faire varier le cache par langue. En pratique cela signifie : URL distincte par langue (préférable), ou inclure le cookie de langue dans la clé de cache, ou contourner le cache quand le cookie de langue est présent.

2) Cache d’objets et caches de fragments sans scope langue

Les caches full-page ne sont pas les seuls coupables. Un cache d’objets persistant peut servir des résultats de requête mis en cache à travers les langues si la clé n’incorpore pas la langue. WPML/Polylang essaient de s’intégrer, mais ils ne peuvent pas réparer des transients personnalisés ou des caches de thème que vous avez écrits en 2017 et oubliés.

Où ça arrive :

  • Transients stockant du HTML rendu pour des widgets
  • Options de thème stockant du « HTML de menu » mis en cache
  • Helpers custom « get_posts_cached() »

Correction : inclure le code de langue dans chaque clé de transient. Si vous ne pouvez pas, supprimez l’optimisation et passez à autre chose.

3) Requêtes personnalisées qui désactivent les filtres

Si vous voyez suppress_filters=true, supposez que le multilingue est cassé jusqu’à preuve du contraire. WPML et Polylang s’appuient sur des filtres pour ajuster les requêtes.

Correction : supprimer suppress_filters, ou ajouter des contraintes de langue explicites via les API du plugin, ou utiliser leurs helpers pour scoper les requêtes.

4) Traductions de taxonomies manquantes ou mal liées

C’est ainsi que vous obtenez une page française qui liste des catégories anglaises, ou un sélecteur de langue qui garde le même slug de catégorie mais change la langue de la page. Les termes ont leur propre mapping de traduction. Si le mapping n’existe pas, les plugins retombent en fallback.

Correction : traduire les termes, assigner les bons termes traduits aux posts traduits, et s’assurer que les menus sont construits par langue.

5) Configuration de menu et widget non spécifique à la langue

Les menus sont essentiellement de la configuration. Sur un site multilingue, la configuration doit être scannée. WPML peut synchroniser les menus ; Polylang peut assigner des menus par langue. Mais si vous avez un menu avec des liens codés en dur, vous avez construit une machine à mélanger le contenu.

Correction : séparer les menus par langue ou utiliser les outils de synchronisation fournis par les plugins, et éviter les liens absolus codés en dur vers la langue par défaut.

6) Le réglage « langue par répertoire pour la langue par défaut » cause une confusion canonique

Une configuration classique WPML est « répertoire pour la langue par défaut : off », ce qui signifie que la langue par défaut vit à / tandis que les autres sont à /fr/, /de/, etc. Ça marche, mais ça augmente les chances que caches et redirections canoniques aplatisent les chemins et mal détectent la langue.

Correction : si vous le pouvez, mettez la langue par défaut dans un répertoire aussi. C’est opérationnellement ennuyeux, et ennuyeux est la meilleure chose à dire du design d’URL.

7) Contenu mixte dans un seul post (processus éditorial)

Parfois le plugin va bien et le problème est éditorial : des traducteurs copient/collent des blocs, des builders réutilisent des templates globaux, ou quelqu’un a édité la mauvaise version de langue parce que le sélecteur de langue de l’admin bar a trompé.

Correction : verrouillez les workflows : rôles, capacités et pipeline de traduction explicite (même si c’est « toujours dupliquer puis traduire, ne jamais éditer l’original »).

Erreurs courantes : symptôme → cause racine → correction

1) Symptom: Homepage occasionally flips language without changing URL

Cause racine : cache full-page qui ne varie pas par cookie ou en-tête de langue.

Correction : utilisez la négociation par URL, ou configurez le cache pour qu’il varie par cookie de langue ; purgez le cache après changement de négociation.

2) Symptom: Menus show items in the wrong language, but page content is correct

Cause racine : menu assigné globalement, pas par langue ; ou HTML de menu mis en cache sans clé de langue.

Correction : assignez les menus par langue (fonction WPML/Polylang), et supprimez tout cache de fragment de menu ou ajoutez la langue à sa clé.

3) Symptom: Category archive shows posts from multiple languages

Cause racine : requête personnalisée avec suppress_filters ; mapping de traduction de taxonomie manquant ; ou paramètre « afficher toutes les langues » activé pour la taxonomie.

Correction : retirez suppress_filters ; traduisez et liez les termes ; assurez-vous que la taxonomie est « traduisible » et filtrée par la langue courante.

4) Symptom: Language switcher points to the homepage for some pages

Cause racine : relation de traduction manquante pour ce type de contenu (post/term/product), ou traduction existante mais non liée au groupe.

Correction : reconstruisez les liens de traduction (dupliquer et connecter correctement), lancez les outils de « troubleshooting » du plugin, et vérifiez le mapping DB pour les éléments affectés.

5) Symptom: WooCommerce cart/checkout shows mixed language strings

Cause racine : chaînes provenant de domaines thème/plugin non enregistrées pour traduction, ou fragments de cache (mini-cart) stockés sans clé de langue.

Correction : enregistrez correctement les chaînes, videz les caches, et assurez-vous que les fragments du panier varient par cookie/URL de langue.

6) Symptom: Admin editing language is “wrong,” leading to edits in the wrong translation

Cause racine : langue du profil utilisateur vs langue du site vs paramètres admin WPML confus ; éditeurs utilisant l’édition rapide sans vérifier la langue.

Correction : standardisez le comportement d’admin linguistique, formez les éditeurs à vérifier les indicateurs de langue, et restreignez qui peut éditer les originaux.

7) Symptom: Hreflang tags are wrong or missing intermittently

Cause racine : head mis en cache et partagé entre langues ; ou redirection canonique supprimant le répertoire de langue ; ou paramètres de permaliens incohérents.

Correction : corrigez le keying du cache pour les fragments head ; validez le comportement canonique ; assurez une format d’URL cohérent pour toutes les langues.

8) Symptom: After migration, translations exist but are “unlinked”

Cause racine : export DB partiel souvent omettant les tables du plugin ou réécrivant les IDs de posts d’une manière qui casse les références de groupe. Les migrations doivent inclure les tables de mapping du plugin et préserver les IDs ou les réconcilier correctement.

Correction : relancez la migration en incluant les tables WPML/Polylang ; évitez les exports partiels ; vérifiez que les comptes de lignes des tables de traduction correspondent à la source avant la coupure.

Blague #2 : « On va juste copier la base de données et voir ce qui arrive » est l’équivalent multilingue de « Je vais juste la redémarrer » — parfois ça marche, mais ce n’est pas une stratégie.

Trois mini-récits d’entreprise tirés du terrain

Mini-récit 1 : L’incident causé par une mauvaise hypothèse

Ils avaient une installation WordPress propre : WPML, trois langues, un plugin de cache et un CDN. L’équipe marketing s’est plainte que les visiteurs français voyaient parfois des titres en anglais. L’équipe d’ingénierie a fait la classique : blâmer WPML et ouvrir un ticket auprès du fournisseur du plugin.

L’hypothèse fausse était simple : « la langue est déterminée par l’URL, donc le cache est sûr ». En réalité, la langue par défaut était servie à /, et le site utilisait un cookie pour mémoriser la langue sélectionnée par certains utilisateurs. Le CDN ignorait les cookies par conception (performance !) et mettait en cache / comme un objet unique.

Ça signifiait que la langue qui frappait / en premier après une purge « gagnait » le cache. Les utilisateurs français sélectionnant le français provoquaient du HTML français sur /, le CDN le stockait, et maintenant les utilisateurs anglais recevaient du français jusqu’à la purge suivante. L’incident était intermittent, exaspérant et totalement déterministe.

La correction n’était pas un paramètre WPML. Ils ont changé la négociation de langue pour qu’elle soit basée sur des répertoires pour toutes les langues, y compris la par défaut (donc l’anglais est devenu /en/), mis à jour les redirections, purgé les caches, et le problème a cessé. Ils ont aussi ajouté un contrôle synthétique qui récupérait chaque page d’accueil de langue et vérifiait que le <html lang> correspondait. Ennuyeux, efficace.

Mini-récit 2 : L’optimisation qui a tourné mal

Une équipe produit voulait des pages de catégorie plus rapides. Quelqu’un a ajouté une « amélioration de performance » : mettre en cache le widget « Top Products » rendu dans un transient pendant 30 minutes parce qu’il faisait une requête lourde. Bonne idée sur un site monolingue.

Sur ce site, les produits étaient traduits par langue, et les prix/disponibilités différaient par marché. Le HTML du widget mis en cache était stocké sous une clé comme top_products_widget sans langue. Donc la première requête qui a chauffé ce cache (souvent l’anglais, à cause de la navigation interne) déterminait ce que tout le monde voyait pendant 30 minutes.

Cela empirait : le widget incluait des liens vers des produits dans la langue chauffée. Donc des pages de catégorie françaises affichaient des noms de produits anglais, des URLs anglaises, et parfois un format monétaire anglais. Pas catastrophique, mais cela a érodé la confiance et augmenté les contacts au support. L’équipe a essayé « purge du cache à la publication », ce qui n’a fait que rendre le comportement plus instable.

La correction finale : supprimer la mise en cache du HTML et à la place mettre en cache les IDs sous-jacents par langue (et par catégorie), puis rendre les titres/URLs corrects selon la langue à la demande. Ça consommait un peu plus de CPU mais a rétabli la justesse. Dans les systèmes de production, la justesse est de la performance. Les utilisateurs n’achètent pas des produits qu’ils ne comprennent pas.

Mini-récit 3 : La pratique ennuyeuse mais correcte qui a sauvé la journée

Une autre société utilisait Polylang avec WooCommerce et Redis. Ils avaient déjà été brûlés, donc ils faisaient quelque chose de douloureusement peu sexy : chaque release avait une checklist de test multilingue. Pas automatisée au début ; juste disciplinée.

La checklist incluait : ouvrir la page d’accueil, une page produit, une archive de catégorie, le panier et le checkout dans chaque langue ; vérifier le menu de langue ; vérifier le format monétaire et local ; vérifier les liens du sélecteur de langue ; vérifier la présence des hreflang. Ils avaient aussi une règle : si vous ajoutez du caching, documentez la clé de cache et ce qui la fait varier.

Un jour un développeur a mis à jour un thème qui introduisait une nouvelle option « cache d’en-tête global ». Ça a amélioré le Time To First Byte et embelli les dashboards. Les tests de fumée ont détecté que la langue de l’en-tête était fausse sur les langues non par défaut juste après le déploiement.

Ils ont revert en quelques minutes, puis redéployé avec le cache d’en-tête désactivé jusqu’à ce qu’ils puissent le patcher pour varier par langue. Pas de drame, pas d’impact client notable, pas de ticket « bug mystère ». La pratique ennuyeuse a fait exactement ce qu’il fallait : elle a sauvé la journée.

Listes de contrôle / plan étape par étape

Plan étape par étape pour corriger une sortie en langues mélangées (ordre sensé)

  1. Choisissez une URL reproductible qui montre le mélange de langues. Notez-la. Ne poursuivez pas dix bugs en même temps.
  2. Contournez le cache full-page et comparez la sortie. Si le contournement corrige, vous êtes en territoire cache.
  3. Videz le cache d’objets et retestez. Si cela corrige temporairement, vous avez un cache d’objets ou de fragments non conscient de la langue.
  4. Confirmez la méthode de négociation de langue (répertoire/subdomain vs cookie vs paramètre). Alignez-la avec votre stratégie de cache.
  5. Auditez les requêtes personnalisées pour suppress_filters, SQL direct et IDs codés en dur.
  6. Validez les liens de traduction pour le contenu cassé : posts et termes.
  7. Validez les menus par langue et assurez-vous que le thème rend l’emplacement de menu correct selon la langue.
  8. Vérifiez les domaines de traduction de chaînes pour thèmes et plugins ; assurez-vous que les bonnes chaînes existent dans chaque langue.
  9. Purgez les caches dans le bon ordre : CDN/proxy → plugin de page cache → cache d’objets → cache navigateur.
  10. Ajoutez du monitoring : un script simple qui récupère des pages clés par langue et vérifie des marqueurs de langue.

Checklist opérationnelle : avant de changer les paramètres

  • Sauvegarder la base de données (y compris les tables WPML/Polylang) et wp-content.
  • Noter le type de négociation de langue et la stratégie d’URL actuelle.
  • Lister toutes les couches de cache : navigateur, CDN, proxy inverse, plugin de page cache, cache d’objets.
  • Confirmer que l’environnement de staging peut reproduire le problème.

Checklist opérationnelle : après application d’un correctif

  • Tester un parcours utilisateur déconnecté (la plupart des caches s’appliquent ici).
  • Tester un parcours éditeur connecté (cookies différents, comportement de cache différent).
  • Vérifier les liens du sélecteur de langue pour au moins 5 pages aléatoires, pas seulement la page d’accueil.
  • Vérifier les archives de taxonomie et les résultats de recherche (les requêtes personnalisées aiment s’y cacher).
  • Vérifier que hreflang et balises canoniques correspondent bien aux URLs réelles.

FAQ

1) Pourquoi le site mélange les langues seulement « parfois » ?

Parce que les caches ne « varient pas parfois » par langue ; ils varient selon ce que la clé de cache inclut. Si la langue n’est pas incluse, la langue qui a chauffé le cache en dernier gagne jusqu’à éviction.

2) Est-ce que la langue dans l’URL est toujours meilleure que la langue par cookie ?

Opérationnellement, oui. Les URLs rendent la mise en cache, le débogage et le SEO plus déterministes. La détection par cookie peut fonctionner, mais chaque couche de cache doit varier selon ce cookie, et beaucoup ne le feront pas sauf si vous les forcez.

3) Mon contenu de page est correct, mais des widgets sont dans la mauvaise langue. Pourquoi ?

Les widgets exécutent souvent des requêtes séparées et peuvent utiliser des fragments mis en cache. Si ces requêtes désactivent les filtres ou utilisent des transients sans clé de langue, la sortie du widget peut diverger de la langue de la page.

4) Redis object cache peut-il causer le mélange des langues ?

Oui, indirectement. Redis n’est pas le problème ; il stocke fidèlement les clés que votre code lui demande. Si votre thème/plugin met en cache « derniers articles » sans inclure la langue dans la clé, Redis servira la mauvaise langue à grande échelle.

5) Pourquoi le sélecteur de langue envoie certaines pages vers la page d’accueil ?

C’est généralement un lien de traduction manquant (la traduction existe mais n’est pas connectée) ou la traduction n’existe pas. Le sélecteur ne peut pas inventer une cible, il retombe donc sur une page sûre.

6) Après migration, les traductions semblent dupliquées ou non liées. Que s’est-il passé ?

Les exports de base de données partiels omettent souvent les tables du plugin ou réécrivent des IDs de posts d’une façon qui casse les références de groupe. Les migrations doivent inclure les tables de mapping du plugin et préserver les IDs ou les réconcilier correctement.

7) Comment savoir si c’est la traduction de taxonomie versus la traduction de post ?

Si le contenu principal est correct mais que les catégories/étiquettes, breadcrumbs et menus sont faux, suspectez la traduction de taxonomie. Si le corps du post est faux ou que les cibles du sélecteur sont erronées, suspectez le lien de traduction de post ou le routage.

8) Dois‑je « corriger » en désactivant les caches définitivement ?

Non. Ce n’est pas une correction ; c’est programmer un incident de performance pour plus tard. Rendez les caches conscients de la langue et purgez correctement. Gardez la vitesse, gardez la justesse.

9) Nous utilisons un page builder. Est‑ce que cela change quelque chose ?

Ça ajoute plus de caches et plus d’endroits où stocker des templates globaux. Beaucoup de problèmes de mélange de langues viennent de widgets/templates globaux réutilisés entre langues sans variantes conscientes de la traduction.

10) Quel est le changement durable le plus rapide si je suis bloqué ?

Passez à la langue dans l’URL pour toutes les langues (y compris la langue par défaut), puis purgez tous les caches et sauvegardez les permaliens. Cela réduit le nombre de degrés de liberté qui causent le mélange.

Une citation de fiabilité à garder

« L’espoir n’est pas une stratégie. » — souvent attribué à la culture des opérations (idée paraphrasée)

Conclusion : prochaines étapes durables

Si vous ne faites que deux choses, faites celles-ci : rendez la langue explicite dans l’URL, et faites varier chaque couche de cache selon la langue. La plupart des incidents de « mélange de langues » disparaissent quand le routage et le cache cessent d’improviser.

Puis faites le travail moins excitant : auditez suppress_filters, supprimez les transients agnostiques à la langue, traduisez et liez les taxonomies, et ajoutez un moniteur léger qui vérifie des pages clés par langue après chaque déploiement. WordPress multilingue peut être stable. Ça n’arrive juste pas par accident.

← Précédent
MySQL vs MariaDB : la guerre des sauvegardes sur VPS — mysqldump vs sauvegardes physiques
Suivant →
Les correctifs m’ont volé mon FPS : mythe, réalité et la vérité ennuyeuse

Laisser un commentaire