Homepage     Computer-Stoff(Titelseite)

Eine Einführung in die locale

Der date-Befehl gibt die Abkürzungen des Wochentags und des Monats in der Landessprache aus. Irgendwo in einem Linux-System muß stehen, welche Abkürzungen das sind. Irgendwo muß stehen, ob eine 24-Stundenzeit benutzt werden soll, oder ob AM und PM benutzt werden soll. Die Funktionen toupper und tolower müssen irgendwoher wissen, daß beispielsweise "Ä" und "ä" zusammengehören, und wo das "ä" beim alphabetischen Sortieren eingeordnet werden soll.

All diese Sachen stehen in der sog. "locale". Hier gibt es zwar keine erschöpfende Behandlung aller Variablen und Optionen in der locale (die wäre nämlich ziemlich lang), aber einen kurzen Überblick. (Naja, so kurz es eben bei einer so unübersichtlichen Sache geht.)

Meine Erfahrungen habe ich auf einem SuSE-Linux gesammelt. Auf SUNs ist die locale völlig anders strukturiert. Mich würde interessieren, wie sie auf anderen Linux-Distributionen aussieht.


Grundsätzliches

Die Kategorien der locale

Es gibt in der locale sechs Kategorien:

LC_CTYPE
Legt fest, welche chars Buchstaben, Ziffern, Leerzeichen, alphanumerische Zeichen, druckbar usw. sind. Diese Kategorie wird beispielsweise von den C-Funktionen isdigit, isalpha usw. benutzt. Außerdem wird hier festgelegt, welche Klein- und Großbuchstaben zusammengehören.
LC_COLLATE
Legt fest, wie Wörter alphabetisch geordnet werden sollen.
LC_MONETARY
Legt fest, mit welcher Währung wie gearbeitet werden soll.
LC_NUMERIC
Legt beispielsweise fest, ob ein Dezimalpunkt (wie im Englischen) oder ein Komma (wie im Deutschen) verwendet werden soll. Weiterhin ob die Ziffern von großen Zahlen alle drei (oder vier) Ziffern durch ein Komma oder einen Punkt voneinander abgetrennt werden sollen. Diese locale wird z.B. bei einigen Format-Angaben bei der Benutzung von sprintf verwendet.
LC_TIME
Legt fest, in welchem Format Zeit- und Datumsangaben bei diversen Funktionen aus- oder eingegeben werden sollen.
LC_MESSAGES
In diese Kategorie können Programme ihre Ausgaben in verschiedenen Sprachen eintragen. Ein solches Programm läuft dann automatisch in der Sprache, die der Benutzer bei sich eingestellt hat. Dieses feature (NLS= native language support) ist ein Kapitel für sich und wird hier nicht weiter behandelt. In den systemweiten locales stehen meist nur die Buchstaben, die als "Ja"- oder "Nein"-Antwort gelten sollen. Will man die LC_MESSAGES benutzen, so kann man beispielsweise die GNU-gettext-library verwenden.

Weiterhin gibt es noch

LC_ALL
Ist diese Kategorie auf eine bestehende locale gesetzt, so arbeiten alle obigen sechs Kategorien, als seien sie ebenfalls auf diese Kategorie gesetzt.
LANG
Bei vielen Ein- oder Ausgaben wird zunächst nachgeschaut, ob in dieser Umgebungs-Variable eine bestehende locale eingetragen ist, und diese dann verwendet. LANG hat also häufig noch Vorrang vor LC_ALL. Setzt man LANG neu, so werden aber die bestehenden anderen Kategorien nicht neu gesetzt, wie dies bei LC_ALL der Fall ist.

Welche locale aktuell gesetzt ist, kann man sich mit dem Befehl

   locale

anschauen. Will man eine neue locale setzen, so kann man dies beispielsweise mit dem Befehl

   export LC_TIME=en_GB

Aber Achtung: Es gibt einen Unterschied zwischen den Umgebungsvariablen und den eingestellten locales. Ist beispielsweise nach Eingabe obigen Befehls immer noch LC_ALL==german, so hat zwar die Umgebungsvariable LC_TIME den Wert en_GB, die Kategorie LC_TIME der locale ist aber immer noch german.


