Thread localization - Anfängerfrage (20 answers)
Opened by naspdep at 2012-06-11 10:34

topeg
 2012-06-16 01:06
#159061 #159061
User since
2006-07-10
2611 Artikel
BenutzerIn

user image
Also zu Anfang. Es gibt mehr als eine Implementation von Gettext für Perl. Das wird dir noch häufiger begegnen, dass es mehrere Module gibt die alle ungefähr das selbe machen.

Neben CPAN:Gettext gibt es noch CPAN:Locale::gettext, CPAN:Locale::Messages, CPAN:Locale::Simple und noch einige mehr.

Neben dem eigentlichen Programmieren ist es auch wichtig zu wissen welche Module man am besten nutzt.

Aber zurück zu gettext.

Programme die gettext nutzen greifen auf die Umgebungsvariablen zurück um festzustellen was die Aktuelle Ausgabesprache ist.

So ist in LANGUAGE definiert welche Sprachen generell verstanden werden. LC_MESSAGE definiert ein welcher Sprache Texte ausgeben werden sollen. Daneben gibt es noch LC_CTYPE und LANG. Will man alle diese Werte auf einmal beeinflussen gibt es noch LC_ALL
Anzumerken ist das LC_ALL=C sämtliche Übersetzungen unterdrückt und alle Texte so ausgeben werden wie sie im Code stehen. Das gilt für alle Programme. (zumindest wenn das System POSIX Konform ist) Schreibe LC_ALL=C programm und du bekommst die Ausgaben wie sie die Programmierer verfasst haben.

Will man unter Debian (und auch Ubuntu) die aktiven Sprachen einstellen so kann man als root dpkg-reconfigure locales eingeben und die Sprachen einstellen, die man verwenden möchte. Danach ist ein Neustart angebracht, damit die Einstellungen in allen Ecken des Systems ankommen.

Um zu schauen welche locales zur Verfügung stehen kann man locale -a ausführen damit werden alle verfügbaren gelistet.

Nun ein kleines Script:
test.pl:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/usr/bin/perl
use strict;
use warnings;
# gettext laden.
# Das ist Bei Debian gleich dabei und nutzt die C-Lib gettext
use Locale::gettext;

# POSIX laden um "setlocale" nutzen zu lönnen
use POSIX;

# das Verzeichnis finden in dem das Script liegt
use FindBin '$Bin';

# keine Übersetzung vorläufig
setlocale(LC_MESSAGES,'C') or die( "Can't set LC_MESSAGES" );

# die Domein an ein Verzeichnis
# im Ordner des Scriptes binden
bindtextdomain("my_test","$Bin/translate");
# in diesem Scrit diese Domain verwenden
textdomain("my_test");


print gettext("Yo man")."\n";
for(0..9)
{
  printf gettext('ln: %02u')."\n",$_;
}

Das soll ein kleines Beispiel sein.

Wie zu sehen sollte im Verzeichnis des Scripts ein Ordner "translate" existieren.

Nun generieren wir aus dem Script ein Template für die Übersetzungen:

xgettext ./test.pl -d my_test -p translate Das Erzeugt im Ordner 'translate' eine Datei "my_test.po"
Grob gesagt sucht xgettext nach gettext(...) und nimmt den String daraus um damit das Template zu erzeugen. Darum funktionieren so Konstrukte wie gettext( "WERT=$wert\n" ) nicht und sollten besser so geschrieben werden: sprintf( gettext( "WERT=%s\n" ), $wert )

Die Sollte ungefähr so aussehen:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-15 23:27+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"

#: test.pl:13
msgid "Yo man"
msgstr ""

#: test.pl:16
#, perl-format
msgid "ln: %02u"
msgstr ""

Das ist das Template mit dem die einzelnen Übersetzungen erzeugt werden.
Im Verzeichnis 'translate' führt man aus: msginit -l de -i my_test.po Damit wird eine Datei 'de.po' erzeugt. Darin macht man die Übersetzungen. Ungefähr so:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# German translations for PACKAGE package.
# Copyright (C) 2012 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# ToPeG <topeg@test.local>, 2012.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-06-15 23:27+0200\n"
"PO-Revision-Date: 2012-06-15 23:31+0200\n"
"Last-Translator: ToPeG <topeg@test.local>\n"
"Language-Team: German\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: test.pl:13
msgid "Yo man"
msgstr "Hallo"

#: test.pl:16
#, perl-format
msgid "ln: %02u"
msgstr "Zeile %02u"

Wenn man Umlaute benutzt muss man das charset=ASCII Ändern. Speichert man die Datei Als UTF-8 (was zu empfehlen ist) dann setzt man charset=UTF-8 Speichert man in einer anderen Kodierung muss man das dort vermerken. Macht man da einen Fehler nörgelt gettext herum das bestimmte Zeichen nicht zur Kodierung passen, oder die Ausgabe hat seltsame Zeichen.
Das macht man nun für jede Sprache die man haben will (z.B englisch).

Der nächste Schritt ist es die Dateien zu kompilieren und an die richtige Stelle zu packen. Dazu erzeugt man zu jeder Sprache einen Ordner diesen Namens der einen Ordner 'LC_MESSAGES' enthält. Also für Deutsch: translate/de/LC_MESSAGES/ Nun wird das ganze kompiliert: msgfmt -o de/LC_MESSAGES/my_test.mo ./de.po Nun kann das Script auf die Übersetzung zugreifen. Dieses Prozedere wiederholst du für jede der Übersetzungen.

Mit ./test.pl bekommt man :
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
Yo man
ln: 00
ln: 01
ln: 02
ln: 03
ln: 04
ln: 05
ln: 06
ln: 07
ln: 08
ln: 09

Was zu erwarten ist da eine Übersetzung unterdrückt ist.

Kommentiert man #setlocale(LC_MESSAGES,'C') aus bekommt man die Ausgabe:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
Hallo
Zeile 00
Zeile 01
Zeile 02
Zeile 03
Zeile 04
Zeile 05
Zeile 06
Zeile 07
Zeile 08
Zeile 09


Wenn du Vorher für alle gewünschten Übersetzungen die locales ausgewählt hast, kannst du die Sprache ändern indem du die Zeile setlocale(LC_MESSAGES,'...') änderst.

Die Ordnerstruktur ist bei mir nun:
Code: (dl )
1
2
3
4
5
6
test.pl
translate/my_test.po
translate/de.po
translate/en.po
translate/de/LC_MESSAGES/my_test.mo
translate/en/LC_MESSAGES/my_test.mo


Das "gettext"-Packet bietet noch weitere Programme um z.B Änderungen im Script zu erkennen und in den Übersetzungen zu ergänzen. Das solltest du dir aber selber durch lesen.

Ich hoffe das hilft dir weiter.

View full thread localization - Anfängerfrage