WordPress JSON-översättning: Översätta Block Editor JavaScript

Du översatte ditt tillägg. PHP-strängarna visas perfekt i administratörsinställningarna, frontend-mallarna, e-postmeddelandena – allt lokaliserat. Sedan öppnar du blockredigeraren, och varje etikett i ditt anpassade Gutenberg-block är envist, hånfullt på engelska. "Add Item"-knappen, rubrikerna i inspektörspanelen, platshållartexten. Din .mo-fil är laddad. Så varför översätts inte dessa strängar?
Därför att sedan WordPress 5.0 och Guttenbergs ankomst kommer JavaScript-strängar inte alls från din .mo-fil. De behöver en helt separat, per-skript WordPress JSON-översättningsfil – och om du inte genererar den förblir din blockredigerare på engelska oavsett hur komplett din .po-fil är. Detta är en av de vanligaste och mest förvirrande lokaliseringsluckorna i modern WordPress-utveckling. Denna guide förklarar exakt varför det händer, hur JSON-översättningssystemet fungerar, de MD5-hashade filnamnen som ställer till det för alla, och hela verktygskedjan för att åtgärda det.
Varför dina blockredigerarsträngar förblir engelska
Kort svar: PHP och JavaScript använder två helt olika system för översättningsleverans i WordPress, och din .mo-fil matar bara det PHP-baserade systemet.
Två översättningssystem, ett tillägg
När WordPress kör load_plugin_textdomain() läser den din kompilerade .mo-fil till PHP-minnet. Varje __(), _e() och _x()-anrop i din PHP-kod letar upp sin översättning där. Detta fungerar eftersom PHP renderar på serversidan – .mo-datan finns direkt i samma process.
JavaScript är annorlunda. Din blockkod körs i webbläsaren, långt efter att PHP har slutförts. Den kan inte nå en serverside-.mo-fil. Istället förväntar sig paketet @wordpress/i18n – JS-motsvarigheten till Gettext, som exponerar __(), _x() och sprintf() för dina skript – att översättningar levereras som en JSON-nyttolast kopplad till det specifika skript som behöver dem.
Vad händer med en oöversatt JS-sträng
Så ett block med strängar som detta:
import { __ } from '@wordpress/i18n';
registerBlockType( 'myplugin/feature-box', {
title: __( 'Feature Box', 'myplugin' ),
edit: () => {
return <Button>{ __( 'Add Item', 'myplugin' ) }</Button>;
},
} );
kommer aldrig att hitta "Feature Box" eller "Add Item" i din .mo-fil, eftersom webbläsaren aldrig läser .mo-filer. Dessa strängar måste komma som JSON, kopplade till denna exakta skripthandtag. Om du inte har ställt in det, returnerar JS __()-anropen helt enkelt originalet på engelska – tyst, utan fel i konsolen.
Koppla JSON-översättningar med wp_set_script_translations()
Bryggan mellan ditt skript och dess JSON-översättningar är en enda PHP-funktion: wp_set_script_translations(). Svaret på "hur vet WordPress vilken JSON-fil som hör till vilket skript" är: du berättar det, genom att registrera skriptet och sedan deklarera dess textdomän och mappen där JSON-filen finns.
Registrera skriptet och dess översättningsmapp
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'
);
} );
När redigeraren laddar myplugin-editor vet WordPress nu att den ska leta i din languages/-mapp efter en JSON-fil som matchar detta skript och den aktuella användarens språk. Om den hittar en, injicerar den översättningarna innan ditt skript körs, och JS __()-anropen löses korrekt. Handtaget du skickar måste exakt matcha ett registrerat skript – ett felaktigt eller saknat handtag är den näst vanligaste anledningen till att översättningar tyst misslyckas.
Det MD5-hashade filnamnet ingen förväntar sig
Här är detaljen som spårar ur nästan alla. JSON-filen WordPress letar efter är inte namngiven något prydligt som myplugin-fr_FR.json. Den är namngiven med en MD5-hash av skriptets källväg:
Avkoda filnamnsmönstret
myplugin-fr_FR-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.json
Mönstret är {textdomain}-{locale}-{md5}.json, där hashen är MD5-summan av den relativa sökvägen till skriptfilen (till exempel build/index.js) som den är registrerad. WordPress beräknar denna hash vid körning för att hitta rätt JSON för rätt skript. Om du namnger din fil manuellt kommer WordPress inte att hitta den, och du kommer att svära att systemet är trasigt när det bara letar efter ett annat filnamn.
Du beräknar inte hashen själv. WP-CLI i18n-kommandot gör det åt dig, vilket är exakt anledningen till att du måste använda verktygen snarare än att skapa dessa filer för hand. Att förstå att hashen existerar är dock det som sparar dig timmar när en JSON-fil finns i languages/ men fortfarande ignoreras – det är nästan alltid en felmatchning i filnamns-hashen eftersom skriptsökvägen ändrades.
Det fullständiga arbetsflödet: make-pot till make-json
Den goda nyheten är att du behåller dina översättningar i samma .po-filer som du redan använder. JSON är en härledd artefakt som genereras i slutet. Svaret på "måste jag underhålla JS-strängar separat" är nej – de finns i samma .pot/.po som dina PHP-strängar, och ett extra kommando delar upp JS-strängarna till JSON.
Den fyrastegskedjan
Här är den fullständiga kedjan:
# 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
Steg 1:s make-pot är smart nog att skanna både dina .php-filer och din .js/.jsx-källa, så en enda .po per språk håller allt. Steg 4:s make-json läser varje översatt .po, hittar de poster som kom från JavaScript-filer och skriver ut en korrekt hashad JSON per skript. Flaggan --no-purge behåller även JS-strängarna i din .po, så en senare make-mo förlorar dem inte – utan den tar make-json bort JS-posterna från .po, vilket överraskar folk som kör kommandona i fel ordning.
En genererad JSON-fil ser ut som en Jed-format översättningsuppsättning:
{
"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 läser locale_data och matar det till @wordpress/i18n innan ditt skript körs. Nu returnerar __( 'Add Item', 'myplugin' ) i webbläsaren Ajouter un élément, och din blockredigerare är äntligen lokaliserad.
Hur detta skiljer sig från i18next JSON
Båda systemen använder JSON, båda riktar sig till JavaScript, och den ytliga likheten orsakar verklig förvirring. De är inte utbytbara. WordPress blockredigerings-JSON är en Gettext-härledd, MD5-hashad, per-skript nyttolast som konsumeras av @wordpress/i18n. i18next JSON är en platt eller nästlad nyckel-värdefil som konsumeras av react-i18next eller next-intl, med sin egen {{interpolation}}-syntax och konventioner för pluralnycklar.
Om du arbetar i vanlig React eller Next.js utanför WordPress, vill du ha i18next-metoden, som vi behandlar i translating i18next JSON in React and Next.js. Inom WordPress vill du ha make-json-arbetsflödet ovan. Att blanda ihop dem – till exempel att skriva platt JSON i i18next-stil för hand och förvänta dig att wp_set_script_translations() ska ladda den – kommer helt enkelt inte att fungera, eftersom WordPress letar efter det hashade Jed-formatet, inte godtyckliga nyckel-värde-par.
En källa, varje format du behöver
Skörheten i allt detta är översättningssteget i mitten. Din .po-fil matar både .mo (PHP) och JSON (JavaScript), så en enda misslyckad översättning – en förvanskad %s, en trasig <strong>-tagg, en ombenämnd pluralform – förgiftar båda utdata samtidigt. Och eftersom JS-strängar laddas asynkront i webbläsaren, uppstår ett strukturellt fel där ofta som en tom etikett eller en hård krasch snarare än en graciös återgång.
En uppladdning, PHP och JavaScript täcks
Det är här en översättningspipeline som förstår Gettext-strukturen förtjänar sin plats. SimplePoTranslate tar en käll-.po- eller .pot-fil och producerar ren, översatt utdata i flera format från en enda uppladdning – .po, .mo, .json, .php och .xliff – så du behöver inte sy ihop separata verktyg för dina PHP- och JavaScript-lager. Dess Syntax Locking håller %s, %1$s, {count} och inbyggd HTML på plats, vilket är dubbelt viktigt för blockredigerarsträngar där en trasig platshållare kan slå ut hela redigeringspanelen. Vi går djupare in på modellen med en källa, många utdata i one file in, five formats out.
Du kör fortfarande make-json för att producera de hashade filerna som WordPress förväntar sig – det steget är WordPress-specifikt och stannar i din byggprocess. Men själva översättningen, den del som mest sannolikt bryter dina JS-strängar, hanteras av en kontextmedveten motor istället för ett sök-och-ersätt-skript.
Slutsats
Anledningen till att din blockredigerare förblir engelska är strukturell, inte en bugg: WordPress JSON-översättning är ett separat leveranssystem från .mo-filen, byggt specifikt eftersom webbläsare inte kan läsa serverside Gettext-data. När du väl förstår att JavaScript-strängar behöver per-skript, MD5-hashad JSON som genereras av wp i18n make-json och kopplas med wp_set_script_translations(), är lösningen mekanisk. Behåll dina strängar i en .po, kompilera .mo för PHP och kör make-json för JS.
Får du översättningssteget rätt följer båda utdata. Får du det fel så får du felsöka tomma redigeringspaneler en hel eftermiddag.
Redo att översätta dina WordPress JSON- och PHP-strängar från en ren källa? Prova SimplePoTranslate gratis — inget kreditkort krävs. Den kostnadsfria nivån översätter riktiga
.po- och.pot-filer med platshållarsäker Syntax Locking, så dina blockredigerarsträngar levereras korrekta.