Die C-locale und die POSIX-locale

Wenn man ein C-Programm startet, übernimmt dieses erst einmal nicht die locale des Benutzers, sondern sie hat eine fest eingebaute, die sog. "C-locale". Will man eine andere locale verwenden, so kann man dies mit Hilfe des Befehles setlocale (definiert in locale.h) tun:

   setlocale (LC_TIME, "de_DE");
   setlocale (LC_ALL, "");

Der erste Befehl setzt die Kategorie LC_TIME der im C-Programm verwendeten locale auf de_DE. Der zweite Befehl setzt alle im Programm verwendeten locales auf die locale des Benutzers, welche durch seine oben erwähnten Umgebungsvariablen gesetzt wurde. (Mit dem Befehl setlocale kann man auch abfragen, welche locale gerade gültig ist. Vergl. im Abschnitt über das das Setzen und Abfragen der locale.)

Ist außerhalb eines C-Programmes keine besondere locale eingestellt oder installiert, so gilt ebenfalls die C-locale, auch wenn sie dann eher als "POSIX"-locale bezeichnet wird.


Wo die locale steckt und wie man sie übersetzt

Wenn man mit der locale arbeitet, hat man vor allem mit zwei Verzeichnissen zu tun:

   /usr/share/locale/
   /usr/share/i18n/

Im ersten dieser beiden stecken die locales, und zwar als Binärdateien. Sie haben meist einen Namen der Form Sprache_Landeskennung, also beispielsweise de_DE, de_AT, en_GB, en_US usw.. Da es sich um Binärdateien handelt, kann man nicht so einfach neue locales anlegen oder bestehende verändern. Hierzu braucht man das zweite Verzeichnis, in dem die sourcen für die locales liegen. (i18n steht übrigens für "internationalization".)

Die sourcen für jede locale bestehen aus drei Dateien, welche in den drei Verzeichnissen

   /usr/share/locale/i18n/charmaps/
   /usr/share/locale/i18n/locales/
   /usr/share/locale/i18n/repertoiremaps/

liegen. Die eigentlichen Informationen für die locales liegen im Unterverzeichnis locales. Die Dateien dort haben (dies ist allerdings kein Zwang) denselben Namen wie die übersetzten locales. Jede locale braucht außer den landesspezifischen Informationen noch einen Zeichensatz, welcher im Unterverzeichnis charmaps/ liegt. Für die locale de_DE ist dies beispielsweise ISO-8859-1. In diesem werden die in den sourcen verwendeten Symbole den einzelnen char-Werten zugeordnet. Außerdem wird in der source für eine locale noch auf eine Datei aus dem Verzeichnis repertoiremaps verwiesen, in dem weitere Symbole in unicode definiert sind (stimmt das?). Zeichensätze und locales kann man verschieden kombinieren.

Hat man eine dieser Dateien verändert oder neu geschrieben, so muß man seine locale neu übersetzen:

   localedef -f ISO-8859-1 -i de_DE.neu de_TEST

übersetzt die Datei de_DE.neu mit dem Zeichensatz ISO-8859-1 und speichert das Ergebnis als locale mit dem Namen de_TEST ab. Die Verzeichnisse, in denen diese Dateien liegen, muß man nicht angeben. (Zumindest meiner Erfahrung nach. Auf anderen Distributionen mag dies anders aussehen.)


Die sourcen der locales

Aufgrund der doch recht unterschiedlichen Natur der Informationen, die in einer locale abgespeichert werden sollen, hat jede Kategorie ihre eigenen Optionen und Variablen. Und zwar nicht zu knapp. Ich kann hier unmöglich einen vollständigen Überblick geben.

Allgemeines

Die nötigen Informationen für eine bestimmte Kategorie, sagen wir LC_TIME, stehen in einem Abschnitt

   LC_TIME

      [...]

   END LC_TIME

Für die anderen Kategorien sieht das entsprechend aus.

Innerhalb eines solchen Abschnitts werden für die betreffende Kategorie Variablen gesetzt. Die allgemeine Form einer Zeile in einem solchen Abschnitt ist

   name    value1;value2;value3;...;valueN

