Tradução JSON do WordPress: Traduzindo JavaScript do Editor de Blocos

Você traduziu seu plugin. As strings PHP aparecem perfeitamente nas configurações de administração, nos modelos de frontend, nas notificações por e-mail - tudo localizado. Então você abre o editor de blocos, e cada rótulo em seu bloco Gutenberg personalizado está teimosamente, zombeteiramente em inglês. O botão "Adicionar Item", os títulos do painel do inspetor, o texto do espaço reservado. Seu arquivo .mo está carregado. Então, por que essas strings não estão sendo traduzidas?
Porque desde o WordPress 5.0 e a chegada do Gutenberg, as strings JavaScript não vêm do seu arquivo .mo de forma alguma. Elas precisam de um arquivo de tradução JSON do WordPress completamente separado, por script - e se você não o gerar, seu editor de blocos permanecerá em inglês, não importa quão completo esteja seu arquivo .po. Esta é uma das lacunas de localização mais comuns e confusas no desenvolvimento moderno do WordPress. Este guia explica exatamente por que isso acontece, como funciona o sistema de tradução JSON, os nomes de arquivo com hash MD5 que confundem a todos, e a cadeia de ferramentas completa para corrigi-lo.
Por Que Suas Strings do Editor de Blocos Permanecem em Inglês
Resposta curta: PHP e JavaScript usam dois sistemas de entrega de tradução inteiramente diferentes no WordPress, e seu arquivo .mo alimenta apenas o de PHP.
Dois Sistemas de Tradução, Um Plugin
Quando o WordPress executa load_plugin_textdomain(), ele lê seu arquivo .mo compilado na memória do PHP. Cada chamada __(), _e() e _x() em seu código PHP busca sua tradução lá. Isso funciona porque o PHP renderiza no lado do servidor - os dados .mo estão ali no mesmo processo.
JavaScript é diferente. Seu código de bloco é executado no navegador, muito depois de o PHP ter terminado. Ele não consegue acessar um arquivo .mo no lado do servidor. Em vez disso, o pacote @wordpress/i18n - o equivalente JS do Gettext, expondo __(), _x() e sprintf() aos seus scripts - espera que as traduções sejam entregues como um payload JSON anexado ao script específico que as necessita.
O Que Acontece com uma String JS Não Traduzida
Então, um bloco com strings como esta:
import { __ } from '@wordpress/i18n';
registerBlockType( 'myplugin/feature-box', {
title: __( 'Feature Box', 'myplugin' ),
edit: () => {
return <Button>{ __( 'Add Item', 'myplugin' ) }</Button>;
},
} );
nunca encontrará "Feature Box" ou "Add Item" em seu arquivo .mo, porque o navegador nunca lê arquivos .mo. Essas strings precisam chegar como JSON, conectadas a este identificador de script exato. Se você não configurou isso, as chamadas JS __() simplesmente retornam o inglês original - silenciosamente, sem erro no console.
Conectando Traduções JSON com wp_set_script_translations()
A ponte entre seu script e suas traduções JSON é uma única função PHP: wp_set_script_translations(). A resposta para "como o WordPress sabe qual arquivo JSON pertence a qual script" é: você informa, registrando o script e então declarando seu domínio de texto e a pasta onde o JSON reside.
Registrando o Script e Sua Pasta de Tradução
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'
);
} );
Quando o editor carrega myplugin-editor, o WordPress agora sabe que deve procurar na sua pasta languages/ por um arquivo JSON que corresponda a este script e ao local do usuário atual. Se encontrar um, ele injeta as traduções antes que seu script seja executado, e as chamadas JS __() são resolvidas corretamente. O identificador que você passa deve corresponder exatamente a um script registrado - um identificador incompatível ou ausente é o segundo motivo mais comum para que as traduções falhem silenciosamente.
O Nome de Arquivo com Hash MD5 Que Ninguém Espera
Aqui está o detalhe que desvia quase todo mundo. O arquivo JSON que o WordPress procura não tem um nome organizado como myplugin-fr_FR.json. Ele é nomeado com um hash MD5 do caminho de origem do script:
Decodificando o Padrão de Nome de Arquivo
myplugin-fr_FR-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.json
O padrão é {textdomain}-{locale}-{md5}.json, onde o hash é o MD5 do caminho relativo para o arquivo de script (por exemplo build/index.js) conforme registrado. O WordPress calcula este hash em tempo de execução para encontrar o JSON certo para o script certo. Se você nomear seu arquivo manualmente, o WordPress não o encontrará, e você jurará que o sistema está quebrado quando ele está apenas procurando por um nome de arquivo diferente.
Você não calcula o hash sozinho. O comando wp i18n do WP-CLI faz isso por você, e é exatamente por isso que você deve usar as ferramentas em vez de criar esses arquivos manualmente. Entender que o hash existe, no entanto, é o que economiza horas quando um arquivo JSON está presente em languages/ mas ainda é ignorado - é quase sempre uma incompatibilidade do hash do nome do arquivo porque o caminho do script mudou.
O Fluxo de Trabalho Completo: make-pot para make-json
A boa notícia é que você mantém suas traduções nos mesmos arquivos .po que já usa. O JSON é um artefato derivado gerado no final. A resposta para "eu mantenho as strings JS separadamente" é não - elas vivem no mesmo .pot/.po que suas strings PHP, e um comando extra separa as strings JS em JSON.
O Pipeline de Quatro Comandos
Aqui está o pipeline completo:
# 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
O make-pot do Passo 1 é inteligente o suficiente para escanear tanto seus arquivos .php quanto sua fonte .js/.jsx, então um único .po por localidade contém tudo. O make-json do Passo 4 lê cada .po traduzido, encontra as entradas que vieram de arquivos JavaScript e escreve um JSON com hash correto por script. A flag --no-purge também mantém as strings JS em seu .po, para que um make-mo posterior não as perca - sem ela, make-json remove as entradas JS do .po, o que surpreende as pessoas que executam os comandos na ordem errada.
Um arquivo JSON gerado se parece com um conjunto de tradução no formato 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" ]
}
}
}
O WordPress lê locale_data e o alimenta para @wordpress/i18n antes que seu script seja executado. Agora __( 'Add Item', 'myplugin' ) no navegador retorna Ajouter un élément, e seu editor de blocos está finalmente localizado.
Como Isso Difere do i18next JSON
Ambos os sistemas usam JSON, ambos visam JavaScript, e essa similaridade superficial causa confusão real. Eles não são intercambiáveis. O JSON do editor de blocos do WordPress é um payload por script derivado do Gettext, com hash MD5, consumido por @wordpress/i18n. O JSON do i18next é um arquivo de chave-valor plano ou aninhado consumido por react-i18next ou next-intl, com sua própria sintaxe de {{interpolação}} e convenções de chaves plurais.
Se você está trabalhando em React ou Next.js puro fora do WordPress, você quer a abordagem i18next, que cobrimos em traduzindo JSON i18next em React e Next.js. Dentro do WordPress, você quer o fluxo de trabalho make-json acima. Confundi-los - por exemplo, escrever manualmente JSON no estilo i18next plano e esperar que wp_set_script_translations() o carregue - simplesmente não funcionará, porque o WordPress está procurando o formato Jed com hash, não pares arbitrários de chave-valor.
Uma Fonte, Todos os Formatos Que Você Precisa
A fragilidade em tudo isso é a etapa de tradução no meio. Seu arquivo .po alimenta tanto o .mo (PHP) quanto o JSON (JavaScript), então uma única tradução malfeita - um %s deformado, uma tag <strong> quebrada, uma forma plural renomeada - contamina ambas as saídas de uma vez. E como as strings JS são carregadas assincronamente no navegador, um erro estrutural ali muitas vezes se manifesta como um rótulo em branco ou uma falha grave, em vez de um fallback elegante.
Um Upload, PHP e JavaScript Cobertos
É aqui que um pipeline de tradução que entende a estrutura Gettext ganha seu lugar. O SimplePoTranslate pega um .po ou .pot de origem e produz uma saída limpa e traduzida em múltiplos formatos a partir de um único upload - .po, .mo, .json, .php e .xliff - para que você não esteja juntando ferramentas separadas para suas camadas PHP e JavaScript. Seu Syntax Locking mantém %s, %1$s, {count} e HTML inline no lugar, o que é duplamente importante para as strings do editor de blocos onde um placeholder quebrado pode derrubar todo o painel do editor. Aprofundamos no modelo de uma fonte, muitas saídas em um arquivo de entrada, cinco formatos de saída.
Você ainda executa make-json para produzir os arquivos com hash que o WordPress espera - essa etapa é específica do WordPress e permanece em sua compilação. Mas a tradução em si, a parte mais provável de quebrar suas strings JS, é tratada por um motor sensível ao contexto em vez de um script de busca e substituição.
Conclusão
A razão pela qual seu editor de blocos permanece em inglês é estrutural, não um bug: a tradução JSON do WordPress é um sistema de entrega separado do arquivo .mo, construído especificamente porque os navegadores não conseguem ler dados Gettext do lado do servidor. Uma vez que você entende que as strings JavaScript precisam de JSON por script, com hash MD5 gerado por wp i18n make-json e conectado com wp_set_script_translations(), a correção é mecânica. Mantenha suas strings em um único .po, compile o .mo para PHP e execute make-json para JS.
Acerte a etapa de tradução e ambas as saídas funcionarão. Erre e você depurará painéis do editor em branco por uma tarde.
Pronto para traduzir suas strings JSON e PHP do WordPress a partir de uma fonte limpa? Experimente o SimplePoTranslate gratuitamente — não é necessário cartão de crédito. A camada gratuita traduz arquivos
.poe.potreais com Syntax Locking seguro para placeholders, para que suas strings do editor de blocos sejam enviadas corretamente.