Software de traducción utilizando gettext de GNU

GNU gettext es una de las herramientas más utilizadas para la internacionalización de software libre. Ofrece una forma sencilla y flexible de localizar software. Ofrece una excelente compatibilidad con plurales, permite añadir contexto a la cadena traducida y existen numerosas herramientas basadas en ella. Por supuesto, es muy compatible con Weblate (consulte la descripción del formato de archivo GNU gettext PO (Portable Object)).

Nota

Si es sobre el usarlo en software propietario, consulte primero la licencia, tal vez no es apropiado para ti.

GNU gettext se puede utilizar desde una gran variedad de lenguajes (C, Python, PHP, Ruby, JavaScript y muchos más) y, por lo general, los marcos de interfaz de usuario ya incluyen cierta compatibilidad con ello. El uso estándar es a través de la invocación a la función gettext(), que a menudo se pone el alias como _() para que el código sea más sencillo y fácil de leer.

Además, proporciona un`pgettext()`invocado para proporcionar contexto adicional a los traductores y ngettext() que puede manejar tipos plurales según lo definido para el idioma de destino.

Como es una herramienta ampliamente utilizada, tiene muchos envoltorios que hacen que su uso sea realmente simple; en lugar de invocar manualmente gettext como se describe a continuación, es posible que desees probar uno de ellos, por ejemplo, intltool.

Descripción general del flujo de trabajo

El gettext de GNU utiliza varios archivos para gestionar la localización:

  • PACKAGE.pot contiene cadenas extraídas desde su código fuente, típicamente usando xgettext o alguna cobertura de alto nivel tal como intltool.

  • LANGUAGE.po contiene cadenas con una traducción a idioma único. Tiene que ser actualizado por msgmerge una vez que el PACKAGE.pot sea actualizado. Puedes crear archivos de idiomas nuevos utilizando msginit o con Weblate.

  • LANGUAGE.mo contiene una representación binaria de LANGUAGE.po y se utiliza en tiempo de ejecución de la aplicación. Normalmente no se mantiene bajo control de versiones, sino que se genera en tiempo de compilación mediante msgfmt. En caso de que desee tenerlo en el control de versiones, puede generarlo en Weblate utilizando el complemento Generar archivos MO.

En general, el flujo de trabajo de GNU gettext se ve así:

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 "]; }

Muestra del programa

El programa simple en C que usa gettext podría verse así:

#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);
}

Extraer cadenas traducibles

Una vez que tenga el código utilizando las invocaciones a gettext, puede utilizar xgettext para extraer mensajes del mismo y almacenarlos en un .pot:

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

Nota

Existen programas alternativos para extraer cadenas del código, por ejemplo pybabel.

Esto crea un archivo de plantilla, que puede utilizar para iniciar nuevas traducciones (utilizando msginit) o actualizar las existentes tras un cambio en el código (para ello, utilizaría msgmerge). El archivo resultante es simplemente un archivo de texto estructurado:

# 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 línea msgid define una cadena para traducir, la cadena vacía especial al principio es el encabezado del archivo que contiene metadatos sobre la traducción.

Iniciar traducción nueva

Con la plantilla en su lugar, podemos iniciar nuestra primera traducción:

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

El archivo cs.po recién creado ya contiene cierta información. Lo más importante es que tiene la definición correcta de las formas plurales para el idioma elegido y se puede ver que el número de plurales ha cambiado en consecuencia:

# 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 archivo se compila en una forma binaria optimizada, el archivo .mo utilizado por las funciones GNU gettext en tiempo de ejecución.

Actualizar cadenas

Una vez que agregue más cadenas o cambie algunas cadenas en su programa, ejecute nuevamente xgettext el cual regenera el archivo de plantilla:

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

Cuando pueda actualizar archivos de traducción individuales para coincidir plantillas creadas nuevamente (esto incluye reordenar las cadenas para que coincidan con la plantilla nueva):

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

Nota

Cuando utilice Weblate, típicamente no necesita ejecutar msgmerge manualmente. Weblate puede ggestionar esto automáticamente a través del complemento Actualizar archivos PO para que coincidan con POT (msgmerge), o puede subir el archivo POT de la actualización utilizando el método de subida Update source strings. Consulte Actualización de archivos del idioma destino para los detalles.

Importar a Weblate

Para importar dicha traducción a Weblate, todo lo que necesita definir son los siguientes campos al crear el componente (consulte Configuración de componentes para obtener una descripción detallada de los campos):

Campo

Valor

Repositorio de código fuente

La URL del repositorio VCS con su proyecto

Máscara de archivos

po/*.po

Plantilla para traducciones nuevas

po/hello.pot

Formato de archivo

Elegir gettext PO file

Idioma nuevo

Seleccione Crear nuevo archivo de idioma

Y eso es todo, ¡ahora puede comenzar a traducir tu software!

Ver también

Puedes encontrar un ejemplo de gettext con muchos idiomas en el proyecto Weblate Hello en GitHub: <https://github.com/WeblateOrg/hello>.