Weiterhin kann man ganz oben in der Datei einen comment_char, mit dem Kommentare eingeleitet werden, und einen escape_char definieren, mit dem man Sonderzeichen maskieren kann, wie man es aus diversen Skript-Sprachen oder aus C-strings kennt. Ein escape-char am Ende einer Zeile bedeutet hier außerdem, daß diese und die nächste Zeile als eine zusammenhängende Zeile gelesen werden sollen.

   comment_char #
   escape_char \

Teilweise können die Definition ganz schon lang werden. Deshalb gibt es eine Möglichkeit, die Definitionen aus anderen locales zu übernehmen. In diesem Fall schreibt man

   LC_TIME
   copy "de_DE"
   END LC_TIME

In diesem Fall werden die LC_TIME-Einstellungen aus der locale de_DE übernommen.


Symbole und Charaktere

In jedem im Verzeichnis charmaps liegenden Zeichensatz sind sog. "Symbole" definiert, Ausdrücke in spitzen Klammern, die angeben, welche Zeichen durch welches char dargestellt werden. Da in den source-Dateien für die locales natürlich keine char-Werte direkt verwendet werden können (diese sind ja zeichensatzabhängig), muß man dort mit diesen Symbolen arbeiten.

In meinem ISO-8859-1-Zeichensatz ist das große "Ä" beispielsweise definiert als

   <A:>                   /xC4   <U00C4> LATIN CAPITAL LETTER A WITH DIAERESIS

In den sourcen für die locales wird also das "Ä" durch <A:> dargestellt. Man kann allerdings chars auch durch sich selber darstellen. In diesem Fall schreibt man sie einfach hin (ohne spitze Klammern). Außerdem als Oktalzahl, Hexadezimalzahl oder Dezimalzahl (\245, \xA5 bzw. \d165). In der Regel sollte man aber Symbole verwenden.


LC_TIME

Dies ist vielleicht die am leichtesten zu verstehende Kategorie der locale. Und auch gleichzeitig diejenige, mit der viele Leute auch am meisten zu tun haben werden. Deshalb werde ich sie hier recht ausführlich besprechen. Für die anderen Kategorien kann ich nur auf eine erschöpfende Dokumentation verweisen (s.u.).

Die in LC_TIME gesetzten Variablen sind die folgenden. Sie werden in bestimmten Fällen von den C-Funktionen strftime(), strptime() und wcsftime() ausgewertet.

abday
Dreibuchstabige Abkürzung der sieben Wochentage (beginnend mit Sonntag) in der Landessprache. Diese werden für den %a-Deskriptor benötigt. Dieser wiederum wird beispielsweise vom date-Befehl verwendet.
day
Der vollständige Name der sieben Wochentage. Für den %A-Deskriptor.
abmon
Dreibuchstabige Abkürzung der 12 Monate (beginnend mit Januar). Für den %b-Deskriptor.
mon
Die vollständigen Monatsnamen. Für den %B-Deskriptor.
d_t_fmt
Diese Variable enthält einen Formatstring für strftime() etc., der verwendet werden soll, wenn der %c-Deskriptor (Ausgabe von Datum und Zeit) angegeben wurde. (Beispielsweise "%a %d %b %Y %T %Z")
d_fmt
Formatstring für den %x-Deskriptor.
t_fmt
Formatstring für den %X-Deskriptor.
am_pm
Zwei strings, welche für "AM" und "PM" ausgegeben werden. Für die Verwendung des %p-Deskriptors.
t_fmt_ampm
Formatstring für die Zeitausgabe mit AM und PM mit dem %r-Deskriptor.

