GNU - pomoc při tvorbě programů: Gettext

3. 4. 2001
Doba čtení: 8 minut

Sdílet

Are you able to read (and sometime write) English texts well? If so, no need to read this, am I right? Možná, a možná taky ne. Pro ty, co si nemyslí, že jediným správným jazykem na světě je angličtina, je tady další díl seriálu. Bude o lokalizačním nástroji z dílny GNU, který se jmenuje Gettext.

Faktem i dnes stále zůstává, že spousta programů je psána, dokumentována a provozována v anglickém prostředí. Tím mám na mysli, že komunikační jazyk je angličtina. Tento přístup má zcela opodstatněně řadu výhod. Mezi hlavní patří, že na takovém projektu může pracovat libovolný člověk ovládající daný jazyk. Další může být to, že odpadnou problémy s kódováním cizojazyčných textů, jejich překlad, údržba a další náležitosti s tím spojené. Na druhou stranu se tím někdy poměrně podstatně omezí počet uživatelů tohoto projektu, prostě proto, že mu nerozumí.

Rozdělme problém na tři části. Vlastní program (zdrojové texty), dokumentaci k programu ve všech formách (WWW, man a info, tištěný manuál) a komunikační prostředí programu. Z výše uvedených důvodů vyplývá, že zdrojové texty programu je vhodné vést v jazyce, který je společný všem zúčastněným vývojářům projektu. Tímto jazykem dnes téměř bez výjimek bývá angličtina, protože na projektech často pracují lidé z celého světa nebo tomu tak může být někdy v budoucnosti. Tady tedy problém není.

Další je dokumentace. Pokud předpokládáme jazykově smíšené uživatele programu, pohybuje se situace v reálném světě někde mezi oběma hranicemi. Hlavní dokumentace je v angličtině, a pokud je třeba, překládá následně do nejpotřebnějších dalších jazyků. V případě „linuxových“ projektů však dokumentace v angličtině převládá. Je to zřejmě dáno množstvím textu, který by bylo třeba překládat, na straně jedné a množstvím lidí, kteří by to byli ochotni (a schopni) dělat.

A teď to poslední. Komunikace programu. Od problému dokumentace se liší v několika věcech.

  • Text, kterým program komunikuje, vzniká postupně na rozdíl od dokumentace, která vzniká po větších částech. Jednotlivé fragmenty textu v programu jsou často velmi malé a bývá snazší je přeložit.
  • Asi by vám připadala divná dokumentace, kde by jedna věta byla přeložena a další dvě ne. V případě textů v programu jsme si asi už zvykli, že je v jednom menu „Otevřít“, „Uložit“ a „Save as …“. Překlad jde tedy dělat postupně.
  • Každý uživatel používá program, ale zdaleka ne každý si čte dokumentaci. A to platí pro její libovolnou formu.

Tak jsme tedy pracně dospěli k závěru, že je třeba překládat texty v programu do několika jazyků. Tím se dostáváme k dvěma zásadním pojmům. Internacionalizace a Lokalizace. Často se pro ně používají zkratky I18n a L10n.

I18n znamená proces, při kterém je program vybaven tak, aby obecně podporoval vícejazyčné prostředí. Jedná se o zobecnění některých postupů tak, aby vyhovovaly pro různá národní prostředí. I18n je využití locales v programu, upravení vstupních a výstupních metod, aby například nebyly závislé na formátu zadaného/tištěného datumu a času. Jedná se tedy o zásahy do programu a programovacího sty­lu.

L10n je proces, který následuje po I18n. Při něm je program vybaven všemi potřebnými daty, aby skutečně podporoval (vybrané) jazykové prostředí. Jde tedy o doplnění dat příslušných locales a také přeložených textů ve vhodné formě. Při tom se data využívají metodami připravenými v předchozím kroku.

Někdy se všechny zmíněné aktivity souhrnně označují jako Native Language Support, zkráceně NLS. V převážné většině lze úlohy rozdělit následovně: Internacionalizaci zajišťují programátoři a Lokalizaci překladatelé, což mohou (ale nemusí) být odlišné skupiny lidí.

