Traduction JSON pour WordPress : Traduire le JavaScript de l'éditeur de blocs

Vous avez traduit votre extension. Les chaînes PHP s'affichent parfaitement dans les réglages d'administration, les modèles frontend, les notifications par e-mail – toutes sont localisées. Puis vous ouvrez l'éditeur de blocs, et chaque étiquette de votre bloc Gutenberg personnalisé est obstinément, ironiquement en anglais. Le bouton « Add Item », les titres du panneau d'inspection, le texte de l'espace réservé. Votre fichier .mo est chargé. Alors pourquoi ces chaînes ne sont-elles pas traduites ?
Car depuis WordPress 5.0 et l'arrivée de Gutenberg, les chaînes JavaScript ne proviennent pas du tout de votre fichier .mo. Elles nécessitent un fichier de traduction JSON pour WordPress complètement séparé, par script – et si vous ne le générez pas, votre éditeur de blocs reste en anglais, quelle que soit l'exhaustivité de votre fichier .po. C'est l'une des lacunes de localisation les plus courantes et les plus déroutantes dans le développement WordPress moderne. Ce guide explique exactement pourquoi cela se produit, comment fonctionne le système de traduction JSON, les noms de fichiers hachés en MD5 qui déroutent tout le monde, et l'ensemble de la chaîne d'outils pour y remédier.
Pourquoi les chaînes de votre éditeur de blocs restent en anglais
Réponse courte : PHP et JavaScript utilisent deux systèmes de livraison de traduction entièrement différents dans WordPress, et votre fichier .mo n'alimente que celui de PHP.
Deux systèmes de traduction, une seule extension
Lorsque WordPress exécute load_plugin_textdomain(), il lit votre fichier .mo compilé dans la mémoire PHP. Chaque appel __(), _e() et _x() dans votre code PHP y recherche sa traduction. Cela fonctionne parce que PHP s'exécute côté serveur – les données .mo sont directement présentes dans le même processus.
JavaScript est différent. Votre code de bloc s'exécute dans le navigateur, bien après que PHP a terminé son exécution. Il ne peut pas accéder à un fichier .mo côté serveur. Au lieu de cela, le paquet @wordpress/i18n – l'équivalent JS de Gettext, exposant __(), _x() et sprintf() à vos scripts – s'attend à ce que les traductions soient livrées sous forme de charge utile JSON attachée au script spécifique qui en a besoin.
Que se passe-t-il avec une chaîne JS non traduite
Ainsi, un bloc avec des chaînes comme ceci :
import { __ } from '@wordpress/i18n';
registerBlockType( 'myplugin/feature-box', {
title: __( 'Feature Box', 'myplugin' ),
edit: () => {
return <Button>{ __( 'Add Item', 'myplugin' ) }</Button>;
},
} );
ne trouvera jamais « Feature Box » ou « Add Item » dans votre fichier .mo, car le navigateur ne lit jamais les fichiers .mo. Ces chaînes doivent arriver sous forme de JSON, connectées à cet identifiant de script exact. Si vous n'avez pas configuré cela, les appels JS __() renvoient simplement l'anglais original – silencieusement, sans erreur dans la console.
Connexion des traductions JSON avec wp_set_script_translations()
Le pont entre votre script et ses traductions JSON est une seule fonction PHP : wp_set_script_translations(). La réponse à « comment WordPress sait quel fichier JSON appartient à quel script » est : vous le lui dites, en enregistrant le script puis en déclarant son domaine de texte et le dossier où se trouve le JSON.
Enregistrement du script et de son dossier de traduction
add_action( 'init', function () {
wp_register_script(
'myplugin-editor',
plugins_url( 'build/index.js', __FILE__ ),
array( 'wp-blocks', 'wp-i18n', 'wp-element' ),
'1.0.0'
);
// Tell WordPress where this script's JSON translations live
wp_set_script_translations(
'myplugin-editor', // the registered script handle
'myplugin', // text domain
plugin_dir_path( __FILE__ ) . 'languages'
);
} );
Lorsque l'éditeur charge myplugin-editor, WordPress sait maintenant qu'il doit rechercher dans votre dossier languages/ un fichier JSON correspondant à ce script et à la locale de l'utilisateur actuel. S'il en trouve un, il injecte les traductions avant l'exécution de votre script, et les appels JS __() se résolvent correctement. L'identifiant que vous transmettez doit correspondre exactement à un script enregistré – un identifiant non concordant ou manquant est la deuxième raison la plus courante pour laquelle les traductions échouent silencieusement.
Le nom de fichier haché en MD5 que personne n'attend
Voici le détail qui déroute presque tout le monde. Le fichier JSON que WordPress recherche n'est pas nommé de manière propre comme myplugin-fr_FR.json. Il est nommé avec un hachage MD5 du chemin source du script :
Décoder le modèle de nom de fichier
myplugin-fr_FR-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.json
Le modèle est {textdomain}-{locale}-{md5}.json, où le hachage est le MD5 du chemin relatif vers le fichier de script (par exemple build/index.js) tel qu'enregistré. WordPress calcule ce hachage à l'exécution pour trouver le bon JSON pour le bon script. Si vous nommez votre fichier manuellement, WordPress ne le trouvera pas, et vous jurerez que le système est en panne alors qu'il ne fait que rechercher un nom de fichier différent.
Vous ne calculez pas le hachage vous-même. La commande WP-CLI i18n le fait pour vous, et c'est précisément pourquoi vous devez utiliser les outils plutôt que de créer ces fichiers à la main. Comprendre que le hachage existe, cependant, est ce qui vous fera gagner des heures lorsqu'un fichier JSON est présent dans languages/ mais est toujours ignoré – c'est presque toujours une non-concordance de hachage de nom de fichier parce que le chemin du script a changé.
Le flux de travail complet : de make-pot à make-json
La bonne nouvelle est que vous conservez vos traductions dans les mêmes fichiers .po que vous utilisez déjà. Le JSON est un artefact dérivé généré à la fin. La réponse à « dois-je maintenir les chaînes JS séparément » est non – elles résident dans les mêmes fichiers .pot/.po que vos chaînes PHP, et une commande supplémentaire sépare les chaînes JS en JSON.
La pipeline de quatre commandes
Voici la pipeline complète :
# 1. Extract ALL translatable strings (PHP and JS) into one template
wp i18n make-pot . languages/myplugin.pot
# 2. Translate languages/myplugin-fr_FR.po as usual (Poedit, AI, etc.)
# 3. Compile the .mo for PHP strings (server-side, as always)
wp i18n make-mo languages/
# 4. Generate the MD5-hashed JSON files for JS strings
wp i18n make-json languages/ --no-purge
Le make-pot de l'étape 1 est suffisamment intelligent pour analyser à la fois vos fichiers .php et votre source .js/.jsx, de sorte qu'un seul fichier .po par locale contient tout. Le make-json de l'étape 4 lit chaque fichier .po traduit, trouve les entrées provenant des fichiers JavaScript et écrit un fichier JSON correctement haché par script. L'option --no-purge conserve également les chaînes JS dans votre fichier .po, afin qu'un make-mo ultérieur ne les perde pas – sans elle, make-json supprime les entrées JS du .po, ce qui surprend les personnes qui exécutent les commandes dans le mauvais ordre.
Un fichier JSON généré ressemble à un ensemble de traductions au format Jed :
{
"translation-revision-date": "2026-06-12 10:00+0000",
"generator": "WP-CLI/2.x",
"domain": "messages",
"locale_data": {
"messages": {
"": { "domain": "messages", "lang": "fr_FR" },
"Feature Box": [ "Bloc fonctionnalité" ],
"Add Item": [ "Ajouter un élément" ]
}
}
}
WordPress lit locale_data et le transmet à @wordpress/i18n avant l'exécution de votre script. Maintenant, __( 'Add Item', 'myplugin' ) dans le navigateur renvoie Ajouter un élément, et votre éditeur de blocs est enfin localisé.
En quoi cela diffère du JSON i18next
Les deux systèmes utilisent JSON, les deux ciblent JavaScript, et cette similarité de surface engendre une réelle confusion. Ils ne sont pas interchangeables. Le JSON de l'éditeur de blocs WordPress est une charge utile par script, dérivée de Gettext, hachée en MD5, consommée par @wordpress/i18n. Le JSON i18next est un fichier clé-valeur plat ou imbriqué consommé par react-i18next ou next-intl, avec sa propre syntaxe d'interpolation {{interpolation}} et ses conventions de clés plurielles.
Si vous travaillez avec du React ou Next.js pur en dehors de WordPress, vous souhaitez l'approche i18next, que nous abordons dans la traduction de JSON i18next dans React et Next.js. À l'intérieur de WordPress, vous souhaitez le flux de travail make-json ci-dessus. Les mélanger – par exemple, écrire manuellement du JSON plat de style i18next et s'attendre à ce que wp_set_script_translations() le charge – ne fonctionnera tout simplement pas, car WordPress recherche le format Jed haché, et non des paires clé-valeur arbitraires.
Une seule source, tous les formats dont vous avez besoin
La fragilité de tout cela réside dans l'étape de traduction au milieu. Votre fichier .po alimente à la fois le .mo (PHP) et le JSON (JavaScript), de sorte qu'une seule traduction bâclée – un %s corrompu, une balise <strong> cassée, une forme plurielle renommée – empoisonne les deux sorties à la fois. Et parce que les chaînes JS sont chargées de manière asynchrone dans le navigateur, une erreur structurelle y apparaît souvent comme une étiquette vide ou un plantage brutal plutôt qu'un retour arrière élégant.
Un seul téléchargement, PHP et JavaScript couverts
C'est là qu'une pipeline de traduction qui comprend la structure Gettext prend tout son sens. SimplePoTranslate prend un fichier source .po ou .pot et produit une sortie propre et traduite dans plusieurs formats à partir d'un seul téléchargement – .po, .mo, .json, .php et .xliff – de sorte que vous n'avez pas à assembler des outils séparés pour vos couches PHP et JavaScript. Son verrouillage syntaxique maintient %s, %1$s, {count} et les balises HTML en ligne en place, ce qui est doublement important pour les chaînes de l'éditeur de blocs où un espace réservé cassé peut faire planter tout le panneau de l'éditeur. Nous approfondissons le modèle une source, plusieurs sorties dans un fichier en entrée, cinq formats en sortie.
Vous exécutez toujours make-json pour produire les fichiers hachés que WordPress attend – cette étape est spécifique à WordPress et reste dans votre processus de compilation. Mais la traduction elle-même, la partie la plus susceptible de casser vos chaînes JS, est gérée par un moteur sensible au contexte plutôt que par un script de recherche et remplacement.
Conclusion
La raison pour laquelle votre éditeur de blocs reste en anglais est structurelle, et non un bogue : la traduction JSON pour WordPress est un système de livraison distinct du fichier .mo, conçu spécifiquement parce que les navigateurs ne peuvent pas lire les données Gettext côté serveur. Une fois que vous comprenez que les chaînes JavaScript nécessitent un JSON par script, haché en MD5, généré par wp i18n make-json et connecté avec wp_set_script_translations(), la solution est mécanique. Gardez vos chaînes dans un seul fichier .po, compilez le .mo pour PHP, et exécutez make-json pour JS.
Réussissez l'étape de traduction et les deux sorties suivront. Faites-le mal et vous passerez l'après-midi à déboguer des panneaux d'éditeur vides.
Prêt à traduire vos chaînes JSON et PHP de WordPress à partir d'une seule source propre ? Essayez SimplePoTranslate gratuitement – aucune carte de crédit requise. Le niveau gratuit traduit de vrais fichiers
.poet.potavec un verrouillage syntaxique sécurisé pour les espaces réservés, afin que les chaînes de votre éditeur de blocs soient livrées correctement.