Lupus: Sprachverwaltungs-System für WebApp

Beitrag lesen

Hallo,

wow, erstmal herzlichen Dank an alle, besonders Dieter. Ich denke, dass ich nun schon ein ziemliches Stück weiter bin. Vielleicht sollte ich noch erwähnen, dass es sich bei meinem WebApp nicht um ein Projekt handelt, dass schlussendlich auch weltweit und in sämtlichen Sprachen verfügbar sein wird; sondern ich bin ein Schüler, der an diesem Projekt üben und neue Techniken kennen lernen möchte - unter anderem eben auch das einbinden von mehreren Sprachen in ein WebApp. Da möchte ich mir natürlich keine falschen, schlechte oder halbpatzige Techniken aneignen.

Die Methode von Dieter gefällt mir eigentlich sehr gut; sie ist ja auch recht nahe an meinem ursprünglichen Gedanken. Die Methode mit gettext(), ist mir doch etwas zu mirakulös. Da mag ich die andere Methode mit den Vokabular-Files doch schon viel leiber, weil ich so eher den Eindruck habe den Überblick über meinen Code zu behalten. Ich verstehe aber nicht ganz, was der Vorteil ist, wenn ich das Vokabular in in einer INI-Datei festlege, anstatt es in einer herkömmlichen PHP-Datei mit einem Array festzulegen. Ich könnte mir vorstellen, dass das einlesen der INI-Datei in PHP mittels parse_ini_file() deutlich länger dauert, wie wenn das Vokabular-Array direkt in der PHP-Datei steht.
Auch vertehe ich noch nicht ganz, weshalb man, wenn das ganze Vokabular in einer Datenbank erfasst wird, den Umweg machen muss, das ganze Vokabular erst in einer INI-Datei abzulegen, wenn man es doch auch direkt mit einer SQL-Abfrage an PHP übergeben könnte, bzw. es so direkt in ein Array speichern könnte. Mir ist schon klar, dass die Datei nich bei jedem Aufruf der Application neu erstellt wird. Dauert ein eine Datenbank-Abfrage tatsächlich länger als parse_ini_file()?! Das ganze Vokabular in einer Datenbank abzulegen erscheint mir hingegen wieder als sehr sinnvoll, weil so eben fehlende Keys vermieden werden können.

[...] Du wirst Uebersetzungen in der Art 'Found 35 results' vs. '35 Ergebnisse gefunden' haben [...]

Danke für den Hinweis; das wollte ich eigentlich noch fragen. Aber auch dieser Fall ist mit der kleinen Funktion die Dieter mir vorgeschlagen hat recht einfch zu lösen. Hier nochmals die einwenig von mir angepasste Funktion.

<?php  
function __($key) {  
    global $locale;  
    if(!isset($locale[$key])) {  
        return $key;  
    } else {  
        $args = func_get_args();  
        $args[0] = $locale[$key];  
        return call_user_func_array('sprintf', $args);  
    }  
}  
?>

Mich würde aber interessieren, wie ich diese Funktion anpassen muss, dass damit auch etwas kompliziertere Fäll übersetzt werden können.

Auch schön sind Texte, in denen mehr als eine Variable vorkommt, die je nach Sprache in
verschiedenen Reihenfolgen vorliegen, gerne auch kombiniert mit den verschiedenen
Numerus-Varianten: "Der Begriff %s wurde %d mal in %s gefunden." vs. "In %s, %s was
found %d times." Da ist ein normales (s)printf überfordert, weil die Platzhalter nicht
unterschieden werden können. Abhilfe schaffen da nur numerierte oder benannte Platzhalter.

In diesem Beispiel könnte ich mir ja noch vorstellen, wie man so etwas lösen könnte. In der Datei mit dem Vokabular für eine Sprache (es spielt hier ja keine Rolle, ob es nun, eine INI- oder eine PHP-Datei ist), die zu ersetzenden Sätze mit Nummerierten "Pseudo-Variablen" definieren und diese dann mit einem Regex (vielleicht reicht ja sogar str_replace) in der richtigen Reihenfolge ersetzten. Beispiel:

de.php: found_a_in_b_x_times = 'Der Begriff $arg1 wurde $arg2 mal in $arg3 gefunden.'
en.php: found_a_in_b_x_times = 'In $arg3, $arg1 was found $arg2 times.'

