4.2. Lokalisierte Nachrichten mit POSIX.1 Native Language Support (NLS)

Beigetragen von Gábor Kövesdán.

Über die Basisfunktionen von I18N hinaus, wie das Bereitstellen von verschiedenen Eingabecodierungen oder die diversen nationalen Konventionen, zum Beispiel die verschiedenen Dezimalpunkte, ist es auf einem höheren Level von I18N möglich, die Ausgabe von Programmen zu lokalisieren. Ein Weg dies zu tun besteht in der Nutzung der POSIX.1 NLS-Funktionen von FreeBSD.

4.2.1. Organisation von lokalisierten Mitteilungen in Katalog Dateien

POSIX.1 NLS basiert auf Katalogdateien, welche die lokalisierten Mitteilungen in der entsprechenden Codierung enthalten. Die Mitteilungen sind in Sets organisiert und jede Mitteilung ist durch eine eindeutige Zahl in dem jeweiligen Set identifiziert. Die Katalogdateien werden nach der Lokale, von den jeweiligen lokalisierten Mitteilungen, die sie enthalten, gefolgt von der .msg Endung benannt. Zum Beispiel werden die ungarischen Mitteilungen für das ISO8859-2 Encoding in einer Datei mit dem Dateinamen hu_HU.ISO8859-2 gespeichert.

Diese Katalogdateien sind normale Textdateien, welche die nummerierten Mitteilungen enthalten. Es ist möglich Kommentare in die Dateien zu schreiben, indem Sie ein $-Zeichen an den Anfang der Zeile setzen. Das Setzen von Grenzen wird ebenfalls durch spezielle Kommentare möglich wobei das Schlüsselwort set direkt nach dem $-Zeichen folgen muss. Dem Schlüsselwort set folgt dann die Set-Nummer. Ein Beispiel:

$set 1

Der aktuelle Mitteilungseintrag startet mit der Mitteilungsnummer gefolgt von der lokalisierten Nachricht. Die bekannten Modifikatoren von printf(3) werden akzeptiert:

15 "File not found: %s\n"

Die Katalogdateien müssen in binärer Form vorliegen, bevor sie von einem Programm benutzt werden können. Dies wird mit dem gencat(1) Tool durchgeführt. Das erste Argument ist der Dateiname des kompilierten Katalogs und die weiteren Argumente sind die Eingabekataloge. Die lokalisierten Mitteilungen können auf mehrere Katalogdateien aufgeteilt sein. Danach werden dann alle auf einmal mit dem gencat(1) Tool kompiliert.

4.2.2. Nutzung der Katalogdateien im Quellcode

Das Benutzen der Katalogdateien ist einfach. Um die relevante Funktion zu nutzen, muss nl_types.h in die Quelldatei eingefügt werden. Bevor ein Katalog benutzt werden kann, muss er mit catopen(3) geöffnet werden. Die Funktion hat 2 Argumente. Der erste Parameter ist der Name des installierten und kompilierten Katalogs. Normalerweise wird der Name des Programmes, zum Beispiel grep, genutzt. Dieser Name wird zum Suchen der kompilierten Katalogdatei benutzt. Der Aufruf von catopen(3) sucht nach dieser Datei in /usr/share/nls/locale/catname und in /usr/local/share/nls/locale/catname, wobei locale die gesetzte Lokale und catname der Katalogname ist. Der zweite Parameter ist eine Konstante, die zwei Werte haben kann:

Der catopen(3) Aufruf gibt einen Katalogidentifizierer vom Type nl_catd zurück. Sehen Sie in der Manualpage nach, um eine Liste mit möglichen Fehlercodes zu erhalten.

Nach dem Öffnen eines Katalogs, kann catgets(3) benutzt werden, um Mitteilungen zu erhalten. Der erste Parameter ist der Katalogidentifizierer, der von catopen(3) zurück gegeben wurde, das zweite ist die Nummer des Sets, das dritte die Nummer der Mitteilung und das vierte ist eine Fallbackmitteilung, die angezeigt wird, falls die gewünschte Mitteilung in der Katalogdatei nicht verfügbar ist.

Nach der Nutzung der Katalogdatei, muss sie mit dem Kommando catclose(3), geschlossen werden. Es besitzt ein Argument, die Katalog ID.

4.2.3. Ein Beispiel aus der Praxis

Das folgende Beispiel zeigt einen einfachen Weg wie man NLS-Kataloge flexibel nutzen kann.

Die nachfolgenden Zeilen müssen in eine allgemeine Headerdatei, die in allen Quelldateien vorhanden ist, die lokalisierte Mitteilungen benutzen, eingefügt werden:


#ifdef WITHOUT_NLS
#define getstr(n)         nlsstr[n]
#else
#include <nl_types.h>

extern nl_catd            catalog;
#define getstr(n)         catgets(catalog, 1, n, nlsstr[n])
#endif

