« No translation found » : ce message est apparu du jour au lendemain sur les fiches « réalisations » d’un site vitrine d’artisan menuisier, alors que le reste du site fonctionnait parfaitement en français et en anglais depuis des mois. Le type de contenu personnalisé « realisation » venait pourtant d’être ajouté récemment par un second développeur, sans que personne ne signale de changement majeur dans la configuration de Polylang.
Ce cas illustre un piège classique des sites multilingues qui évoluent dans le temps : un type de contenu ajouté après la mise en place initiale de la traduction peut se retrouver mal enregistré auprès de l’extension de traduction, sans erreur visible en apparence.
Symptôme : un message qui n’apparaît que sur le nouveau type de contenu
Le message « No translation found » remplaçait le contenu attendu uniquement sur les pages du type « realisation », jamais sur les articles ni sur les pages classiques. Les fiches existaient bien en base de données, dans les deux langues, avec un lien de traduction visible dans l’éditeur. Le problème ne se situait donc pas dans le contenu lui-même, mais dans la façon dont Polylang tentait de résoudre l’URL demandée vers la bonne traduction.
- Le contenu existe en base, dans les deux langues, avec la relation de traduction enregistrée
- Le message apparaît uniquement à l’affichage de l’URL publique, pas dans l’éditeur
- Aucune erreur PHP dans les journaux, seulement ce message côté affichage
Diagnostic : un ordre de chargement en cause
Le type de contenu personnalisé « realisation » était déclaré par une extension maison, chargée via un fichier de plugin classique avec le hook init à la priorité par défaut, soit 10. Polylang, de son côté, a besoin de connaître les types de contenu à rendre traduisibles avant de résoudre les requêtes publiques, et cette connaissance passe par le filtre pll_get_post_types.

Le souci venait du fait que l’extension maison enregistrait le type de contenu à la priorité 10 sur init, exactement la même priorité que celle utilisée en interne par Polylang pour construire sa liste de types de contenu traduisibles. Selon l’ordre alphabétique des noms de fichiers de plugin (un détail d’implémentation de WordPress rarement documenté), Polylang construisait parfois sa liste avant que le type de contenu ne soit enregistré, et parfois après, ce qui expliquait le comportement intermittent observé par le client.
Reproduire le bug pour le confirmer
Pour confirmer cette hypothèse, j’ai ajouté un simple error_log() dans le filtre pll_get_post_types, afin de vérifier la présence ou l’absence du type « realisation » dans le tableau reçu, à chaque rechargement de page. Le résultat alternait effectivement selon des facteurs indépendants du contenu lui-même, ce qui confirmait un problème d’ordre d’exécution plutôt qu’un problème de configuration.
Correctif : forcer une priorité explicite
La solution retenue a consisté à enregistrer le type de contenu personnalisé plus tôt, avec une priorité explicite inférieure à celle utilisée par Polylang, afin de garantir que la déclaration soit toujours terminée avant que l’extension de traduction ne construise sa liste :
add_action( 'init', 'enregistrer_cpt_realisation', 5 );
function enregistrer_cpt_realisation() {
register_post_type( 'realisation', array(
'public' => true,
'show_in_rest' => true,
'label' => __( 'Réalisations', 'menuiserie-theme' ),
) );
}
Le changement de priorité de 10 à 5 a suffi à rendre le comportement systématique et correct, sans jamais plus revoir le message d’erreur, y compris après plusieurs cycles de désactivation et réactivation d’extensions par le client lui-même.
Prévention : un test systématique à chaque nouvelle extension
Depuis ce cas, j’ajoute à ma liste de vérifications post-déploiement un test spécifique : après l’ajout ou la modification de tout type de contenu personnalisé sur un site multilingue, je vide le cache d’objets, je recharge chaque URL du nouveau type dans chaque langue configurée, et je vérifie l’absence de tout message d’erreur de traduction avant de considérer le déploiement terminé.
Un ordre de chargement des greffons qui semble fonctionner neuf fois sur dix reste un bug, pas une coïncidence favorable.
Ce qu’il faut retenir de ce cas
Ce cas ne relevait ni d’un bug de Polylang ni d’une erreur de configuration visible, mais d’une collision de priorité entre deux hooks init exécutés au même niveau. La leçon à retenir : sur un site multilingue, tout type de contenu personnalisé doit être déclaré avec une priorité de hook explicite et documentée, jamais laissée à la valeur par défaut quand plusieurs extensions se partagent le même point d’entrée.