Översättning av programvara med GNU gettext

GNU gettext är ett av de mest använda verktygen för internationalisering av fri programvara. Det erbjuder ett enkelt men flexibelt sätt att lokalisera programvara. Det har utmärkt stöd för pluralformer, kan lägga till ytterligare kontext till den översatta strängen och det finns en hel del verktyg som bygger på det. Naturligtvis har det utmärkt stöd i Weblate (se GNU gettext PO (Portable Object) filformatbeskrivning).

Observera

Om du tänker använda det i proprietär programvara, vänligen konsultera licensvillkoren först, det kanske inte är lämpligt för dig.

GNU gettext kan användas från en rad olika språk (C, Python, PHP, Ruby, JavaScript och många fler) och vanligtvis har UI-ramverken redan ett visst stöd för det. Standardanvändningen sker genom funktionsanropet gettext(), som ofta aliasas till _() för att göra koden enklare och lättare att läsa.

Dessutom tillhandahåller den pgettext()-anrop för att ge översättarna ytterligare kontext och ngettext() som kan hantera pluralformer enligt definitionen för målspråket.

Som ett allmänt utbrett verktyg har det många wrappers som gör det väldigt enkelt att använda. Istället för att manuellt anropa gettext som beskrivs nedan kan du prova någon av dem, till exempel intltool.

Översikt över arbetsflödet

GNU gettext använder flera filer för att hantera lokaliseringen:

  • PACKAGE.pot innehåller strängar som extraherats från din källkod, vanligtvis med hjälp av xgettext eller någon högnivåwrapper som intltool.

  • LANGUAGE.po innehåller strängar med en översättning till ett enda språk. Den måste uppdateras med msgmerge när PACKAGE.pot har uppdaterats. Du kan skapa nya språkfiler med msginit eller i Weblate.

  • LANGUAGE.mo innehåller binär representation av LANGUAGE.po och används vid programmets körning. Vanligtvis sparas den inte i versionshanteringen, utan genereras vid kompilering med hjälp av msgfmt. Om du vill ha den i versionshanteringen kan du generera den i Weblate med hjälp av tillägget Generera MO-filer.

Totalt sett ser arbetsflödet för GNU gettext ut så här:

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

Exempelprogram

Det enkla programmet i C som använder gettext kan se ut så här:

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

Extrahera översättningsbara strängar

När du har kod som använder gettext-anrop kan du använda xgettext för att extrahera meddelanden från den och lagra dem i en .pot:

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

Observera

Det finns alternativa program för att extrahera strängar från koden, till exempel pybabel.

Detta skapar en mallfil som du kan använda för att starta nya översättningar (med msginit) eller uppdatera befintliga efter kodändringar (för detta använder du msgmerge). Den resulterande filen är helt enkelt en strukturerad textfil:

# 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 ""

Varje msgid-rad definierar en sträng som ska översättas. Den speciella tomma strängen i början är filhuvudet som innehåller metadata om översättningen.

Starta ny översättning

När mallen är på plats kan vi börja vår första översättning:

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

Den nyskapade filen cs.po innehåller redan viss information. Viktigast av allt är att den har rätt pluralformer för det valda språket, och du kan se att antalet pluralformer har ändrats i enlighet med detta:

# 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 ""

Denna fil kompileras till en optimerad binär form, filen .mo som används av GNU gettext-funktionerna vid körning.

Uppdatering av strängar

När du har lagt till fler strängar eller ändrat några strängar i ditt program kör du xgettext igen, vilket genererar om mallfilen:

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

Sedan kan du uppdatera enskilda översättningsfiler så att de matchar de nyskapade mallarna (detta inkluderar att ordna om strängarna så att de matchar den nya mallen):

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

Observera

När du använder Weblate behöver du vanligtvis inte köra msgmerge manuellt. Weblate kan hantera detta automatiskt genom tillägget Uppdatera PO-filerna till att matcha POT (msgmerge), eller så kan du ladda upp den uppdaterade POT-filen med hjälp av uppladdningsmetoden Uppdatera källsträngar. Se Uppdatera filer på målspråket för mer information.

Importera till Weblate

För att importera en sådan översättning till Weblate behöver du bara definiera följande fält när du skapar komponenten (se Komponentkonfiguration för en detaljerad beskrivning av fälten):

Fält

Värde

Källkodsarkiv

URL till VCS-arkivet med ditt projekt

Filmask

po/*.po

Mall för nya översättningar

po/hello.pot

Filformat

Välj gettext PO-fil

Nytt språk

Välj Skapa ny språkfil

Och det var allt, nu är du redo att börja översätta din programvara!

Se även

Du kan hitta ett gettext-exempel med många språk i Weblate Hello-projektet på GitHub: <https://github.com/WeblateOrg/hello>.