Außerdem gibt es noch einige weitere Variablen, die ich hier nicht mehr aufführe. Die sourcen für die de_DE-locale auf meiner Distribution sehen beispielsweise wie folgt aus:

   LC_TIME
   abday   "<S><o><n>";"<M><o><n>";\
           "<D><i><e>";"<M><i><t>";\
           "<D><o><n>";"<F><r><e>";\
           "<S><a><m>"
   day     "<S><o><n><n><t><a><g>";\
           "<M><o><n><t><a><g>";\
           "<D><i><e><n><s><t><a><g>";\
           "<M><i><t><t><w><o><c><h>";\
           "<D><o><n><n><e><r><s><t><a><g>";\
           "<F><r><e><i><t><a><g>";\
           "<S><a><m><s><t><a><g>"
   abmon   "<J><a><n>";"<F><e><b>";\
           "<M><a:><r>";"<A><p><r>";\
           "<M><a><i>";"<J><u><n>";\
           "<J><u><l>";"<A><u><g>";\
           "<S><e><p>";"<O><k><t>";\
           "<N><o><v>";"<D><e><z>"
   mon     "<J><a><n><u><a><r>";\
           "<F><e><b><r><u><a><r>";\
           "<M><a:><r><z>";\
           "<A><p><r><i><l>";\
           "<M><a><i>";\
           "<J><u><n><i>";\
           "<J><u><l><i>";\
           "<A><u><g><u><s><t>";\
           "<S><e><p><t><e><m><b><e><r>";\
           "<O><k><t><o><b><e><r>";\
           "<N><o><v><e><m><b><e><r>";\
           "<D><e><z><e><m><b><e><r>"
   d_t_fmt "<%><a><SP><%><d><SP><%><b><SP><%><Y><SP><%><T><SP><%><Z>"
   d_fmt   "<%><d><.><%><m><.><%><Y>"
   t_fmt   "<%><T>"
   am_pm   "";""
   t_fmt_ampm ""
   END LC_TIME

Die Datumsausgabe (d_fmt) und die Datums- und Zeitausgabe (d_t_fmt) haben also die Form

   28.06.1969
   Die 8 Aug 2000 21:30:00 CEST

Die leeren strings bei am_pm und t_fmt_ampm bedeuten, daß eine 12-stündige Zeitausgabe von dieser locale nicht unterstützt wird. Das Prozentzeichen, welches hier durch das Symbol <%> dargestellt wird, hat auf anderen Installationen allerdings ein anderes Symbol, z.B. <percent sign>.


LC_CTYPE

Die Syntax in LC_CTYPE ist recht einfach zu verstehen. Es gibt verschiedene "Klassen" von Zeichen, hinter denen je eine durch Semikolon getrennte Liste von Zeichen-Symbolen folgt, die zu dieser Klasse gehören. Beispielsweise ist die Klasse der Kleinbuchstaben in der POSIX-locale definiert durch

   lower    <a>;<b>;<c>;<d>;<e>;<f>;<g>;<h>;<i>;<j>;<k>;<l>;<m>;\
                           <n>;<o>;<p>;<q>;<r>;<s>;<t>;<u>;<v>;<w>;<x>;<y>;<z>

In den diversen europäischen locales gibt es hier natürlich noch massenhaft Vokale mit Akzenten und Punkten drauf, weshalb die Klassen ungefähr die 10fache Größe wie diese hier haben.

Welche Klassen es gibt, entnehme man am besten einer bestehenden locale-sourcen. Die Namen sind eigentlich selbsterklärend. xdigit ist die Klasse aller hexadezimalen Ziffern. Man kann diese Klassen aber nicht vollständig unabhängig voneinander definieren. Einige sind Teilmengen von anderen, andere müssen disjunkt sein. Und es gibt noch mehr Einschränkungen, die ich hier nicht aufzählen kann.

Außerdem gibt es noch zwei Zeilen toupper und tolower. Hinter dem Schlüsselwort folgt eine durch Semikolon getrennte Liste von in Klammern eingefaßten und durch ein Komma getrennten Buchstabenpaaren:

   toupper  (<a>,<A>);(<b>,<B>);(<c>,<C>);...

Natürlich muß in diesem Fall das erste Symbol jedes Paares in der Klasse lower sein, und das zweite in upper.


LC_COLLATE

Der Abschnitt über die Kategorie LC_COLLATE macht meist ca. 95% der Datei aus. Und er ist bei weitem der schwierigste und unübersichtlichste Teil der Datei. Deshalb nur ein ganz grober Überblick.

