---
title: Kapitel 4. Lokalisierung und Internationalisierung - L10N und I18N
prev: books/developers-handbook/secure
next: books/developers-handbook/policies
showBookMenu: true
weight: 5
params:
  path: "/books/developers-handbook/l10n/"
---

[[l10n]]
= Lokalisierung und Internationalisierung - L10N und I18N
:doctype: book
:toc: macro
:toclevels: 1
:icons: font
:sectnums:
:sectnumlevels: 6
:sectnumoffset: 4
:partnums:
:source-highlighter: rouge
:experimental:
:images-path: books/developers-handbook/

ifdef::env-beastie[]
ifdef::backend-html5[]
:imagesdir: ../../../../images/{images-path}
endif::[]
ifndef::book[]
include::shared/authors.adoc[]
include::shared/mirrors.adoc[]
include::shared/releases.adoc[]
include::shared/attributes/attributes-{{% lang %}}.adoc[]
include::shared/{{% lang %}}/teams.adoc[]
include::shared/{{% lang %}}/mailing-lists.adoc[]
include::shared/{{% lang %}}/urls.adoc[]
toc::[]
endif::[]
ifdef::backend-pdf,backend-epub3[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]
endif::[]

ifndef::env-beastie[]
toc::[]
include::../../../../../shared/asciidoctor.adoc[]
endif::[]

[[l10n-programming]]
== I18N-konforme Anwendungen programmieren

Um Ihre Anwendung verwendbarer für andere Sprachen zu machen, hoffen wir, dass Sie I18N-konform programmieren. Der GNU gcc-Compiler und Bibliotheken für grafische Benutzeroberflächen wie QT und GTK unterstützen I18N durch eine spezielle Verarbeitung von Zeichenketten. Das Erstellen eines I18N-konformen Programms ist sehr einfach und erlaubt anderen Mitwirkenden, Ihre Programme leichter in andere Sprachen zu übersetzen. Lesen Sie die Bibliothek-spezifischen I18N-Dokumentationen für weitere Details.

Im Gegensatz zur allgemeinen Meinung ist I18N-konformer Code einfach zu programmieren. Üblicherweise umfasst dies nur das Einbetten Ihrer Zeichenketten in Bibliothek-spezifische Funktionen. Stellen Sie außerdem bitte sicher, dass Sie Unterstützung für Unicode- und Multibyte-Zeichen vorsehen.

=== Ein Aufruf, die I18N-Bemühungen zu vereinheitlichen

Wir sind darauf aufmerksam geworden, dass die einzelnen I18N-/L10N-Bemühungen für jedes Land wiederholt wurden. Viele von uns haben somit unproduktiverweise das Rad immer wieder neu erfunden. Wir hoffen, dass die verschiedenen großen Gruppen für I18N Ihre Bemühungen in einer Gruppe vereinen können, ähnlich der Zuständigkeit des Core-Teams.

Derzeit hoffen wir, dass wenn Sie I18N-konforme Programme schreiben oder portieren, diese an die betreffenden FreeBSD-Mailinglisten jedes Landes schicken, um sie testen zu lassen. Wir hoffen in Zukunft, Anwendungen zu entwickeln, die in allen Sprachen direkt und ohne unsaubere Änderungen funktionieren.

Die {freebsd-i18n}-Mailingliste ist eingerichtet worden. Wenn Sie I18N-/L10N-Entwickler sind, schicken Sie bitte Ihre Kommentare, Ideen, Fragen und alles, das Sie mit dem Thema in Verbindung bringen, dorthin.

=== Perl und Python

Perl und Python bieten Bibliotheken für I18N und zur Behandlung von Unicode-Zeichen. Bitte nutzen Sie diese für I18N-Konformität.

[[posix-nls]]
== Lokalisierte Nachrichten mit POSIX.1 Native Language Support (NLS)

Ü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.

[[nls-catalogs]]
=== 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 [.filename]#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:

[.programlisting]
....
$set 1
....

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

[.programlisting]
....
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 man: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 man:gencat[1] Tool kompiliert.

[[nls-using]]
=== Nutzung der Katalogdateien im Quellcode

Das Benutzen der Katalogdateien ist einfach. Um die relevante Funktion zu nutzen, muss [.filename]#nl_types.h# in die Quelldatei eingefügt werden. Bevor ein Katalog benutzt werden kann, muss er mit man: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 man:catopen[3] sucht nach dieser Datei in [.filename]#/usr/shared/nls/locale/catname# und in [.filename]#/usr/local/shared/nls/locale/catname#, wobei `locale` die gesetzte Lokale und `catname` der Katalogname ist. Der zweite Parameter ist eine Konstante, die zwei Werte haben kann:

* `NL_CAT_LOCALE`, hat die Bedeutung, dass die benutzte Katalogdatei auf `LC_MESSAGES` basiert.
* `0`, hat die Bedeutung, dass `LANG` benutzt wird, um die Katalogdatei zu öffnen. 

Der man: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 man:catgets[3] benutzt werden, um Mitteilungen zu erhalten. Der erste Parameter ist der Katalogidentifizierer, der von man: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 man:catclose[3], geschlossen werden. Es besitzt ein Argument, die Katalog ID.

[[nls-example]]
=== 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:

[.programlisting]
....
#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:

[.programlisting]
....
#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:

[.programlisting]
....
#ifndef WITHOUT_NLS
 catalog = catopen("myapp", NL_CAT_LOCALE);
#endif

...

printf(getstr(1));

...

#ifndef WITHOUT_NLS
 catclose(catalog);
#endif
....

==== 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:

[.programlisting]
....
#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:

[.programlisting]
....
#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, [.filename]#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:

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

[[nls-mk]]
=== Benutzung von [.filename]#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 [.filename]#bsd.nls.mk# einige Makros zur Verfügung. Es ist nicht notwendig [.filename]#bsd.nls.mk# explizit hinein zu kopieren, es wird automatisch aus den allgemeinen Makefiles wie [.filename]#bsd.prog.mk# oder [.filename]#bsd.lib.mk# gezogen.

Normalerweise reicht es, `NLSNAME` zu definieren, die den Namen des Kataloges als erstes Argument von man: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 man:make[1] muss so definiert werden, dass das Programm ohne NLS-Unterstützung gebaut wird.

[.programlisting]
....
.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 [.filename]#nls#-Unterverzeichnis abgelegt. Dies ist der Standard von [.filename]#bsd.nls.mk#. Es ist möglich, mit der `NLSSRCDIR`-Variablen von man: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 [.filename]#bsd.nls.mk# finden Sie in der Datei selbst. Der Text ist kurz und leicht zu verstehen.