extern char              *nlsstr[];
       

Als nächstes fügen Sie die folgenden Zeilen in den globalen Deklarationsteil der Hauptquelldatei ein:


#ifndef WITHOUT_NLS
#include <nl_types.h>
nl_catd   catalog;
#endif

/*
* Default messages to use when NLS is disabled or no catalog
* is found.
*/
char    *nlsstr[] = {
        "",
/* 1*/  "some random message",
/* 2*/  "some other message"
};
	

Als nächstes kommt der Code der den Katalog öffnet, liest und schließt:


#ifndef WITHOUT_NLS
 catalog = catopen("myapp", NL_CAT_LOCALE);
#endif

...

printf(getstr(1));

...

#ifndef WITHOUT_NLS
 catclose(catalog);
#endif
	

4.2.3.1. Reduzierung von zu lokalisierenden Zeichenketten

Es gibt einen guten Weg, Zeichenketten die lokaliesert werden müssen, durch den Einsatz von libc-Fehlermeldungen zu reduzieren. Dadurch vermeidet man Duplikate und erstellt gleiche Meldungen für häufige Fehlermeldungen, die bei vielen Programmen auftreten können.

Als erstes ist hier ein Beispiel, dass keine libc-Fehlermeldungen benutzt:


#include <err.h>
...
if (!S_ISDIR(st.st_mode))
 err(1, "argument is not a directory");
	 

Dies kann so abgeändert werden, dass eine Fehlermeldung durch Auslesen der Variabel errno ausgegeben wird. Die Fehlermeldung wird entsprechend dem Beispiel ausgegeben:


#include <err.h>
#include <errno.h>
...
if (!S_ISDIR(st.st_mode)) {
 errno = ENOTDIR;
 err(1, NULL);
}
	 

In diesem Beispiel wurde die benutzerdefinierte Zeichenkette entfernt. Übersetzer haben weniger Arbeit, wenn sie ein Programm lokalisieren und die Benutzer sehen die übliche “"Not a directory"” Fehlermeldung, wenn dieser Fehler auftritt. Diese Meldung wird ihnen wahrscheinlich vertraut erscheinen. Bitte beachten Sie, dass es notwendig ist, errno.h hinzuzufügen um einen direkten Zugriff auf errno zu haben.

Es lohnt sich darauf hinzuweisen, dass es Fälle gibt, in denen errno automatisch aufgerufen wird, so dass es nicht notwendig ist, es explizit zu tun:


#include <err.h>
...
if ((p = malloc(size)) == NULL)
 err(1, NULL);
	 

4.2.4. Benutzung von bsd.nls.mk

Das Benutzen von Katalogdateien setzt einige sich wiederholende Schritte, wie das kompilieren und installieren der Kataloge, voraus. Um diese Schritte zu vereinfachen, stellt bsd.nls.mk einige Makros zur Verfügung. Es ist nicht notwendig bsd.nls.mk explizit hinein zu kopieren, es wird automatisch aus den allgemeinen Makefiles wie bsd.prog.mk oder bsd.lib.mk gezogen.

Normalerweise reicht es, NLSNAME zu definieren, die den Namen des Kataloges als erstes Argument von catopen(3) enthalten sollte und die Katalogdateien in NLS ohne ihre Endung .msg auflistet. Hier ist ein Beispiel, das es ermöglicht, NLS mit dem obigen Code zu deaktivieren. Die WITHOUT_NLS Variable von make(1) muss so definiert werden, dass das Programm ohne NLS-Unterstützung gebaut wird.


.if !defined(WITHOUT_NLS)
NLS=     es_ES.ISO8859-1
NLS+=    hu_HU.ISO8859-2
NLS+=    pt_BR.ISO8859-1
.else
CFLAGS+= -DWITHOUT_NLS
.endif
	

Normalerweise werden die Katalogdateien in dem nls-Unterverzeichnis abgelegt. Dies ist der Standard von bsd.nls.mk. Es ist möglich, mit der NLSSRCDIR-Variablen von make(1) diese zu überschreiben. Der Standardname der vorkompilierten Katalogdateien folgt den Namenskonventionen, wie oben beschrieben. Er kann durch die NLSNAME-Variablen überschrieben werden. Es gibt noch weitere Optionen, um eine Feinabstimmung zur Verarbeitung der Katalogdateien zu erreichen. Da sie nicht notwendig sind, werden sie hier nicht weiter beschrieben. Weitere Informationen über bsd.nls.mk finden Sie in der Datei selbst. Der Text ist kurz und leicht zu verstehen.

Wenn Sie Fragen zu FreeBSD haben, schicken Sie eine E-Mail an <[email protected]>.
Wenn Sie Fragen zu dieser Dokumentation haben, schicken Sie eine E-Mail an <[email protected]>.