Die Idee bei der ganzen Sache ist ungefähr folgende: Es gibt sog. "Vergleichs-Elemente" (collating elements), welche miteinander verglichen werden können. Jedes Element kann aus einem, aber auch mehreren Zeichen bestehen. Jedem Element sind ein oder mehrere Gewichte zugeordnet; das primäre Gewicht, das sekundäre, das tertiäre usw.. Sollen nun zwei strings miteinander verglichen werden, so werden sie erst einmal aufgespalten in Vergleichs-Elemente. Diese werden dann der Reihe nach paarweise miteinander verglichen, indem ihre primären Gewichte miteinander verglichen werden. Ergibt der Vergleich keinen Unterschied, so werden die sekundären Gewichte verglichen. Usw..

Die Gewichte selber wiederum sind keine Zahlen, sondern ebenfalls Symbole. Ein Gewicht ist genau dann "größer" als ein anderes Gewicht, falls es in der Liste später vorkommt. Die Liste muß also ungefähr so geordnet sein, wie man die Ordnung auch haben will.

Um dies alles zu bewerkstelligen gibt es außerdem "Vergleichs-Symbole". Dies sind einfach nur Hilfs-Symbole, die man definieren kann, um die richtigen Gewichte zu definieren.

Am besten mal ein kleines Beispiel. Hier ist ein Auszug aus meiner de_DE-locale (allerdings leicht vereinfacht):


   LC_COLLATE

   collating-symbol <CAPITAL>
   collating-symbol <SMALL>

   collating-symbol <NONE>
   collating-symbol <DIAERESIS>


   order_start forward;forward;forward

   <SMALL>
   <CAPITAL>

   <NONE>
   <DIAERESIS>

   <a>     <A>;<NONE>;<SMALL>
   <A>     <A>;<NONE>;<CAPITAL>
   <a:>    <A>;<DIAERESIS>;<SMALL>
   <A:>    <A>;<DIAERESIS>;<CAPITAL>

   <m>     <M>;<NONE>;<SMALL>
   <M>     <M>;<NONE>;<CAPITAL>

   order_end

   END LC_COLLATE

Was passiert hier? Also zunächst einmal werden die vier Vergleichs-Symbole "CAPITAL", "SMALL", "NONE" und "DIAERESIS" definiert. Die Symbole hätte man auch ganz anders nennen können. Immerhin deutet beispielsweise der Name "NONE" an, daß das Symbol bedeutet, daß der Buchstabe keinen Akzent trägt.

Als nächstes kommt, zwischen die Schlüsselwörter "order_start" und "order_end" eingefaßt, die eigentliche Sortiersequenz. Die drei "forward" hinter dem order_start bedeuten, daß die Vergleichselemente je drei Gewichte haben, und daß beim Vergleichen (in allen drei möglichen Runden) zunächst die ersten Vergleichselemente, dann die zweiten usw. miteinander verglichen werden sollen, daß also von vorne an verglichen werden soll.

Weiterhin gibt es in der Liste sechs Vergleichs-Elemente, die miteinander verglichen werden können: "a", "A", "a:", "A:", "m" und "M".

Durch die Angabe der Vergleichs-Symbole in der Liste teilt man der locale mit, wie ihre relativen Gewichte zueinander stehen. Dahinter folgen die Vergleichs-Elemente mit ihren drei Gewichten. In obigen Ausschnitt kommen sechs Gewichte vor, welche wie folgt geordnet sind:

   SMALL < CAPITAL < NONE < DIAERESIS < A < M

Dies ist nämlich genau die Reihenfolge, in der sie in der Liste auftauchen. Nun vergleichen wir mal die Worte "Masten" und "mästen". Im ersten Durchlauf sind die beiden Worte gleich, denn "M" und "m" haben dasselbe primäre Gewicht <M>, und "a" und "ä" haben dasselbe primäre Gewicht <A>. Im zweiten Durchlauf haben "M" und "m" immer noch dasselbe Gewicht <NONE>, aber "a" hat ein kleineres sekundäres Gewicht als "ä". Folglich kommt "Masten" vor "mästen".

Wir halten fest: Vor der Sortier-Liste werden die Vergleichs-Symbole definiert, und diejenigen Vergleichselemente, die nicht bereits im Zeichensatz definierte Symbole sind.

Innerhalb der Sortierliste gibt es zwei verschiedene Arten von Zeilen. Die beiden möglichen Formen sind:

   <collating-symbol>
   <collating-element>   weight-1;weight-2;...weight-n