GNU Gettext zajišťuje systém pro tvorbu a užití lokalizovaných textových řetězců. Dosáhne toho vytvořením souborů pro každý jazyk, které obsahují identifikaci řetězců a následně přeložený text pro příslušný jazyk. Tyto soubory jsou následně upraveny do binární podoby a využity programem dle nastavených LOCALES. V programu jsou navíc použity inicializační rutiny a pro každý řetězec, který má být překládán, je užito příslušné makro, které se rozvine vefunkci zajišťující natažení odpovídajícího řetězce dle nastavení LOCALES z možných binárních forem.

A teď praxe. Nejprve změny v textu programu. Inicializační kód ukazuje následující výpis:

#ifdef ENABLE_NLS
#  include <libintl.h>
#  undef _
#  define _(String) dgettext (PACKAGE, String)
#  ifdef gettext_noop
#    define N_(String) gettext_noop (String)
#  else
#    define N_(String) (String)
#  endif
#else
#  define textdomain(String) (String)
#  define gettext(String) (String)
#  define dgettext(Domain,Message) (Message)
#  define dcgettext(Domain,Message,Type) (Message)
#  define bindtextdomain(Domain,Directory) (Domain)
#  define _(String) (String)
#  define N_(String) (String)
#endif

int main (int argc, char *argv[])
{
#ifdef ENABLE_NLS
  bindtextdomain (PACKAGE, PACKAGE_LOCALE_DIR);
  textdomain (PACKAGE);
#endif

  set_locale (LC_ALL, "");
...

Zde je vidět definice příslušných maker a následné volání inicializačních rutin. Hlavním makrem pro pozdější použití v programu je _(String). To volá vlastní překladovou rutinu. Další důležitá makra jsou použita při inicializaci. Ty zajišťují, že bude nalezen odpovídající binární soubor s překladem. Název souboru je PACKAGE a bude se hledat v adresáři PACKAGE_LOCALE_DIR. Dále je třeba inicializovat použití locales všeobecně. V příkladu použitá konstrukce zajistí nastavení podle proměnných prostředí. Ty se prohledávají (pro glibc) následujícím způsobem.

První se zkouší proměnná LC_ALL. Pokud není nastavena, zkouší se dále proměnné podle kategorie: LC_COLLATE pro regulární výrazy a třídění, LC_CTYPE pro konverze, case-sensitive porovnávání, LC_MESSAGES pro textové řetězce v programech, LC_MONETARY pro formátování měny, LC_NUMERIC pro formátování čísel a LC_TIME pro formátování výpisů datumu a času. Pokud ani tohle neuspěje, zkusí se ještě proměnná LANG. Hodnotou těchto proměnných musí být řetězec ve tvaru:

language[_territory][.codeset]  -->  cs_CZ.ISO-8859-2

Pokud nejsou nalezeny příslušné soubory (nebo je nastavena hodnota „C“), použijí se řetězce zkompilované v programu.

Jediné, co je nyní ještě třeba provést ve zdrojových kódech, je úprava vypisovaných textů. Ta je velmi jednoduchá. Provede se aplikací makra _() na potřebné řetězce. Následuje opět několik příkladů:

   ...
   perror(_("Could not send request to server"));
   ...
   g_print(_("Data from server: %d B\n"), size);
   ...
   g_print("*** %s\n\n", pos);
   ...
   printf (_("String `%s' has %d characters\n"), s, strlen (s));
   ...

A to je všechno. Alespoň co se zdrojového textu týče. Ještě je třeba vytvořit soubory pro překlad a následně jejich binární podobu. Pokud jste četli předchozí díly, možná si vzpomenete na makro pro Autoconf AM_GETTEXT. To není vůbec od věci. Zařídí vám kontrolu přítomnosti prostředí gettext při překladu a ve spolupráci s Automake vygeneruje potřebné zdroje pro Makefile. Přesto si popíšeme alespoň základní nástroje pro správu souborů s jazykovými verzemi, není jich zase tak moc.

Nejprve musíme vytvořit soubor PACKAGE.pot. Zkratka znamená Template for PO. PO je potom Portable Object, k tomu se vrátíme později. Soubor .pot můžeme samozřejmě vytvářet ručně, ale mnohem pohodlnější je použít program xgettext. Základní parametry jsou:

Tabulka č. 111
–add-coments přidá komentáře ze zdrojových textů do .pot
–default-domain=NAME výstupem bude NAME.po
–directory=DIR prohledává zadaný adresář na zdrojové texty
–files-from=FILE použij seznam zdroj. souborů v FILE
–keyword=WORD hledej klíčová slova WORD – často WORD=_

Výsledný soubor se často přejmenuje na PACKAGE.pot a slouží jako šablona pro všechny ostatní jazykové verze. Dalším krokem je zkopírování souboru PACKAGE.pot do souboru LANG.po pro každý podporovaný jazyk. Formát obou souborů je jako v následujícím příkladě:

#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: netinfo 0.1.3\n"
"POT-Creation-Date: 2001-02-18 12:22+0100\n"
"PO-Revision-Date: 2001-02-18 12:24:07+0100\n"
"Last-Translator: Tomas Kasparek <tomas.kasparek@seznam.cz>\n"
"Language-Team: Czech\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-2\n"
"Content-Transfer-Encoding: 8bit\n"
#: src/interface.c:106
msgid "NetInfo - show network information"
msgstr "NetInfo - zobrazí informace ze sítě "
#: src/interface.c:107 src/interface.c:1210
msgid "NetInfo"
msgstr "NetInfo"
#: src/interface.c:128
msgid "File"
msgstr "Soubor"
...

Soubor obsahuje hlavičku, kde je důležité správně nastavit kódování v „charset“. Následují jednotlivé texty ze zdrojových souborů. msgid je identifikace řetězce ve zdrojovém souboru a msgstr je případný překlad. V souboru .pot jsou tyto řádky prázdné – tedy msgstr "". Pro orientaci, odkud text pochází, slouží zakomentovaný řádek. Pokud se text v souboru vyskytuje vícekrát, je zde jen na jednom místě, jako pro druhý případ v příkladu. Takto připravíme všechny soubory pro překlad.

Pro případné pozdější doplnění a aktualizaci souborů .po/.pot je možno použít program msgmerge. Ten může některé položky souborů označit jako fuzzy a nebo obsolete. První znamená, že není v pořádku aktualizace této položky. Většinou pokud se změní text tak, že program neví k čemu ho teď přiřadit. Druhý atribut je uveden u položek, které už nadále nejsou obsaženy ve zdrojových textech. Tyto jsou zakomentovány a umístěny na konec souboru .po/.pot.

Posledním úkolem zůstává překlad do binární podoby. K tomu slouží program msgfmt. Ten převede soubor .po na odpovídající soubor .mo respektive .gmo pro nástroje GNU. Jde o překlad z Portable Object – čitelné podoby do tzv. Machine Object – binární podoby pro přímé použití.

A už zbývá jen vytvořené soubory přejmenovat na PACKAGE.mo a nainstalovat je na příslušné místo v systému (PACKAGE_LOCA­LE_DIR). A to je vše. Není to zase tak složité, jak to vypadá, a navíc ostatní nástroje jako Autoconf-Automake vám ušetří další spoustu práce.

ict ve školství 24

Systém Gettext se ještě pořád vyvíjí a tak má i své mouchy. Některé již byly zmíněny v diskuzi k předchozím článkům. Jde především o někdy problematickou detekci Autoconfem, dále o nemožnost konverze znakových sad, a dalších několik maličkostí. Nicméně pořád je to nejpoužívanější cesta, jak dát uživateli lokalizované prostředí jeho oblíbeného programu. A myslím, že ta cesta není vůbec špatná!

A na závěr tohoto článku ještě malý tip. Zkuste někdy oslnit svého Windousoidního přítele pěti spuštěnými verzemi jednoho programu. Jeden česky, druhý anglicky, další francouzsky, španělsky, a tak dál. Nejsem si sice úplně jist, ale tohle Bill myslím ještě nezvládá.

Autor článku