Quem lida com o WordPress provavelmente já traduziu um tema, simplesmente buscando por strings nos arquivos e substituindo pelo equivalente em português. Isso é simples (até certo ponto) e eficaz, mas o WP oferece um sistema de tradução nativo, baseado no GNU Gettext
. Verdade que muitos desenvolvedores não dão a menor bola para isso, mas alguns sim! Um brinde a esses!
Nas próximas linhas vamos tentar mostrar como “internacionalizar” um tema ou plugin – usarei daqui em diante o termo genérico “addon” para ambos.
O modo grosseiro
O primeiro caso (citado acima) não requer muito conhecimento, apenas paciência. Onde achar uma frase traduzível, traduz e salva. Se eu fosse você, não apagaria as frases originais nesse caso. Mas isso só se aplica a temas e plugins que foram desenvolvidos sem essa preocupação – nos que usam as funções de tradução, o trabalho é bem mais fácil.
Se o addon que deseja traduzir tem suporte a tradução…
… as strings serão tratadas com as funções
_e() e
__(). Ou seja, o que você esperava que fosse assim:
<h2>Plugin title</h2>
aparece assim no código:
<h2><?php _e("Plugin title", "text_domain"); ?></h2>Aqui “
text_domain" é uma string definida pelo desenvolvedor para identificar o plugin no sistema de tradução e é definida pelas funções
load_theme_textdomain() e
load_plugin_textdomain() que associam o textdomain ao arquivo .mo, que é gerado a partir do catálogo PO.
Deve haver um ou mais arquivos com extensão .PO incluídos no pacote ou, de preferência, um arquivo .POT – que nada mais é que um .PO apenas com as strings originais, sem tradução, para servir de base para criação dos arquivos .PO. Para editar esses catálogos (PO ou POT), você pode usar o poEdit que é grátis e simples de usar.
Nesse caso, você não deve modificar os arquivos do addon – a tradução acontecerá apenas no catálogo, que deverá ser salvo seguindo o padrão definido pelo WP:
textdomain + ‘-’ + código da linguagem + ‘.po’ -> no nosso exemplo seria assim -> text_domain-pt_BR.po
Ao finalizar a tradução, salve o catálogo. Neste momento o poEdit gera automaticamente um arquivo de mesmo nome com extensão .MO – esse é que será usado pelo WordPress, o .PO é apenas para nós, humanos, conseguirmos ler e editar as strings.
Se o arquivo
text_domain-pt_BR.mo estiver presente no diretório informado ao declarar o textdomain, basta configurar a constante WP_LANG (em wp-config.php) para “pt_BR” e pronto, se tudo deu certo, o sistema aparecerá em português.
Mas você pode querer internacionalizar um addon que não oferece suporte à tradução…
Nesse caso teremos que fazer o que o desenvolvedor não fez, editando o código – portanto só é recomendado para quem tem alguma intimidade com o PHP.
A primeira coisa é declarar o textdomain e informar a localização dos arquivos .MO, usando uma das funções citada acima. A linha abaixo pode ser inserida em qualquer parte do arquivo principal do plugin, ou do arquivo functions.php, se estamos traduzindo um tema
// para plugins:
load_plugin_textdomain("mytextdomain", dirname(__FILE__)."/languages");
// para temas:
load_theme_textdomain("mytextdomain", dirname(__FILE__)."/languages");Aqui vamos criar o textdomain “mytextdomain” e salvar nossos arquivos no diretório languages, sob a raiz do addon. Agora é que começa a parte chata. Teremos que editar os arquivos, um por um em busca das strings que precisam ser traduzidas. Vamos então entender a diferença entre as funções que iremos usar:
<?php _e('string', 'textdomain'); ?>
a função _e() imprime a string traduzida na tela
<?php $str = __('string', 'textdomain'); ?>
a função __() retorna a string traduzida sem imprimir
Vamos ver um trecho de código a ser traduzido, como exemplo:
<?php
if(!empty($_POST['act'])) {
?><div class="updated fade"><p><?php
if($_POST['act'] = 'remove')
print deleteThing($_POST['mythings']) // função imaginária...
? "Your '{$_POST['mythings']}' was successfully removed."
: "Your '{$_POST['mythings']}' could not be removed!";
if($_POST['act'] = 'edit')
print editThing($_POST['mythings'])// função imaginária...
? "Your '{$_POST['mythings']}' was successfully edited."
: "Your '{$_POST['mythings']}' could not be edited!";
}
?></p></div><?php
?>
<h2>My things</h2>
<div class="wrap">
<form action="<?php print $PHP_SELF; ?>" method="post">
<label>Your cool things:
<select name="mythings">
<?php foreach($coolthings as $things) { ?>
<option value="<?php print sanitize_title($things['thing_title']); ?>"><?php print $things['thing_title']; ?></option>
<?php } ?>
</select>
</label>
<p class="butts">
<input type="button" class="button auto"<?php if(count($coolthings) == 0) print ' disabled="disabled"'; ?>
value="Edit" onclick=" this.form.act.value = 'edit'; this.form.submit();" />
<input class="auto button delete"<?php if(count($coolthings) == 0) print ' disabled="disabled"'; ?>
value="<?php _e("Edit", "mythings"); ?>"type="button" value="Delete" onclick="if(!confirm('Do you really want to delete this thing?'))
return; this.form.act.value = 'remove'; this.form.submit();" />
</p>
<input type="hidden" name="act" />
</form>
</div>Veja abaixo o mesmo código, já com o suporte à internacionalização:
<?php// essa linha deve aparecer apenas uma vez, em qualquer lugar - fora
// de funções (ou não, se você sabe quando executá-la)
load_plugin_text_domain("mythings", dirname(__FILE__).'/languages');
// começamos usando __(), pois o valor está sendo atribuído à variável $msg, não impresso
if(!empty($_POST['act'])) {
if($_POST['act'] = 'remove')
$msg = deleteThing($_POST['mythings']) // função imaginária...
? sprintf(__("Your '%s' was successfully removed.", "mythings"), $_POST['mythings'])
: sprintf(__("Your '%s' could not be removed!", "mythings"), $_POST['mythings']);
if($_POST['act'] = 'edit')
$msg = editThing($_POST['mythings'])// função imaginária...
? sprintf(__("Your '%s' was successfully edited.", "mythings"), $_POST['mythings'])
: sprintf(__("Your '%s' could not be edited!", "mythings"), $_POST['mythings']);
?>
<div class="updated fade">
<p><?php print $msg; ?></p>
</div>
<?php
}
?>
<?php
// para os valores que estavam escritos diretamente na parte HTML do documento,
// usamos a função _e(), que imprime a tradução, sem precisar de echos ou prints
?>
<h2><?php _e("My things", "mythings"); ?></h2>
<div class="wrap">
<form action="<?php print $PHP_SELF; ?>" method="post">
<label><?php _e("Your cool things:", "mythings"); ?>
<select name="mythings">
<?php foreach($coolthings as $things) { ?>
<option value="<?php print sanitize_title($things['thing_title']); ?>"><?php print $things['thing_title']; ?></option>
<?php } ?>
</select>
</label>
<p class="butts">
<input type="button" class="button auto"<?php if(count($coolthings) == 0) print ' disabled="disabled"'; ?>
value="<?php _e("Edit", "mythings"); ?>" onclick=" this.form.act.value = 'edit'; this.form.submit();" />
<input class="auto button delete"<?php if(count($coolthings) == 0) print ' disabled="disabled"'; ?>
type="button" value="<?php _e("Delete", "mythings"); ?>" onclick="if(!confirm('<?php _e("Do you really want to delete this thing?", "mythings"); ?>')) return; this.form.act.value = 'remove'; this.form.submit();" />
</p>
<input type="hidden" name="act" />
</form>
</div>Repare no uso da função sprintf() para trabalhar com strings que são mescladas com variáveis PHP. Isso simplifica a string evitando confusões na hora de traduzir – pode ser que outras pessoas tentem fazer isso, inclusive gente que não conhece PHP.
Não esqueça coisas que podem parecer detalhes, como rótulos dos botões, texto de alerts e conffirms Javascript, etc.
Bem, se não havia suporte… não existe nenhum arquivo .POT ou .PO…
Você pode usar o já citado poEdit para criá-lo ou copiar o texto abaixo para um arquivo de texto:
msgid ""
msgstr ""
"Project-Id-Version: n"
"Report-Msgid-Bugs-To: n"
"POT-Creation-Date: n"
"PO-Revision-Date: n"
"Last-Translator: seu nome <seu@email.com>n"
"Language-Team: n"
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=UTF-8n"
"Content-Transfer-Encoding: 8bitn"
"X-Poedit-KeywordsList: __;_en"
"X-Poedit-Basepath: .n"
"X-Poedit-SearchPath-0: .n"
Salve este arquivo como
mythings-pt_BR.po na pasta-mãe do plugin. A extensão .PO já associa o arquivo ao poEdit. Abra com um duplo clique. Clique então em “Atualizar catálogo” e as strings que estiverem dentro de chamadas às funções de tradução irão aparecer como num passe de mágica!
Clique em Ok e inicie sua tradução. Ao terminar, salve o arquivo e saia. Você verá que o arquivo
mythings-pt_BR.mo foi gerado. Coloque este arquivo no diretório que associamos ao nosso textdomain (./languages). Pronto!