Die Gewichte wiederum sind ebenfalls Vergleichs-Symbole, Vergleichs-Elemente oder vordefinierte Gewichte. (Diese kommen im obigen Beispiel nicht vor.)


locales und C-Programmierung

Die locale setzen und abfragen

Wie man eine neue locale setzt, die in einem C-Programm gültig sein soll, habe ich bereits im Abschnitt über die C-locale beschrieben, nämlich mit der setlocale()-Funktion. Mit Hilfe dieser Funktion kann man nicht nur locales neu setzen, sondern man kann auch abfragen, welche locale gerade gültig ist. Der Aufruf

   setlocale (LC_TIME,NULL);

liefert einen Zeiger auf einen (statisch allokierten?) string zurück, in dem der Name der locale, die für LC_TIME gültig ist, steht.

Der Name allein sagt einem u.U. nicht viel. Es gibt deshalb Möglichkeiten, detailliertere Informationen abzufragen.

   localeconv();

liefert Informationen über die in LC_NUMERIC und LC_MONETARY gesetzten Variablen zurück. Der Rückgabewert ist ein Zeiger auf eine Struktur struct lconv, deren Definition man auf der manpage locale(7) nachlesen kann.

Der Befehl nl_langinfo(); (definiert in langinfo.h) kann Informationen über Variablen aller Kategorien liefern, und zwar im Format eines strings. Beispielsweise würde, wenn meine obige de_DE-locale in einem C-Programm gültig wäre, der Befehl

   nl_langinfo (D_T_FMT);

einen Zeiger auf einen (statisch allokierten?) string liefern, in welchem

   %a %d %b %Y %T %Z

steht. nl_langinfo nimmt als Argument etwas vom Typ nl_item. Was die möglichen Werte solcher nl_item sind, muß man in langinfo.h nachlesen. Auch eine manpage zu nl_langinfo scheint es auf den meisten Distributionen nicht zu geben. (Es gibt sie aber.)


Funktionen, die die locale benutzen

LC_TIME

Diese Kategorie wird von den Funktionen

strftime() formatierte Ausgabe von Zeiten und Daten
strptime() formatierte Eingabe von Zeiten und Daten
wcsftime()?

benutzt, falls als Format der Aus- bzw. Eingabe bestimmte Deskriptoren verwendet werden. Die locale-abhängigen Deskriptoren kann man ziemlich simpel den manpages dieser Funktionen entnehmen.

LC_CTYPE

Von dieser locale sind alle in ctype.h definierten Funktionen abhängig:

isalnumalphanumerische Zeichen
isalphaBuchstabe
isascii7-bit-ascii-Zeichen. Wirklich locale-abhängig?
isblankLeerzeichen oder tab
iscntrlKontroll-Zeichen
isdigitZiffer
isgraphdruckbar, aber kein Leerzeichen
islowerkleiner Buchstabe
isprintdruckbares Zeichen
ispunctSatzzeichen - alles, was kein Trennzeichen und nicht alphanumerisch ist
isspaceTrennzeichen, wie Leerzeichen, Zeilenumbruch...
isuppergroßer Buchstabe
isxdigithexadezimale Ziffer
toupperUmwandlung in einen Großbuchstaben
tolowerUmwandlung in einen Kleinbuchstaben
<regex.h>Diverse Einstellungen werden beim Gebrauch von regulären Ausdrücken verwendet.

Insbesondere sollte man, wenn man auf die performance eines Programmes achten muß, und keine Sonderzeichen vorkommen, auf die Verwendung von Funktionen wie toupper oder tolower verzichten. Eine selbstgeschriebene Funktion, die -ohne in der locale nachzuschauen- die Buchstaben a,b,c...z nach A,B,C...Z konvertiert, ist wesentlich schneller.

LC_COLLATE

Diese Kategorie beeinflußt das Verhalten der Funktionen

strcoll()strings alphabetisch ordnen, ähnlich wie mit strcmp(). S.u.
strxfrmwandelt einen string in einen zweiten um, so daß ein Vergleich zweier auf diese Art umgewandelter strings mit strcmp dasselbe Ergebnis liefert, wie der Vergleich der ursprünglichen strings mit strcoll.
wcsxfrm?
<regex.h>Diverse Einstellungen werden beim Gebrauch von regulären Ausdrücken verwendet.

