Termínem "locale" nebo "locales" se rozumí lokalizace funkcí poskytovaných knihovnou libc nebo glibc. Vzhledem k tomu, že služby této knihovny používá většina programů, ovlivní se tím chování téměř celého systému.
Locales umožňují, aby se jednotlivé programy chovaly podle národních zvyklostí: aby správně fungovalo rozlišování znaků na písmena, číslice a ostatní znaky, písmen na velká a malá, převody mezi malými a velkými písmeny (to jsou spíše záležitosti znakové sady než národních zvyklostí, ale i to je zahrnuto v locales), řazení (třídění) znaků a řetězců, aby programy používaly v dané zemi a jazyce obvyklý způsob zápisu peněžních údajů, výpisů čísel, data a času, názvů měsíců a dnů v týdnu. Locales úzce souvisí s katalogy zpráv, které umožňují, aby programy vypisovaly svá hlášení ve zvoleném jazyce. Vše je přitom možné měnit, aniž by bylo nutné programy rekompilovat!
Lokalizaci libc je možné nastavit buď kompletní, nebo pouze pro vybrané kategorie. Kategorie locales jsou uvedeny v tabulce.
Kategorie | Význam |
LC_COLLATE | Popisuje všechny znaky abecedy a určuje jejich pořadí při lexikografickém třídění. |
LC_CTYPE | Používána pro dělení znaků do tříd jako: malá, velká písmena, oddělovače, apod.. |
LC_MESSAGES | Používána pro zprávy zobrazované programy, tzv. katalogy zpráv. |
LC_MONETARY | Definuje formátování výpisů peněžních informací. |
LC_NUMERIC | Definuje formátování výpisů čísel. |
LC_TIME | Formát výpisu času a data, názvy a zkratky měsíců a dnů v týdnu. |
|
Kategorie LC_COLLATE
ovlivňuje chování funkcí strcoll()
a strxfrm()
pro porovnávání řetězců.
Kategorie LC_CTYPE
ovlivňuje chování funkcí deklarovaných
v souboru ctype.h
jako jsou isupper()
, toupper()
,
... a funkcí pro práci s vícebajtovými znaky jako jsou mblen()
,
wctomb()
.
Kategorie LC_MONETARY
a LC_NUMERIC
ovlivňují chování
funkce localeconv()
, na některých systémech bohužel i funkce ze
skupiny printf()
.
Kategorie LC_TIME
ovlivňuje chování funkce strftime()
.
Převážná většina programů volá funkci setlocale(LC_ALL, "")
,
která inicializuje locales podle hodnot proměnných prostředí,
jejichž názvy jsou stejné jako kategorie locales, a podle proměnných
LC_ALL
a LANG
.
V knihovně libc/glibc je vestavěn mechanismus, díky kterému se
vyhodnocování, jaká lokalizace se má použít pro určitou kategorii,
provádí následovně: Je-li nastavena proměnná LC_ALL
, použije se
její hodnota. Pokud nastavena není, pak se zkoumá nastavení proměnných
LC_kategorie
. Pokud není nastavena ani proměnná pro příslušnou
kategorii, rozhoduje nastavení proměnné LANG
. Není-li nastavena
ani proměnná LANG
, použije se implicitní hodnota "C". Některé
programy (například man 1.x) nastavení proměnných LC_*
ignorují
a řídí se pouze podle proměnné LANG
.
Zmíněné proměnné se nastavují na hodnoty tvaru:
jazyk[_ZEMĚ[.kódování]]
nebo lépe na některou z přezdívek definovaných v souboru
locale.alias
--- to je czech
pro češtinu,
slovak
pro slovenštinu. Díky přezdívce se hodnota převede na
cs_CZ.ISO-8859-2
nebo sk_SK.ISO-8859-2
, což udává jak
kódování, tak jazyk a zemi. Locale soubory se díky mechanismu zabudovanému
do knihovny libc hledají postupně v adresářích cs_CZ.ISO-8859-2
,
cs_CZ.iso88592
, cs_CZ
, cs.ISO-8859-2
,
cs.iso88592
a nakonec v cs
.
Zkratky jazyků stanovuje norma ISO 639, zkratky zemí norma
ISO 3166 (viz kapitola
příloha).
Kód češtiny je cs
, slovenštiny sk
, kód České
republiky CZ
, Slovenska SK
. Země se uvádí
z toho důvodu, že některými jazyky se mluví ve více zemích,
ve kterých se například používá jiné měna.
Poněkud matoucí je fakt, že kód češtiny se liší od kódu České republiky. Ale i mezi jazyky, které se používají v jediné zemi to není ojedinělý případ: podobně je to u da_DK (dánština, Dánsko), ja_JP (japonština, Japonsko). V případě cs_CZ je však o důvod ke zmatení více, protože kód češtiny je shodný s ISO kódem bývalého Československa.
Přípona .kódování
by měla sloužit k výběru správných
locale informací na počítačích, které pro určitý jazyk podporují
několik kódování (v Evropských podmínkách asi pouze ISO-8858-x a
Unicode), nebo naopak určité kódování nepodporují (například
ISO-8859-2). Bohužel v různých systémech se pro kódování používají
různé řetězce, takže je možné se setkat se zápisy ISO-8859-2
,
ISO_8859-2
, ISO8859-2
, iso88592
, za kterými
ještě někdy bývá dvojtečka a rok přijetí standardu kódování ISO-8859-2.
Pokud nemusíte, je lepší příponu .kódování
vůbec nepoužívat.
Přestože v mnoha návodech je lakonické sdělení "nastavte proměnnou
LANG
na cs_CZ
" (nebo cs
, někde dokonce ještě
chybně cz
), je užitečné se zamyslet, jestli skutečně chcete
nastavovat všechny kategorie. Nemusí se vám například líbit lokalizovaný
výpis příkazu ls -l
, v němž mohou být rozhozeny sloupce kvůli
různé délce zkratek názvů měsíců, některé programy nebo skripty mohou
dokonce při nastavení LC_ALL
nebo LANG
špatně fungovat
(zejména když na některých systémech nastavení locales ovlivňuje i takové
funkce jako je printf()
).
Navíc autoři programů ne vždy dobře rozlišují (pokud už vůbec
používají locales), kdy program produkuje výpisy pro uživatele a kdy
výpisy pro další zpracování nějakým programem (například zápis do
konfiguračního souboru). Ve druhém případě by se lokalizované funkce
neměly používat. Bohužel u mnoha programů to lze těžko odlišit (typickým
příkladem jsou řádkové příkazy jako příkaz ls -l
, který může
být jak vyvolán uživatelem, tak použit v jiném programu nebo skriptu).
Při psaní skriptů by mělo být vždy zajištěno, že skripty budou fungovat i při rozličně nastavené lokalizaci. Pokud se ve skriptech očekává, že výstupy programů budou v nelokalizované formě, musí být na začátku skriptu uvedeny příkazy
LC_ALL=C; export LC_ALL
LANG=C; export LANG
Nastavení proměnné LC_ALL
by mělo být postačující; proměnná
LANG
se nastavuje, aby správně fungovaly i programy, které
nesprávně používají pouze tuto proměnnou.
Pro práci se znakovou sadou ISO-8859-2 je velice vhodné mít nastavené
přinejmenším LC_CTYPE
. Bez něj nebudou fungovat některé
klávesnice v X, v textových editorech nebudou správně rozeznávány hranice
slov (takže například slovo užovka nepůjde v editoru vi smazat příkazem
dw
, ale bude nutné použít 3dw, jako by se jednalo o tři slova).
Knihovna glibc (alias libc6 nebo libc2) funguje s locales vcelku bez problémů (od verze 2.0.7 obsahuje i české locales). To se však nedá říci o knihovně libc5. Ve v Linuxu poměrně rozšířené verzi libc-5.3.12 jsou právě v oblasti locales chyby, které při nevhodných hodnotách v sekci LC_TIME způsobí pád programu localedef. Obvykle se doporučuje libc verze alespoň 5.4.17.
Na systémech, které mají libc i glibc je nutné u již přeložených
programů zjistit, s jakou variantou knihovny libc pracují. Bohužel
například v systému Red Hat 5.x příkaz ldd `which program`
zcela bezostyšně lže.
Dále je třeba mít odpovídající utility `localedef' a `locale', a pokud chcete překládat katalogy zpráv, tak také utility `gencat' a `msgfmt'.
Nejdříve zjistěte v jakém stavu má váš systém locales: Příkazem
localedef --help
zjistíte (podle řádku s textem System's directory for character
maps:
), v jakém adresáři jsou očekávány mapy znaků. U systémů
s libc5 to bývá /usr/share/nls/charmap
, u systémů s glibc
/usr/share/i18n/charmaps
. Další popis je psán pro systémy
s libc5, protože uživatelé glibc systémů pravděpodobně už budou mít
locales nainstalované. Pokud ne, musí si v následujícím popisu
upravit cesty v příkazech podle vlastního systému. Pozor na 's',
které ve jménech adresářů locale(s) a charmap(s) někde je a někde
není!
Pokud v tomto adresáři chybí soubor s popisem znakové sady ISO-8859-2
(zkuste žolíkový zápis ISO*8859-2*), budete si muset stáhnout soubor
http://www.inf.upol.cz/~michlv/ftp/WG15-collection.tar.gz
rozbalit jej do libovolného adresáře a z rozbaleného adresáře
WG15-collection
zkopírovat adresáře charmaps
a
locales
včetně obsahu do adresáře, ve kterém se očekává
adresář s mapami znaků:
cp -r WG15-collection/charmaps /usr/share/nls/charmap
cp -r WG15-collection/locales /usr/share/nls/locale
Pokud už na vašem systému zmíněné soubory jsou, bude stačit nainstalovat
pouze české nebo slovenské locales. Alespoň české by už měly být v glibc
2.0.7; a pokud jste instalovali českou klávesnici do X11 z balíku
XKB-czsk-forcedIM*
, máte české a slovenské locales už také
nainstalované. O tom je možné se přesvědčit příkazem
locale -a | grep ^cs
Vždy je však vhodné stáhnout zdrojový soubor s českými locales
ftp://ftp.fi.muni.cz/pub/localization/locale/cs_CZ
a umístit jej do adresáře /usr/share/nls/locale
. V mnoha
balících je totiž stará verze tohoto souboru, ve které mimo jiné
nemusí fungovat správně třídění.
Zdrojový soubor s českými locales je nutné přeložit do binární podoby pro libc příkazy
cd /usr/share/locale
mkdir -p cs_CZ/LC_MESSAGES
localedef -c -i /usr/share/nls/locale/cs_CZ \
-f /usr/share/nls/charmap/ISO*8859-2* ./cs_CZ
pro glibc příkazy
mkdir -p /usr/share/locale/cs_CZ/LC_MESSAGES
localedef -c -i /usr/share/i18n/locales/cs_CZ \
-f /usr/share/i18n/charmaps/ISO-8859-2 /usr/share/locale/cs_CZ
Výsledkem bude adresář /usr/share/locale/cs_CZ
obsahující sadu
souborů se jmény LC_*
a adresář LC_MESSAGES
.
Výše uvedené příkazy můžete také použít, pokud se vám nelíbí, že
v dodávaných českých locales jsou na místě zkratek jmen měsíců použity
plné názvy, což způsobuje rozházení výpisu produkovaného příkazem ls
-l
. Stačí opravit názvy uvedené v sekci abmon
ve zdrojovém
souboru /usr/share/i18n/locales/cs_CZ
a locales znovu přeložit.
Pak už můžete nastavovat proměnné LC_CTYPE
, LC_COLLATE
nebo LC_ALL
a LANG
a kochat se, jak to funguje.
Například aby správně fungovala klasifikace znaků, je třeba nastavit
proměnnou prostředí LC_CTYPE
. V shellech bash a ksh se to
provede příkazem
export LC_CTYPE=cs_CZ
v csh a tcsh příkazem
setenv LC_CTYPE cs_CZ
a ve starších shellech vycházejících z Bourne shellu, sh, a jsh příkazem
LC_CTYPE=cs_CZ
export LC_CTYPE
Pro nastavení všech kategorií locales je třeba nastavit proměnnou
prostředí LANG
nebo LC_ALL
.
Pokud chcete, aby česky byly pouze zprávy vypisované programy,
nastavte proměnnou LC_MESSAGES
:
export LC_MESSAGES=cs_CZ
Při nastavení některé z proměnných prostředí ovládajících locales
se najde v souboru /usr/share/locale/locale.alias
odpovídající
hodnota, podle které se vybere adresář z /usr/share/locale
(nebo se tento adresář vybere přímo). V adresáři odpovídajícím vybranému
jazyku jsou binární soubory vygenerované příkazem localedef
z textových locales. Jména souborů jsou následující:
LC_COLLATE, LC_MESSAGES, LC_NUMERIC, LC_CTYPE, LC_MONETARY, LC_TIME.
Pokud některý soubor smažete a vytvoříte místo něj adresář se stejným jménem, pak se po novém vygenerování souborů utilitou `localedef' soubor umístí do tohoto adresáře se jménem začínajícím předponou SYS_.
Tohoto se nejčastěji využívá u LC_MESSAGES
, kdy jsou do tohoto
adresáře umísťovány katalogy zpráv pro různé programy. Katalog zpráv je
soubor, v němž jsou umístěny všechny zprávy vypisované programem nebo
skupinou programů a jehož záměnou lze docílit změny jazyka, kterým
program komunikuje.
V případě katalogů zpráv lze předepsat, kde se tyto katalogy mají hledat,
pomocí proměnné prostředí
NLSPATH
.
Např: export NLSPATH=/usr/share/locale/%L/LC_MESSAGES/%N.cat kde %N znamená jméno katalogu. %L znamená jméno lokalizace (kategorie LC_MESSAGES).
Za oba tyto atributy si program dosadí správné hodnoty, když potřebuje informace o zvyklostech země.
Pokud je třeba v NLSPATH
zadat více adresářů, oddělují se
dvojtečkou.
Jedním z cílů lokalizace je umožnit, aby si uživatel mohl vybrat, v jakém jazyce budou jednotlivé programy vypisovat svá hlášení, menu, apod., a to bez rekompilace programů. Aby to bylo možné, musí být texty všech zpráv, které program produkuje, z něj vytaženy a umístěny v nějakém externím souboru (katalogu zpráv). Jeho záměnou za jiný se dosáhne změny všech zpráv. V současné době se používají dva způsoby jak to provést:
ad a) Starší a také při programování pracnější řešení. Paralelně s programem je třeba vytvářet textový katalog zpráv, ze kterého se nakonec pomocí `gencat' vytvoří katalog v binárním tvary (který mívá příponu .cat). Pro přístup do katalogu se v programu používají funkce catopen, catclose, catgets (popis viz man).
ad b) Novější řešení, jednodušší pro tvorbu a údržbu programů. Pro jeho použití je nutný balík gettext. V programu se pak každá zpráva, kterou vypisuje, napíše jako argument funkce gettext. Po změně programu pak stačí vygenerovat seznam všech zpráv, které jsou v programu, a tyto zprávy přeložit. Nový katalog lze také spojit se starým, již přeloženým. Zdrojový tvar katalogu se pro použití programem převádí do binárního tvaru tzv. objektu zpráv (soubor mívá příponu .mo nebo .gmo) utilitou `msgfmt'.
Při obou postupech se výsledný katalog zpráv umístí do adresáře
/usr/share/locale/cs_CZ.*/LC_MESSAGES
.
Nejprve je třeba zjistit, zda je aplikace napsaná internacionálně. To lze několika způsoby:
LANG
nebo LC_ALL
na příslušný jazyk ---
např: export LC_ALL=cs_CZ
.
Pokud aplikace internacionálně napsaná není, pak máme smůlu, nebo ji můžeme upravit.
Je-li internacionálně napsaná, je třeba zjistit, který ze dvou výše popsaných, pak může používat jeden ze dvou mně známých způsobů a to:
Tento způsob je starší a pravděpodobně přenositelnější na jiné operační systémy. Všechny zprávy z programu jsou vytaženy do katalogu (mívá příponu .msg, .m), který může být rozdělen na několik částí. Katalog vypadá následovně:
$set cislo #Nazev $ #Jmeno_zpravy1 dále poznámky, třeba originální zpráva # Vlastní zpráva 1 $ #Jmeno_zpravy2 dále poznámky, třeba originální zpráva # Vlastní zpráva 2 ...
Řádky které začínají znakem '$', nejsou umístěny do výsledného katalogu. '$set cislo #Nazev' je příkaz, který udává číslo množiny a její symbolický název. Tímto musí začínat každý katalog. Dále pokračujeme vždy po dvou řádcích, přitom první řádek je nepovinný, pouze definuje symbolické jméno zprávy.
$ #Jmeno_zpravy1 dále poznámky, třeba originální zpráva # Vlastní zpráva 1
Takže pokud máme napsán katalog, můžeme jej zkompilovat příkazem gencat, jehož syntaxe je:
gencat [-new] [-or] [-lang C|C++|ANSIC] catfile msgfile [-h <header-file>]... -new generuje nový katalog -lang pro jaký jazyk má být vytvořen hlavičkový soubor catfile jak se má jmenovat katalog msgfile soubor zpráv -h hlavičkový_soubor generovat hlavičkový soubor tohoto jména
Po kompilaci již máme výsledný katalog, který pak stačí umístit do adresáře s ostatními katalogy.
!!!POZOR!!! Pokud překládáme katalog z jiného jazyka, je třeba zachovat pořadí i počet zpráv.
Příklad:
Uděláme malý příklad použití tohoto způsobu:
#include <locale.h> #include <stdio.h> #include <features.h> #include <nl_types.h> #include "test-cat.h" char main() { nl_catd cfd; setlocale(LC_MESSAGES, ""); cfd = catopen("test", MCLoadBySet); printf("%s\n", catgets(cfd, TestlistSet, TestlistWelcome, "Welcome in test program")); /* "Welcome in test program" se vypíše v~případě, že zpráva není v~katalogu nalezena, nebo katalog nebyl nalezen */ printf("%s\n", catgets(cfd, TestlistSet, TestlistAuthor, "Author: Vladimir Michl")); catclose(cfd); return 0; }
$set 10 #Testlist $ #Welcome # Vítejte v~testovacím programu $ #Autor # Autor: Vladimir Michl
gencat -new -lang C test.cat test.m -h test-cat.h
gcc -o test test.c
NLSPATH
do tohoto adresáře
mv test.cat /usr/share/locale/cs_CZ.iso88592/LC_MESSAGES export NLSPATH=/usr/share/locale/%L/LC_MESSAGES/%N.cat
LC_ALL
a spustíme test
LC_ALL=C test LC_ALL=cs_CZ.ISO-8859-2 test
K tomuto způsobu je třeba si stáhnout GNU gettext z nějakého FTP. Já osobně považuji tento způsob za daleko lepší než první.
Katalogy zpráv bývají ve dvou tvarech a to s příponou .pot a .po. S příponou .pot jsou to pouze zprávy vytažené ze zdrojáků, kdežto soubory s příponou .po jsou soubory, které již mají alespoň některé zprávy přeložené. .po soubor má následující strukturu:
#
jsou komentářem.#:
jsou odkazy, kde se
řetězec vyskytuje ve zdrojovém kódu.msgid "xxxxxx"
nebo msgid ""
začíná
původní řetězec uvedený ve zdrojovém kódu.msgstr "xxxxxx"
nebo msgstr ""
začíná
přeložený řetězec.#,
informují o stavu překladu
nebo formátu.
Výjimku tvoří první dvojice msgid
a msgstr
, kde se
uvádí informace o konkrétním katalogu.
Příklad .po souboru:
# Czech translations for the GNU gettext messages # Copyright (C) 1996 Free Software Foundation, Inc. # Vladimir Michl <Vladimir.Michl@upol.cz>, 1997. # Version: 1.1 # msgid "" msgstr "" "Project-Id-Version: fileutils 3.15a\n" "POT-Creation-Date: 1997-01-26 00:26-0600\n" "PO-Revision-Date: 1997-04-23 20:21+0200\n" "Last-Translator: Vladimir Michl <Vladimir.Michl@upol.cz>\n" "Language-Team: Czech <cs@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-2\n" "Content-Transfer-Encoding: 8-bit\n" #: src/chgrp.c:144 msgid "group number" msgstr "číslo skupiny" #: src/chgrp.c:290 src/chmod.c:234 src/chown.c:254 src/cp-aux.c:86 #: src/dd.c:1121 src/df.c:576 src/dircolors.c:121 src/du.c:238 #: src/install.c:625 src/ln.c:347 src/ls.c:2805 src/mkdir.c:70 src/mkfifo.c:68 #: src/mknod.c:79 src/mv.c:407 src/rm.c:543 src/rmdir.c:94 src/sync.c:46 #: src/touch.c:262 msgid "" "\n" "Report bugs to fileutils-bugs@gnu.ai.mit.edu" msgstr "" "\n" "Popis chyb zasílejte na adresu fileutils-bugs@gnu.ai.mit.edu (pouze " "anglicky),\n" "popis chyb v~překladu zasílejte na adresu cs@li.org" Pokud se těsně před msgid vyskytne řádek #, fuzzy, pak je tento řetězec považován za neúplně přeložený. Např: #, fuzzy msgid "OK" msgstr "xxx"
Pro práci s katalogem existuje několik utilit:
Zkompilované katalogy musí mít příponu .mo.
Příklad použití:
#include <locale.h> #include <stdio.h> #include <libintl.h> #define PACKAGE "test" #define LOCALEDIR "/usr/share/locale" char main() { setlocale(LC_MESSAGES, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); printf("%s\n", gettext("Welcome in test program")); printf("%s\n", gettext("Author: Vladimir Michl")); return 0; }
xgettext test.c
# Czech translation of test. # Vladimir Michl <Vladimir.Michl@upol.cz>, 1997. # msgid "" msgstr "" "Project-Id-Version: test 1.0\n" "POT-Creation-Date: 1997-05-02 16:28+0000\n" "PO-Revision-Date: 1997-05-02 18:00+0200\n" "Last-Translator: Vladimir Michl <Vladimir.Michl@upol.cz>\n" "Language-Team: Czech <cs@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-2\n" "Content-Transfer-Encoding: 8bit\n" #: test.c:13 msgid "Welcome in test program" msgstr "Vítejte v~testovacím programu" #: test.c:14 msgid "Author: Vladimir Michl" msgstr "Autor: Vladimír Michl"
msgfmt -v -o test.mo messages.po
gcc -o test test.c -lintl
mv test.mo /usr/share/locale/cs_CZ.iso88592/LC_MESSAGES LC_ALL=C test LC_ALL=cs_CZ.ISO-8859-2 test
Manuálové stránky: catopen(3), catclose(3), catgets(3), locale(7), setlocale(3) Info stránky: gettext
Přehled programových balíků, které jsou lokalizovány i které na lokalizaci teprve čekají naleznete na http://www.inf.upol.cz/~michlv/gnu-loc.shtml.
Katalogy je možné získat na
http://www.inf.upol.cz/~michlv/ftp/catalogs/
nebo
ftp://ftp.fi.muni.cz/pub/localization/locale/catalogs/.
Katalogy pro LyX jsou na
ftp://merkur.econ.muni.cz/pub/lyx.cz/.
Pro KDE jsou české a slovenské katalogy k dispozici v podadresářích
po/cs/
a po/sk/
jednotlivých adresářů na
ftp://ftp.ujep.cz/pub/OS/Linux/terezka.ujep.cz/kde/src/.
Některé kódy jazyků podle normy ISO 639:
arabština `ar', čínština `zh', čeština `cs', dánština `da', holandština `nl', angličtina `en', Esperanto `eo', finština `fi', francouzština `fr', hebrejština `he', němčina `de', řečtina `el', maďarština `hu', irština `ga', italština `it', indonéština `id', japonština `ja', korejština `ko', latina `la', norština `no', perština `fa', polština `pl', portugalština `pt', ruština `ru', slovenština `sk', slovinština `sl', španělština `es', švédština `sv', turečtina `tr', ukrajinština `uk'.
Některé kódy zemí podle normy ISO 3166:
Česká republika `CZ', Slovensko `SK', Německo `DE', Francie `FR', Polsko `PL', Rakousko `AT', Spojené státy `US'.