In der __()-Funktion müsste man dann eben mit einem Regex oder str_replace die durchnummerierten $arg[1-9]'s mit den dazugehörigen Argumenten ersetzen. Ich weiss jetzt zwar nicht, ob das besonders elegant ist aber funktionieren müsste es eigentlich.

Richtig garstig wird das, wenn Dinge wie Singular, Dual, Paukal und Plural ins Spiel
kommen, z.B. bei "keine Eier gefunden" / "ein Ei gefunden", "zwei Eier gefunden" / "%d
Eier gefunden". (Dual-Beispiele bitte aus der Wikipedia fischen!) gettext kümmert sich
darum, genauer die ngettext-Funktion.

Zum Glück muss ich nicht auf Dinge wie Dual oder Paukal achten, weil ich bei meinem kleinen Test-Projekt nur mit Deutsch, Französisch und Englisch rumspielen werde. Aber mit dem Singular und Plural ist es ja im Prinzip ähnlich. Ich habe leider keine Ahnung, wie ich das Eier-Beispiel lösen würde. Vielleicht etwas in der Art...(?):

de.php: x_eggs_found = 'Es [wurde|wurden] $arg1 [Ei|Eier] gefunden.'

Und im Regex dann den entsprechend so filtern, dass entweder wurde, order wurden - bzw. Ei, oder Eier - verwendet wird, jenachdem, was $arg1 ist. In diesem Falls müsste dann wahrscheinlich noch eine extra abfrage gemacht werden, ob $arg1 überhaupt eine Zahl ist, bzw. dass es kein String ist.
Hat jemand bessere Ideen, wie man so etwas elegant lösen würde? Oder ist es hierfür dann wirklich notendig, gettext() zu verwenden, weil es sonst extrem kompliziet werden würde?!

Jetzt gibt es noch ein paar Dinge, auf die ich dich aufmerksam machen moechte.Anstatt
von 'lang' solltest du vielleicht lieber von 'locale' sprechen, Wikipedia kann das nett erklaeren.
Wenn du in deiner Uebersetung Apostroph meinst, solltest du auch Apostroph sagen und
nicht '. Das Zeichen kriegst du mit ALT + 0146. Allerdings musst du deine Anwendung
dann ganz in UTF-8 halten, aber das ist sowieso eine gute Idee.

Okay, danke. Das werde ich gerne beherzigen. Ich verwende sowieso UTF-8 als Charset bei all meinen Dateien, den HTML- und PHP-Header. Von dem her ist es kein Problem, richtige Apostrophe zu verwenden anstatt single-quote. Notfalls, was aber bei UTF-8 eh nicht notwendig sein wird, kann ich die sonderzeichen ja noch HTML-encoden. Also zB "&rsquo;" statt "’" verwenden.

Dein Locale-Detector ist an sich gut gedacht, aber was ist mit _GET und _SESSION?

Ich verstehe nicht ganz, wozu ich zusätzlich noch _GET und _SESSION benötige. Ich möchte in mein WebApp ein <select>-Element einbauen, mit dem man die gewünschte Sprache auswählen kann. Die Sprachauswahl wird dann mit method="post" an PHP übergeben und dann in einem Cookie abgelegt. Wozu brauche ich dann noch _GET in meinem Detector, oder sogar "?locale=de" in jeder URL, wenn die Sprache sowieso im Cookie abgelegt ist. Wozu die Sprache zusätzlich in der Session, wenn sie schon im Cookie gespeichert ist? Oder übersehe ich hier etwas?

Und das @ vor _COOKIE ist hoffentlich nur ein Vertipper, ansonsten waere es a.) unnoetig und b.) schlechter Stil.

Naja, eigentlich nicht. Ich will mit dem "@" bloss die Fehlermeldung vermeiden, wenn man die Seite zum ersten Mal aufruft und das Cookie noch nicht gesetzt ist. Dass dies ein schlechter Stil ist und auch recht langsam sein sollte, habe ich auch schon gehört, aber mit was könnte man das "@" ersetzten? Klar, mit einer verschachtelten If-Else-Abfrage würde es funktionieren, aber wenn man _POST, _GET, _SESSION und _COOKIE einbaut wird diese Abfrage dann doch recht tief.

Herzlichen Dank,
Lupus