Die Funktion strcmp() ordnet zwar auch strings, allerdings nimmt es als Vergleichskriterium einfach die numerische Ordnung der chars und ist deshalb nicht von der locale abhängig. Umlaute und Groß- versus Kleinbuchstaben werden also völlig falsch stehen. Glücklicherweise kommt es meistens nicht darauf an.


Verschiedenes

Default-locale setzen (SuSE und Debian)

Will man für normale Benutzer eine default-locale einstellen, so geschieht dies unter SuSE-Linux in der /etc/rc.config und unter Debian in /etc/environment. Über andere Distributionen bin ich nicht informiert. (Kann mir darüber jemand Infos schicken?)

Bei SuSE werden in der rc.config folgende Variablen gesetzt:

   LANGUAGE
   RC_LANG
   RC_LC_ALL
   RC_LC_MESSAGES
   [...]

Für die Bedeutung von LANGUAGE und RC_LANG s. die Erklärungen in der Datei selber.

Diese Einstellungen gelten für alle Benutzer außer root. root verwendet default-mäßig die POSIX-locale. Will man, daß auch root die locale der normalen Benutzer benutzt muß man die Variable

   ROOT_USES_LANG

Auf "yes" setzen. Hiervon wird aber eher abgeraten, da andere locales außer die POSIX-locale eine zusätzliche Fehlerquelle sind.

In der /etc/environment bei Debian setzt man

   LANG

Diese Einstellung gilt für normale Benutzer wie auch root. Bei neueren Debian-Systemen wird, soweit ich weiß, die /etc/environment von der /etc/profile aufgerufen. Benutzt man also einen graphischen login, so muß man seine locale in der xsession setzen.


Die Fehlermeldung: locale not supported by C library

Wenn ein Programm oder eine library auf eine Datei der augenblicklich gültigen locale zuzugreifen versucht, die nicht existiert, gibt es eine Fehlermeldung der Art

   [library-Name]-warning: locale not supported by C library

In einem solchen Fall sollte man als erstes mal schauen, ob die eingestellte locale überhaupt existiert. Falls nicht, sollte man sie sich besorgen, oder eine andere locale einstellen.

Existiert die eingestellte locale, kann der Fehler immer noch auftreten, beispielsweise wenn man ein Programm startet, welches die GNU-gettext-library verwendet, für das aber eine Übersetzung in die augenblicklich eingestellte Sprache fehlt. Der Befehl

   strace -e trace=open [Programmaufruf]

gibt alle fopen-Befehle, die an das System geschickt werden, und ihr Ergebnis aus. Auf diese Weise kann man erkennen, welche fehlenden Dateien die Fehlermeldungen verursachen. Hat man den Bösewicht identifiziert, kann man schauen, ob man nicht eine locale derselben Sprache hat (in /usr/share/locale oder in /usr/local/share/locale), in welcher die fragliche Datei existiert. Falls ja, kann man sie einfach rüberkopieren. Die geht in der Regel gut, weil Programme häufig nur die Existenz von bestimmten Dateien testen, welche sie nur in eher selten eintretenden Fällen auch benutzen.

Alternativ kann man natürlich einfach eine andere locale einstellen, wenn man das Programm startet. Oder man kann die Warnung ignorieren. Wenn das Programm schon so sauber gemacht ist, daß es die Existenz der locale-Dateien prüft, wird es in diesem Fall vermutlich die POSIX-locale verwenden.


Weitere Informationen

Für die einzelnen C-Funktionen sind die manpages recht brauchbar.

Dagegen enthält die manpage, die das Format der source-Dateien für locales beschreibt, nur einen sehr kleinen Teil derjenigen Informationen, die man braucht, um mit der locale irgendetwas anfangen zu können. Glücklicherweise gibt es die ausführlichen locale-Spezifikationen der UNIX Open Group.


Homepage     Computer-Stoff(Titelseite) by Michael Becker, 8/2000. Letzte Änderung: 8/2004.