Traduzindo software usando GNU gettext

GNU gettext é uma das ferramentas mais utilizadas para internacionalização de software livre. Ele fornece uma maneira simples, mas flexível, de localizar o software. Ele tem um ótimo suporte para plurais, pode adicionar mais contexto ao texto traduzido e há várias ferramentas construídas em torno dele. Claro que tem um ótimo suporte no Weblate (veja a descrição do formato de arquivo GNU gettext).

Nota

Se você estiver prestes a usá-lo em um software proprietário, consulte o licenciamento primeiro. Ele pode não ser adequado para você.

GNU gettext pode ser usado a partir de uma variedade de linguagens (C, Python, PHP, Ruby, JavaScript e muitos mais) e geralmente os frameworks de UI já vêm com algum suporte para isso. O uso padrão é através da chamada de função gettext(), que geralmente é apelidada de _() para tornar o código mais simples e fácil de ler.

Além disso, ele fornece a chamada pgettext() para fornecer contexto adicional para tradutores e ngettext() que pode lidar com tipos plurais conforme definido para o idioma alvo.

Como uma ferramenta amplamente difundida, ela possui muitos wrappers que tornam seu uso realmente simples, ao invés de invocar manualmente o gettext descrito abaixo, você pode querer tentar um deles, por exemplo, o intltool.

Visão geral do fluxo de trabalho

O GNU gettext usa vários arquivos para gerenciar a localização:

  • PACKAGE.pot contém textos extraídos de seu código-fonte, normalmente usando xgettext ou alguns wrappers de alto nível como intltool.

  • LANGUAGE.po contém textos com uma tradução para um único idioma. Ele deve ser atualizado por msgmerge uma vez que o PACKAGE.pot seja atualizado. Você pode criar novos arquivos de idioma usando msginit ou dentro do Weblate.

  • LANGUAGE.mo contém a representação binária de LANGUAGE.po e é usado no tempo de execução do aplicativo. Normalmente não é mantido em um controle de versão, mas gerado em tempo de compilação usando msgfmt. No caso de desejar tê-lo no controle de versão, pode gerá-lo no Weblate usando a extensão Gerar arquivos MO.

No geral, o fluxo de trabalho do GNU gettext é assim:

digraph translations { graph [fontname = "sans-serif", fontsize=10]; node [fontname = "sans-serif", fontsize=10, shape=note, margin=0.1, height=0]; edge [fontname = "monospace", fontsize=10]; "Source code" -> "PACKAGE.pot" [label=" xgettext "]; "PACKAGE.pot" -> "LANGUAGE.po" [label=" msgmerge "]; "LANGUAGE.po" -> "LANGUAGE.mo" [label=" msgfmt "]; }

Amostra de programa

O programa simples em C usando gettext pode ter a seguinte aparência:

#include <libintl.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int count = 1;
    setlocale(LC_ALL, "");
    bindtextdomain("hello", "/usr/share/locale");
    textdomain("hello");
    printf(
        ngettext(
            "Orangutan has %d banana.\n",
            "Orangutan has %d bananas.\n",
            count
        ),
        count
    );
    printf("%s\n", gettext("Thank you for using Weblate."));
    exit(0);
}

Extraindo textos traduzíveis

Assim que tiver o código usando as chamadas gettext, você pode usar xgettext para extrair mensagens dele e armazená-las em um .pot:

$ xgettext main.c -o po/hello.pot

Nota

Existem programas alternativos para extrair textos do código, por exemplo pybabel.

Isso cria um arquivo de modelo, que você pode usar para iniciar novas traduções (usando msginit) ou atualizar as existentes após a mudança de código (você usaria msgmerge para isso). O arquivo resultante é simplesmente um arquivo texto estruturado:

# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-10-23 11:02+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"

#: main.c:14
#, c-format
msgid "Orangutan has %d banana.\n"
msgid_plural "Orangutan has %d bananas.\n"
msgstr[0] ""
msgstr[1] ""

#: main.c:20
msgid "Thank you for using Weblate."
msgstr ""

Cada linha msgid define um texto a ser traduzido, o texto vazio especial no início é o cabeçalho do arquivo contendo metadados sobre a tradução.

Iniciando nova tradução

Com o modelo no lugar, podemos começar nossa primeira tradução:

$ msginit -i po/hello.pot -l cs --no-translator -o po/cs.po
Created cs.po.

O recém-criado cs.po já tem algumas informações preenchidas. Mais importante ainda, ele obteve a definição de formas plurais apropriada para o idioma escolhido e você pode ver que o número de plurais mudou de acordo com isso:

# Czech translations for PACKAGE package.
# Copyright (C) 2015 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Automatically generated, 2015.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-10-23 11:02+0200\n"
"PO-Revision-Date: 2015-10-23 11:02+0200\n"
"Last-Translator: Automatically generated\n"
"Language-Team: none\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ASCII\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"

#: main.c:14
#, c-format
msgid "Orangutan has %d banana.\n"
msgid_plural "Orangutan has %d bananas.\n"
msgstr[0] ""
msgstr[1] ""
msgstr[2] ""

#: main.c:20
msgid "Thank you for using Weblate."
msgstr ""

Este arquivo é compilado em um formato binário otimizado, o arquivo .mo usado pelas funções do GNU gettext em tempo de execução.

Atualizando textos

Depois de adicionar mais textos ou alterar alguns textos em seu programa, você executa novamente xgettext que gera novamente o arquivo de modelo:

$ xgettext main.c -o po/hello.pot

Em seguida, você pode atualizar arquivos de tradução individuais para corresponder aos modelos recém-criados (isso inclui reordenar os textos para corresponder ao novo modelo):

$ msgmerge --previous --update po/cs.po po/hello.pot

Importando para o Weblate

Para importar tal tradução para o Weblate, tudo que você precisa definir são os seguintes campos ao criar o componente (veja Configuração de componente para uma descrição detalhada dos campos):

Campo

Valor

Repositório do código-fonte

URL do repositório VCS com seu projeto

Máscara de arquivo

po/*.po

Modelo para novas traduções

po/hello.pot

Formato de arquivo

Escolha arquivo PO gettext

Novo idioma

Escolha Criar novo arquivo de idioma

E é isso. Agora você está pronto para começar a traduzir seu software!

Ver também

Você pode encontrar um exemplo de gettext com muitos idiomas no projeto Weblate Hello no GitHub: <https://github.com/WeblateOrg/hello>.