Der Übersetzungscomputer Babel Fish ist zwar kein Sprachgenie, hilft aber den Inhalt fremdsprachiger Dateien zu verstehen. Das heute vorgestellte Kommandozeilentool dockt an ihn an.
Wer auf altavista.com auf den Translate-Knopf drückt, erhält das
Web-Formular zu Babel Fish, einem Programm, das ein halbes Dutzend
Sprachen versteht und ganze Sätze übersetzen kann. Nun steckt die
maschinelle Übersetzungskunst seit Jahrzehnten in den Kinderschuhen und
es ist noch kein Durchbruch in Sicht, also ist das Ganze nicht ganz
ernstzunehmen. Dennoch: In Sprachen, in denen man nur ``Guten Tag'' und
``Ein Bier bitte'' sagen kann, kann der Babel Fish helfen.
Das Webformular auf babel.altavista.com versteht in eine Eingabebox
getippten Text sowie Links auf zu übersetzende Webdokumente. Statt jedes
Mal den Browser hochzufahren und den zu übersetzenden Text als URL oder
mittels Cut-and-Paste in das Eingabefeld zu transferieren geht es heute
darum, mittels eines Perl Skripts über das Internet bei Babel Fish
anzudocken, den Inhalt lokaler Dateien zu übersetzen und anschließend
auszugeben.
Das vorgestellte Perlskript trans tut genau dies. Wie fast immer
stellt sich nach kurzem Nachforschen auf dem CPAN heraus, dass
es dort schon ein passendes Perl-Modul gibt, in diesem Fall ist es
WWW::Babelfish von Dan Urist, das die Arbeit an trans
auf ein Minimum reduziert.
Das Modul WWW::Babelfish arbeitet mit einem Babelfish-Objekt, dessen
translate()-Methode neben einigen Übersetzungsparametern auch
den zu übersetzenden Text als String entgegennimmt.
Der faule Babel Fish auf dem Web
schneidet Texte rigoros nach 1000 Zeichen ab,
WWW::Babelfish umgeht dies aber geschickt, indem es Texte
in Teile mit weniger als 1000 Buchstaben zerlegt und sie
einzeln an Babel Fish schickt.
Babelfish unterstützt derzeit beidseitige Konvertierungen zwischen den Sprachen Deutsch-Englisch und Deutsch-Französisch. Im Zusammenhang mit Englisch arbeitet er außerdem mit Italienisch, Portugiesisch, Spanisch und Russisch.
Ein Aufruf von trans ganz ohne Parameter zeigt an, welche
Parameter es normalerweise erwartet:
usage: trans \
[efgpirs]2[efgpirs] file ...
e: English
f: French
g: German
i: Italian
p: Portuguese
r: Russian
s: Spanish
Damit das vorgestellte Skript trans auch weiss, aus welcher und in
welche Sprache es übersetzen soll, gibt der erste Kommandozeilenparameter die
Richtung an: g2e (German-English) ist Deutsch-Englisch,
f2g (French-German) ist Französisch-Deutsch.
Der zu übersetzende Text steht in einer oder mehreren Dateien, deren
Namen als Parameter nachfolgen. Der folgende Aufruf übersetzt
zum Beispiel den französischen
Inhalt der Datei /tmp/french.txt ins Deutsche und
gibt das Ergebnis auf der Standardausgabe aus:
$ trans f2d /tmp/french.txt
In alter Unix-Tradition geht es auch,
den Dateinamen wegzulassen, dann nimmt trans die Daten aus
der Standardeingabe entgegen:
$ echo "Der Ball ist rund" | \
trans g2e
The ball is round
Das Skript in Listing trans zieht in Zeile 3 das Modul
WWW::Babelfish herein, das vorher entsprechend den Anweisungen
im Abschnitt Installation vom CPAN geholt und installiert werden
muss.
01 #!/usr/bin/perl
02
03 use WWW::Babelfish;
04
05 # Vorgegaukelter User-Agent
06 use constant AGENT =>
07 'Mozilla/4.73 [en] (X11; U; Linux)';
08
09 # Unterstützte Sprachen
10 my @languages = qw(English French German Italian
11 Portuguese Russian Spanish);
12
13 # Hash aufbauen, der Sprachkürzel der
14 # Sprache zuordnet (g=>German, e=>English, ..)
15 foreach my $language (@languages) {
16 my $initial = substr($language, 0, 1);
17 $i2full{lc($initial)} = $language;
18 }
19
20 # Alle Kürzel in einem String (efgpirs)
21 my $chars = join '', keys %i2full;
22
23 # Umwandlungsrichtung von der
24 # Kommandozeile (g2e, e2f, ...)
25 my $way = shift;
26
27 usage() unless defined $way;
28
29 usage("Scheme $way not supported") unless
30 ($from, $to) = $way =~ /^([$chars])2([$chars])$/;
31
32 # Zu übersetzenden Text einlesen
33 my $data = join '', <>;
34
35 # Verbindung zu Babelfish aufnehmen
36 my $babel = WWW::Babelfish->new(agent => AGENT);
37 usage("Cannot connect to Babelfish") unless
38 defined $babel;
39
40 # Übersetzen lassen
41 my $transtext = $babel->translate(
42 source => $i2full{$from},
43 destination => $i2full{$to},
44 text => $data
45 );
46
47 die("Error: " . $babel->error) unless
48 defined($transtext);
49
50 print $transtext, "\n";
51
52 ##################################################
53 sub usage {
54 ##################################################
55 my $msg = shift;
56 my $prog = $0;
57
58 print "usage: $prog ",
59 "[${chars}]2[${chars}] file ...\n";
60 foreach $c (sort split //, $chars) {
61 print " $c: $i2full{$c}\n";
62 }
63 exit(1);
64 }
Die unterstützten Sprachen stehen in den Zeilen 10 und 11 im
Array @languages. Der praktische Operator qw zur Listendefinition
trennt den eingschlossenen String an den Wortgrenzen
(Leerzeichen und Umbrüche) und liefert eine Liste zurück, die jedes
Wort als Element enthält.
Um später elegant über die Kürzel (z.B. g) auf die vollständigen
Sprachnamen (z.B. German) zugreifen zu können, bauen die Zeilen
15 bis 18 einen Hash %i2full auf, der die Kürzel als Schlüssel
und die Sprachnamen als Werte enthält. Hierzu greift sich die
substr-Funktion jeweils das erste Zeichen des Sprachnamens und die
lc-Funktion konvertiert es in einen Kleinbuchstaben.
Zeile 21 baut für später alle verfügbaren Kürzel zu einem String
$chars zusammen, der mit my auf das gegenwärtige Package beschränkt
wird, aber auch in der Unterfunktion usage zur Verfügung steht.
$way holt sich in Zeile 25 mit shift den ersten
Kommandozeilenparameter, der
die Richtung der Übersetzung angibt. Falls keiner vorliegt, hat der
Benutzer offensichtlich die Syntax von trans nicht begriffen und
die usage-Funktion gibt eine Bedienungsanleitung aus und bricht das
Programm ab.
Der reguläre Ausdruck in Zeile 30 /^([$chars])2([$chars])$/;
interpoliert zu /^([efgpirs])2([efgpirs])$/; und
prüft, ob der Richtungsanzeiger dem Format x2y entspricht, wobei
x und y einen der Werte
e,
f,
g,
p,
i,
r oder
s annehmen. Da der Ausdruck im Listen-Kontext steht und auf
der linken Seite eine Liste mit den Elementen $from und $to
steht, liegen dort bei einem erfolgreichen Match anschließend die
in den Klammern des regulären Ausdrucks eingefangenen Werte. Bei
g2e wäre dies g in $from und e in $to.
Schlägt der Match hingegen fehl, ist das Resultat eine leere Liste, die
im boolschen Kontext von unless als falsch interpretiert wird.
Zeile 33 liest den zu übersetzenden Text ein -- entweder von Dateien,
deren Namen auf der Kommandozeile stehen oder von der Standardeingabe,
falls keine Dateinamen vorliegen. Die join-Funktion verbindet die
Zeilen zu einem langen String, unter Beibehaltung der Zeilenumbrüche,
versteht sich.
Zeile 36 erzeugt ein neues WWW:Babelfish-Objekt und weist es mit
dem agent-Parameterpaar an, sich als Netscape-Browser auszugeben. Hierzu
dient die in Zeile 6 mit Perls use constant-Pragma angegebene Konstante.
So definiert man Funktionen, die Ausssehen wie Makros und von Perl so
optimiert werden, dass sie konstanten Skalaren in nichts nachstehen.
Laut Dokumentation liefert der WWW:Babelfish-Konstruktor den
Wert undef zurück, falls etwas schief ging, was Zeile 37 zum
Abbruch nutzen würde.
Zeile 41 schließlich sendet alle Daten an den Babel Fish auf dem
Web. Die translate-Methode nimmt die vollen
(englischen)
Namen für Ausgangs- und Zielsprache (Parameternamen
source und destination)
entgegen, sowie den zu übersetzenden Text als Stringwert für den Parameter
text.
Das Objekt
schickt die Daten an das Formular,
interpretiert das zurückkommende HTML und extrahiert daraus wieder
das Ergebnis -- alles ohne unser Zutun. In $transtext liegt anschließend
das Ergebnis. Ein Wert von undef deutet einen Fehler an, den Zeile
47 abfängt und mittels der error-Methode des WWW::Babelfish-Objekts
als Meldung anzeigt.
Zeile 50 gibt das Ergebnis schließlich auf der Standardausgabe
aus.
Damit neue Benutzer die Bedienung von trans leicht erlernen, gibt
die ab Zeile 53 definierte usage-Funktion eine ihr übergebene
Nachricht und anschließend eine kurze Bedienungsanleitung aus.
Anschließend bricht sie mit exit(1) das Programm ab.
Das oben schon einmal abgedruckte Kurz-Manual generiert usage
dynamisch aus dem Inhalt der Variablen $chars und %short,
die erlaubte Kürzel und eine Kürzel-zu-Sprachname-Tabelle enthalten.
Die Perlfunktion split in Zeile 60
spaltet mit // als Pattern einen String
in seine Einzelzeichen auf und liefert einen Array zurück, der jedes
Zeichen als Element enthält. Die sort-Funktion bringt den
Array mit Kleinbuchstaben in alphabetische Reihenfolge und
der Hash %short liefert die dazugehörigen Sprachnamen.
Die Reihe der unterstützten Sprachen könnte man übrigens auch
mit der Methode languages() des WWW::Babelfish-Objektes
abfragen, die einen Array mit allen aktuellen Sprachen zurückliefert.
trans tut dies nicht, da die Auswahl relativ statisch ist.
WWW::Babelfish gibt's auf dem CPAN unter
WWW-Babelfish-0.09.tar.gz
und setzt das libwww-Bundle sowie das Modul IO::String voraus.
Installiert wird, wie immer mit der CPAN-Shell und
perl -MCPAN -eshell
cpan> install libwww
cpan> install IO::String
cpan> install WWW::Babelfish
Ein paar Beispiele, um die Funktion von Babelfish zu testen: Hierzu
rufen wir trans nur mit dem Sprachrichtungsparameter auf,
geben den zu übersetzenden Text anschließend über die Standardeingabe
ein und schließen mit ^D (Control+D) ab:
$ trans g2e
Einen Radi und eine Mass
Bier, aber schnell!
^D
A Radi and measure beer, but fast!
Na ja, nicht schlecht, aber halt nicht perfekt. Auch von Englisch nach Französisch gibt's eine Schnittstelle:
$ trans e2f
waiter, where the hell
are my frog legs?
^D
le serveur, oł l'enfer sont
mes cuisses de grenouille?
Oder von Englisch nach Deutsch:
$ trans e2g
waiter, this american beer
tastes terrible!
^D
Kellner, dieses Amerikanerbier
schmeckt schrecklich!
Na bitte, sogar Humor hat das Teil. Viel Spaß damit!
![]() |
Michael Schilliarbeitet als Software-Engineer bei Yahoo! in Sunnyvale, Kalifornien. Er hat "Goto Perl 5" (deutsch) und "Perl Power" (englisch) für Addison-Wesley geschrieben und ist unter mschilli@perlmeister.com zu erreichen. Seine Homepage: http://perlmeister.com. |