Jak zrobić ustawienia lokalne w Linux-ie. (Locales)
Peeter Joot, peeter_joot@vnet.ibm.com
v1.5, 21 Lipca 1997.
WWeerrssjjaa ppoollsskkaa:: BBaarrttoosszz MMaarruusszzeewwsskkii BB..MMaarruusszzeewwsskkii@@jjttzz..oorrgg..ppll
v1.4, 4 Listopada 1997
Dokument ten opisuje jak skonfigurować twojego Linux-a, aby móc używać
pakietu "Locales", czyli ustawień narodowych. Dokument ten jest
napisany w standardzie ISO-8859-2. Wersja oryginalna znajduje się pod
adresem ftp.icm.edu.pl . Nowsza wersja zawiera uaktualnione wskazania na
katalog zawierający jądra na ftp.icm.edu.pl
______________________________________________________________________
Spis treści
1. Wprowadzenie.
2. Co to w ogóle jest pakiet "Locales"?
3. Uwagi.
4. Czego potrzebujesz.
5. Instalacja wszystkiego.
6. I co teraz?
7. Naprawa błędu "catopen".
8. Pytania i odpowiedzi.
8.1 msgcat
9. Zakończenie.
9.1 Od tłumacza.
______________________________________________________________________
11.. WWpprroowwaaddzzeenniiee..
To jest naprawdę opis tego co musiałem zrobić, żeby działał u mnie
pakiet "Locales". Zrobiłem to tylko dla zabawy, i pomyślałem, że może
niektórzy chcą sami spróbować. Jak już raz wszystko poustawiasz,
powinieneś móc używać aplikacji korzystających z NLS, wraz z twoimi
lokalnymi ustawieniami. Już niedługo pakiet "Locales" powinien być
częścią standardowych dystrybucji i większość z tego co tu napisałem
będzie niepotrzebne.
22.. CCoo ttoo ww ooggóóllee jjeesstt ppaakkiieett ""LLooccaalleess""??
Jest to pakiet, który zawiera ustawienia specyficzne dla twojego
kraju. (zapis daty, czasu, specjalne litery itp.) Ustawień tych nie
powineneś zapisywać na stałe w swoich programach.
Jeśli masz na swoim komputerze zainstalowane ustawienia lokalne dla
różnych krajów/języków, to poprzez następujące zmienne możesz
kontrolować zachowanie programów korzystających z nich. Ustawieniem
domyślnym jest ustawienie wg. standardu C lub POSIX zapisane na stałe
w "libc".
LLAANNGG
-- ustawia jakiego języka używamy; może być zmienione przez
zmienną LC_xxxx,
LLCC__CCOOLLLLAATTEE
-- ustawia porządek sortowania,
LLCC__CCTTYYPPEE
-- definicje znaków, duże i małe litery... używane jest to przez
takie funkcje jak: toupper, tolower, islower, isdigit itp.
LLCC__MMOONNEETTAARRYY
-- definicja formatu liczb związanych z pieniędzmi. Są tu
definicje separatora tysięcy, separatora ułamkowego, symbolu
pieniądza (zł) i miejsce, gdzie należy go umieścić,
LLCC__NNUUMMEERRIICC
-- separatory tysięcy i ułamkowe oraz grupowanie numeryczne,
LLCC__TTIIMMEE
-- definicja formatu czasowego i datowego. Są tu zdefiniowane
np. dni tygodnia, miesiące,
LLCC__MMEESSSSAAGGEESS
-- wyrażenia Nie i Tak,
LLCC__AALLLL
-- ustawia jakiego języka używamy i zmienia wszystkie inne
zmienne LC_xxxx.
Oto niektóre ustawienia, a jest ich znacznie więcej:
eenn__CCAA
-- kanadyjski angielski,
eenn__UUSS
-- amerykański angielski,
ddee__DDEE
-- niemiecki niemiecki,
ffrr__FFRR
-- francuski francuski.
Jeśli piszesz program i chcesz, aby można go było używać na całym
świecie respektuj ustawienia lokalne. Najważniejszym powodem jest to,
że nie każdy będzie używał tego samego zestawu znaków czy strony
kodowej co ty.
Upewnij się, że nie robisz czegoś takiego w swoich programach:
/* sprawdź czy to litera */
if ( (( c >= 'a') && ( c <= 'z' )) ||
(( c >= 'A') && ( c <= 'Z' )) ) { ... }
Jeśli napiszesz coś takiego, to zakładasz, że użytkownik będzie używał
tylko podstawowych znaków z kodu ASCII i nie bierzesz pod uwagę, iż
może używać strony kodowej specyficznej dla swojego kraju. Pomija to
takie znaki jak np. a-umlaut, które zostałoby użyte w środowisku
niemieckim. Zamiast tego powinieneś raczej używać funkcji, które
respektują lokalne ustawienia, jak np. isalpha(). Jeśli twój program
wyraźnie wymaga tylko podstawowych znaków ASCII (US-ASCII), dalej
używasz funkcji isalpha(), ale musisz także ustawić zmienną LANG albo
LC_CTYPE albo LC_ALL na "C" lub użyć funkcji setlocale(LC_CTYPE, "C").
Ustawienia lokalne pozwalają na dużą elastyczność i robią pewne
założenia, o których programista mógł zapomnieć.
Na przykład nie możesz z góry założyć pozycji danego znaku na stronie
kodowej. Nic nie stoi na przeszkodzie, żebyś np. stworzył sobie stronę
kodową, na której "A" byłoby na pozycji 99 a nie 65.
Podstawową ideą jest to, że różni ludzie mówią różnymi językami,
przetsrzegają różnych reguł sortowania, używają różnych stron kodowych
i mieszkają w różnych krajach. Ustawienia lokalne i funkcje, które ich
przstrzegają dają środki na respektowanie takich rzeczy i
odpowiedniego ich traktowanie. Nie wymaga to dużego nakładu pracy,
tylko trochę innego sposobu myślenia podczas pisania takich programów.
33.. UUwwaaggii..
ˇ Aby ustawienia lokalne na moim komputerze działały musiałem odnowić
kilka rzeczy. No i tak: ftp.torun.pdi.net w katalogu
/pub/nls/locale. znajdują się wszystkie potrzebne programy. Nie
wiedziałem, że jest osobny pakiet "Locales" i jakoś się domyśliłem,
że trzeba mieć zainstalowane odpowiednie biblioteki libc i lib.so.
Z tego powodu to HOWTO jest w większości zapisem tego co ja
musiałem zrobić, żeby odnowić biblioteki. Jeśli zrobisz to w taki
sposób jak ja, będziesz musiał mieć system ELF, albo zmienić swój
na taki, jak już ustawisz swoje lokalne definicje.
ˇ Wszystko co robiłem, aby odnowić swój system, to to samo, co jest
potrzebne, aby przejść z a.out na ELF. Jeśli tego nie zrobiłeś,
albo jeśli zrobiłeś to poprzez reinstalację Linux-a, powinieneś
zdobyć ostatnią wersję ELF-HOWTO. Jest to wspaniały podręcznik, w
którym znajdziesz dodatkowe wskazówki dotyczące instalacji
bibliotek libc, ld.so i innych odnowień do ELF-a.
ˇ Przed instalacją czegokolwiek, przeczytaj odpowiednie pliki
dostarczone wraz z wersją instalacyjną (README itp.). Jeśli
popsujesz sobie coś, bo źle zinterpretowałeś coś, co ja tutaj
napisałem, albo przez (oby nie) zrobienie czegoś co ja zrobiłem,
nie wiń mnie proszę.
ˇ Jeśli zapomnisz zainstalować nową bibliotekę libc albo ld.so, to
możesz doprowadzić nawet do tego, że nie będziesz mógł wystartować
systemu. Także lepiej mieć pod ręką dyskietkę startową, i upewnij
się, że wszelkie krytyczne albo niezamienialne dane są
zarchiwizowane.
44.. CCzzeeggoo ppoottrrzzeebbuujjeesszz..
Kilka rzeczy musisz sobie ściagnąć. Wszystko czego potrzebujesz
znajdziesz na ftp.icm.edu.pl Kiedy ja instalowałem u siebie ustawienia
lokalne używałem libc-5.2.18, która jest teraz troche przestarzała.
Jak na razie powiedziano mi, że bieżącą wersją jest 5.4.17 i taką też
umieszczam w opisie. Przypuszczalnie libc-5.4.17 będzie przestarzała
zanim zdążysz mrugnąć więc po prostu użyj najnowszej dostępnej wersji.
Rozważ użycie glibc (gnu libc) zamiast Linux libc 5 w pracach
unaradawiających (internalizacyjnych). Glibc jest w pełni unarodowiona
i ma pełne wsparcie dla programowania narodowego tak samo jak jest w
pełni przenaszalna FIXME i ma wbudowaną obsługę wątków. Prawie cała
internalizacja zrobiona w libc 5 wzięta zostałą z glibc. Lokalizacje i
mapy klawiszy dla glibc są powiązane z dodatkami o lokalizacjami
glibc.
Jeśli jesteś za używaniem glibc, to możesz pominąć to mini-howto.
Dołączanie dodatków lokalizacyjnych do kompilacji i instalacji glibc
jest trywialne i opisane jest w dokumentacji do instalacji glibc.
ednak ostrzegam, że pełna aktualizacja nie jest trywialnym zadaniem!
Mam nadzieję, że RedHat (którego używam) wypuści niedługo dystrybucję
opartą na glibc, bo jakoś nie uśmiecha mi się rekompilacja całego
mojego systemu. Wszystkie poniższe pakiety możesz znaleźć pod adresem
ftp.icm.edu.pl w katalogu /pub/Linux/sunsite/GCC oprócz "make" -
/pub/Linux/sunsite/devel/make oraz jądra - /pub/Linux/kernel/
ˇ ustawienia lokalne i źródła zestawów znaków -- to jest to, co
kompilujesz, używając localedef,
ˇ libc-5.4.x.bin.tar.gz -- biblioteki dzielone w wersji ELF dla
bibliotek C i MATH. Zauważ, że prekompilowany dla biblioteki
libc-5.4.17 program "localedef" ma przypuszczalnie w sobie błąd i
tworzy LC_CTYPE ze złą liczbą magiczną. Oznacza to przypuszczalnie,
że jakaś stara wersja "localedef" dostała się do dystrybucji.
ˇ libc-5.4.x.tar.gz -- źródła bibliotek dzielonych w wersji ELF -
będziesz tego potrzebował, aby skompilować localedef,
ˇ make-3.74.tar.gz -- może będziesz musiał skompilować "make", tak
aby zawierał łatę na tzw. dirent bug,
ˇ release.libc-5.4.x -- ta wersja zawiera łatę, która pozwala
skompilować "make", minęło już sporo czasu odkąd powstał błąd w
libc i przypuszczalnie nie musisz się już tym przejmować.
ˇ ld.so-1.8.x -- biblioteka do łączenia dynamicznego w wersji ELF,
ˇ gcc-2.7.2+ -- kompilator C w wersji ELF,
ˇ jądro 2.0.x -- jądro w wersji ELF,
ˇ binutils 2.7.0.x -- różne narzędzia do binariów potrzebne do
kompilacji.
55.. IInnssttaallaaccjjaa wwsszzyyssttkkiieeggoo..
Oto co zrobiłem, aby wszystko zainstalować. Miałem już system ELF
(kompilator, jądro ...).
1. Najpierw zainstalowałem pakiet binutils:
tar xzf binutils-2.6.0.2.bin.tar.gz -C /
2. Potem zainstalowałem bibliotekę do łączenia:
tar zxf ld.so-1.7.12.tar.gz -C /usr/src
cd /usr/src/ld.so-1.7.12
sh instldso.sh
3. Potem binaria do libc. Przeczytaj odpowiednie pliki dotyczące
instalacji w release.libc-5.4.17.
rm -f /usr/lib/libc.so /usr/lib/libm.so
rm -f /usr/include/iolibio.h /usr/include/iostdio.h
rm -f /usr/include/ld_so_config.h /usr/include/localeinfo.h
rm -rf /usr/include/netinet /usr/include/net /usr/include/pthread
tar -xzf libc-5.4.17.bin.tar.gz -C /
4. Teraz trzeba uruchomić ldconfig, żeby zlokalizować nowe biblioteki
dzielone: ldconfig -v.
5. Jest błąd, który został już poprawiony w libc. Powodował on złe
działanie "make" i innych programów. Oto co zrobiłem, żeby
skompilować i zainstalować "make":
tar zxf make-3.74.tar.gz -C /usr/src
cd /usr/src/make-3.74
patch < ścieżka_do_release.libc-5.4.17
configure --prefix=/usr
sh build.sh
./make install
cd ..
rm -rf make-2.74
6. Teraz można skompilować i zainstalować localedef:
mkdir /usr/src/libc
tar zxf libc-5.4.17.tar.gz -C /usr/src/libc
cd /usr/src/libc
cd include
ln -s /usr/src/linux/include/asm .
ln -s /usr/src/linux/include/linux .
cd ../libc
./configure
make clean ; make depend
cd locale
make programs
mv localedef /usr/local/bin
mv locale /usr/local/bin
7. Umieść zestawy znaków tam, gdzie je znajdzie localedef. Ja użyłem
zestawów znaków i locales z ftp.dkuug.dk (charmaps.tar i
locales.tar). W Polsce dostępne są pod adresem:
ftp.arch.pwr.wroc.pl w katalogu /mirror/linux/nls/locale/dkuug.
Starsze "localedef" (5.2.18) szukało źródeł zestawów znaków w
katalogu /usr/share/nls/charmap, ale teraz "localedef" szuka ich w
katalogu /usr/share/i18n/charmaps oraz źródeł definicji lokalnych w
/usr/share/i18n/locales
mkdir /usr/share/i18n
mkdir /usr/share/i18n/charmaps
mkdir /usr/share/i18n/locales
tar xf charmaps.tar -C /usr/share/i18n/charmaps
tar xf locales.tar -C /usr/share/i18n/locales
Nowsze "localedef" (5.4.17) są sprytniejsze i szukają zbiorów
źródłowych definicji lokalnych podczas obsługi funkcji "copy".
Podczas, gdy starsze "localedef" musiały mieć już utworzone pliki
źródłowe definicji lokalnych, aby obsłużyć funkcję "copy". Poniższa
lista poleceń ma wysortowane zależności i może być użyta, aby
wygenerować wszystkie objekty lokalne w zaleźności od używanej wersji
biblioteki libc, ale powinieneś móc teraz utworzyć tylko te, które
chcesz.
localedef -ci en_DK -f ISO_8859-1:1987 en_DK
localedef -ci sv_SE -f ISO_8859-1:1987 sv_SE
localedef -ci fi_FI -f ISO_8859-1:1987 fi_FI
localedef -ci sv_FI -f ISO_8859-1:1987 sv_FI
localedef -ci ro_RO -f ISO_8859-1:1987 ro_RO
localedef -ci pt_PT -f ISO_8859-1:1987 pt_PT
localedef -ci no_NO -f ISO_8859-1:1987 no_NO
localedef -ci nl_NL -f ISO_8859-1:1987 nl_NL
localedef -ci fr_BE -f ISO_8859-1:1987 fr_BE
localedef -ci nl_BE -f ISO_8859-1:1987 nl_BE
localedef -ci da_DK -f ISO_8859-1:1987 da_DK
localedef -ci kl_GL -f ISO_8859-1:1987 kl_GL
localedef -ci it_IT -f ISO_8859-1:1987 it_IT
localedef -ci is_IS -f ISO_8859-1:1987 is_IS
localedef -ci fr_LU -f ISO_8859-1:1987 fr_LU
localedef -ci fr_FR -f ISO_8859-1:1987 fr_FR
localedef -ci de_DE -f ISO_8859-1:1987 de_DE
localedef -ci de_CH -f ISO_8859-1:1987 de_CH
localedef -ci fr_CH -f ISO_8859-1:1987 fr_CH
localedef -ci en_CA -f ISO_8859-1:1987 en_CA
localedef -ci fr_CA -f ISO_8859-1:1987 fr_CA
localedef -ci fo_FO -f ISO_8859-1:1987 fo_FO
localedef -ci et_EE -f ISO_8859-1:1987 et_EE
localedef -ci es_ES -f ISO_8859-1:1987 es_ES
localedef -ci en_US -f ISO_8859-1:1987 en_US
localedef -ci en_GB -f ISO_8859-1:1987 en_GB
localedef -ci en_IE -f ISO_8859-1:1987 en_IE
localedef -ci de_LU -f ISO_8859-1:1987 de_LU
localedef -ci de_BE -f ISO_8859-1:1987 de_BE
localedef -ci de_AT -f ISO_8859-1:1987 de_AT
localedef -ci sl_SI -f ISO_8859-2:1987 sl_SI
localedef -ci ru_RU -f ISO_8859-5:1988 ru_RU
localedef -ci pl_PL -f ISO_8859-2:1987 pl_PL
localedef -ci lv_LV -f BALTIC lv_LV
localedef -ci lt_LT -f BALTIC lt_LT
localedef -ci iw_IL -f ISO_8859-8:1988 iw_IL
localedef -ci hu_HU -f ISO_8859-2:1987 hu_HU
localedef -ci hr_HR -f ISO_8859-4:1988 hr_HR
localedef -ci gr_GR -f ISO_8859-7:1987 gr_GR
66.. II ccoo tteerraazz??
Po przejściu omówionych powyżej kroków powinieneś móc używać ustawień
lokalnych na swoim komputerze. Oto prosty przykładowy program.
/* test.c : prosty przykładowy program do sprawdzenia czy
ustawienia lokalne działają
*/
#include
#include
#include
main(){
time_t t;
struct tm * _t;
char buf[256];
time(&t);
_t = gmtime(&t);
setlocale(LC_TIME,"");
strftime(buf,256,"%c",_t);
printf("%s\n",buf);
}
Żeby sprawdzić jakie są bieżące ustawienia możesz użyć programu
"locale". Skompiluj powyższy program i uruchom z różnymi
ustawieniami. gcc -s -o Test test.c Zobacz jakie są bieżące
ustawienia: locale
LANG=POSIX
LC_COLLATE="POSIX"
LC_CTYPE="POSIX"
LC_MONETARY="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_MESSAGES="POSIX"
LC_ALL=
Hmmm... ustawienia standardowe C...
No to zmieńmy na inne:
export LC_TIME=en_CA -- kanadyjski angielski
Test
Sat 23 Mar 1996 07:51:49 PM
A teraz francuski kanadyjski:
export LC_TIME=fr_CA
Test
sam 23 mar 1996 19:55:27
77.. NNaapprraawwaa bbłłęędduu ""ccaattooppeenn""..
Instalacja obsługi ustawień lokalnych naprawia automatycznie błąd (a
może zaletę) w poleceniu "catopen" w bibliotece libc. Powiedzmy, że
napiszesz program, który używa komunikatów z katalogu
/home/peeter/catalogs/de_DE.
Teraz - jeśli wykonasz następujące polecenia nie mając zainstalowanych
ustawień lokalnych dla de_DE,
export LC_MESSAGES=de_DE
export NLSPATH=/home/peeter/catalogs/%L/%N.cat:$NLSPATH
katalog z niemieckimi komunikatami nie zostanie otwarty. Funkcja
catgets pobierze komunikaty z katalogu standardowego.
Dzieje się tak ponieważ funkcja "catopen" wywołuje funkcję
"setlocale", żeby pobrać odpowiednie komunikaty, a funkcja "setlocale"
zwróci błąd pomimo tego, że została ustawiona zmienna środowiskowa.
Następnie funkcja "catopen" próbuje załadować komunikaty zastępując
wszystkie "L" literą "C" w zmiennej NLSPATH.
Możesz nadal używać swojego katalogu z komunikatami bez definiowania
ustawień lokalnych, ale musiałbyś bezpośrednio ustawić część "L"
zmiennej NLSPATH:
export NLSPATH=/home/peeter/catalogs/de_DE/%N.cat:$NLSPATH
ale to mija się z celem zastosowania zmiennych ustawień lokalnych.
88.. PPyyttaanniiaa ii ooddppoowwiieeddzzii..
Sekcja ta mogłaby urosnąć i zmienić się w FAQ, ale jest jeszcze za
mała.
88..11.. mmssggccaatt
Używam Linux-a i napisałem taki program:
--------------------------------------------------------------------
#include
#include
#include
#include
main(int argc, char ** argv)
{
nl_catd catd;
setlocale(LC_MESSAGES, "");
catd = catopen("msg", MCLoadBySet);
fprintf(stderr,catgets(catd, 1, 1, "otwarcie komunikatów lokalnych nie powiodło się\n"));
catclose(catd);
}
--------------------------------------------------------------------
$ msg.m
$set 1
1 locale message pass\n
--------------------------------------------------------------------
Jeśli użyję bezwzględnej ścieżki dostępu w "catopen", np.:
catopen("/etc/locale/msg.cat", MCLoadBySet);
To jest dobrze. Ale jeśli używam poprzedniego przykładu "catopen"
zwraca mi -1 (czyli, że się nie powiodło)
Częściowa odpowiedź na to pytanie jest w poprzedniej sekcji, ale podam
jeszcze trochę dodatkowych informacji.
Jest wiele "odpowiednich miejsc", gdzie możesz umieścić katalog z
komunikatami. Nawet gdybyś nie ustawił zmiennej środowiskowej NLSPATH,
to jest ona następująco zdefiniowana w libc:
$ strings /lib/libc.so.5.4.17 | grep locale | grep %L
/etc/locale/%L/%N.cat:/usr/lib/locale/%L/%N.cat:/usr
/lib/locale/%N/%L:/usr/share/locale/%L/%N.cat:/usr/
local/share/locale/%L/%N.cat
Więc jeśli zrobiłeś jedno z poniższych:
$ export LC_MESSAGES=en_CA
$ export LC_ALL=en_CA
$ export LANG=en_CA
to funkcja catopen("msg", MCLoadBySet); działałaby, gdyby twój katalog
z komunikatami był jednym z:
/etc/locale/en_CA/
/usr/lib/locale/en_CA/
/usr/lib/locale/msg/
/usr/share/locale/en_CA/
/usr/local/share/locale/en_CA/
Jednak to nie zadziała jeśli nie masz zainstalowanych ustawień
lokalnych dla en_CA, ponieważ funkcja "setlocale" nie powiedzie się i
w wywołaniu funkcji "catopen" w miejsce "L" zostanie podstawiona
litera "C".
99.. ZZaakkoońńcczzeenniiee..
To tyle. Mam nadzieję, że ten "podręcznik" pomógł ci chociaż trochę.
Jest zapewne dużo miejsc, gdzie możesz szukać dodatkowych informacji
na temat pisania programów zgodnych z ustawieniami lokalnymi. Założę
się, że jeśli poszukasz trochę po sieci (WWW), to znajdziesz dużo
informacji. Ulrich Drepper, który zaimplementował większość kodu
umiędzynarodowiającego, ma troche informacji na swojej stronie WWW;
możesz tam zacząć. Jest także trochę informacji na stronach
informacyjnych i w podręczniku systemowym "man" o libc.
99..11.. OOdd ttłłuummaacczzaa..
Jeśli znalazłeś jakieś rażące błędy ortograficzne, gramatyczne,
składniowe, techniczne to pisz do mnie:
B.Maruszewski@jtz.org.pl
Oficjalną stroną tłumaczeń HOWTO jest http://www.jtz.org.pl/
Aktualne wersje przetłumaczonych dokumentów znajdują się na tejże
stronie. Dostępne są także poprzez anonimowe ftp pod adresem
ftp.jtz.org.pl/HOWTO/
Przetłumaczone przeze mnie dokumenty znajdują się także na mojej
stronie WWW. Są tam
też odwołania do Polskiej Strony Tłumaczeniowej.
Kontakt z naszą grupą, grupą tłumaczy możesz uzyskać poprzez listę
dyskusyjną jtz@ippt.gov.pl. Jeśli chcesz sie na nią zapisać, to wyślij
list o treści subscribe jtz Imię Nazwisko na adres
majordomo@ippt.gov.pl
Zmiany wprowadzone przeze mnie do tego dokumentu to polskie odnośniki
do serwerów ftp i WWW.
W wersji v1.31 została poprawiona nazwa pliku testowego z "test" na
"Test", co jak zauważył jeden z czytelników ma podstawowe znaczenie
ponieważ program "test" już istnieje w systemie.