Zur Navigation

Script lokalisieren

1 Ranma (Gast)

Nun zum nächsten Trick mit PHP. Ich will mein Skript lokalisieren, also die Beschriftung in unterschiedlichen Sprachen anzeigen. So weit mir bekannt ist, würde man da normalerweise eine Art Template bauen, indem man alle Beschriftungen durch Variablen ersetzt, die mit den entsprechenden Wörtern in unterschiedlichen Sprachen befüllt werden. Dazu müßte ich zunächst mal sämtliche Beschriftungen in meinem Skript aufspüren und durch Variablen ersetzen. So etwas ist, meiner Auffassung nach, eher Arbeit für einen Computer.

Darum soll mein Skript das gleich selbst übernehmen. Zunächst müssen unter allen Zeichenketten in dem Skript diejenigen aufgespürt werden, die als Beschriftungen vorgesehen sind. Das versuche ich mit einem Regulärem Ausdruck. Außerdem muß ich ausprobieren, ob das Skript auf sich selbst zugreifen kann, ohne dadurch eine Dauerschleife zu produzieren. Darum habe ich folgenden Code einfach an irgendein Skript (ansonsten komplett auskommentiert, das sollte den Regulären Ausdruck nicht stören) angehängt und das Ganze Ausgabetest.php genannt:

$trick1=array(); $trick2=array();
$trick1=file($_SERVER['PHP_SELF']);
// ich mag file(); ohne umständliches öffnen und schließen macht es
// einen Array aus einer Datei; theoretisch zumindest.
$trick3=implode('',$trick1);
// die Datei lieber als String? Auch kein Problem.
$trick4=preg_match_all('§(\'((?<=\<.*value\=\")(?=\"\>)).+\')|(\'?((?<!\<)(?!\>)).+\')§ismU',$trick3,$trick2);
print_r($trick2);

Den Regulären Ausdruck kann man sicherlich noch optimieren. Außerdem sieht man dem vermutlich an, daß ich mir nicht sicher bin, wie lookahead und lookbehind kombiniert werden. Dringender ist aber das Problem, das dieser Code nicht wie erwartet einige Strings präsentiert, sondern folgende Fehlermeldungen:


Warning: file(/Ausgabetest.php): failed to open stream: Datei oder Verzeichnis nicht gefunden in /opt/lampp/htdocs/Ausgabetest.php on line 51
Warning: implode(): Invalid arguments passed in /opt/lampp/htdocs/Ausgabetest.php on line 52
Warning: preg_match_all(): in /opt/lampp/htdocs/Ausgabetest.php on line 53
Array ( )

Eine ab dem dritten Warning:... gleiche Fehlermeldung erhalte ich, wenn ich $_SERVER['PHP_SELF'] gleich als Argument in preg_match_all() einfüge. $trick4= wegzulassen macht keinen Unterschied.

Anscheinend kann das Skript nicht auf sich selbst zugreifen? $_SERVER['PHP_SELF'] dient aber doch genau dazu? Das ist eigentlich auch nichts anderes als wenn mehrere Clients auf den selben Server zugreifen oder wenn sich ein Skript zur Verarbeitung von Formulardaten selbst aufruft. Liege ich damit völlig falsch oder liegen nur handwerkliche Fehler vor?
Ranma

05.10.2015 05:24

2 Jörg Kruse

PHP_SELF ist eine relative Pfadangabe zum Document Root. file() benötigt aber eine Pfadangabe relativ zum System-Root. Die Fehlermeldung weist auch darauf hin: file() sucht die Datei in /Ausgabetest.php statt in /opt/lampp/htdocs/Ausgabetest.php

Probier's mal mit SCRIPT_FILENAME oder SCRIPT_NAME

05.10.2015 09:36

3 Ranma (Gast)

SCRIPT_FILENAME enthält die gleiche Pfadangabe wie die Warnungen, deswegen versuchte ich nun SCRIPT_FILENAME. Damit wird die Ausgabe um zwei Zeilen auf zwei Zeilen reduziert:


Warning: preg_match_all(): in /opt/lampp/htdocs/Ausgabetest.php on line 53
Array ( )

Also die gleiche Ausgabe wie wenn ich $_SERVER['PHP_SELF'] direkt in preg_match_all() einbaue. Ich habe auch schon überprüft, daß $trick1 und $trick3 das Skript nun tatsächlich enthalten. Also sollte mit den Variablen normal weitergearbeitet werden können. Irgendetwas muß also mit dem preg_match_all() sein. Aber für mich sieht es aus wie immer. Sollte der Reguläre Ausdruck nicht funktionieren, dann dürfte schlimmstenfalls ein leeres Array ausgegeben werden, aber nicht die Zeile vorher.
Ranma

07.10.2015 02:54

4 Jörg Kruse

Der Fehler tritt ja schon bei einem gewöhnlichen String auf:

<?php

$trick2 = array();
preg_match_all(
    '§(\'((?<=\<.*value\=\")(?=\"\>)).+\')|(\'?((?<!\<)(?!\>)).+\')§ismU',
    'BLA',
    $trick2
);
print_r($trick2);

Ich frage mich, ob Nicht-Ascii-Zeichen wie das § als Delimiter überhaupt zulässig sind?

Wenn man stattdessen ~ oder # als Delimiter verwendet, wird eine "gesprächigere" Fehlermeldung ausgegeben:

Compilation failed: lookbehind assertion is not fixed length at offset 20

Vielleicht kommst du damit weiter?

07.10.2015 14:21

5 Ranma (Gast)

Das Tutorial von developers-guide.net verwendet ° als Delimiter, also sollten Nicht-ASCII-Zeichen zulässig sein. Übrigens war mir garnicht bewußt, daß § kein ASCII-Zeichen ist, weil ich die bisher immer mit den Zeichen auf der Tastatur gleichsetzte. Jedenfalls bis auf ß ä ü ö und °.

Aber die neue Fehlermeldung sagt immerhin, daß es am lookbehind liegen soll. Also muß ich tatsächlich nur am RegEx arbeiten. Das dürfte weiterhelfen.
Ranma

08.10.2015 06:16

6 Jörg Kruse

Das § bringt preg_match_all() als Delimiter zumindest soweit aus dem Tritt, dass es die eigentliche Fehlermeldung nicht mehr bringt.

Nicht-ASCII-Zeichen können je nach Codierung unterschiedlich interpretiert werden, ggf. auch als Multibyte. Deswegen würde ich von der Verwendung als Metazeichen absehen.

Neben ° und § gehören auch noch das Euro-Zeichen sowie der Forward-Tick (´) zu den Nicht-Ascii-Zeichen auf der deutschen Tastatur

08.10.2015 16:09

7 Ranma (Gast)

Den Forward-Tick finde ich jetzt nichtmal auf der Tastatur. Aber ich muß feststellen, daß ASCII-Zeichen als Delimiter tatsächlich viel besser funktionieren. Auch wenn es theoretisch anders ginge, sollte man doch nur ASCII-Zeichen verwenden. Der Lookbehind war eigentlich auch unsinnig. Das ausgegebene Ergebnis hat außerdem noch die unschöne Eigenschaft, daß das darin enthaltene HTML interpretiert wird. Darum der Versuch einer Verbesserung mit neuem RegEx:

$trick1=array(); $trick2=array();
$trick1=file($_SERVER['SCRIPT_FILENAME']);
$trick3=implode('',$trick1);
$trick5='#((\<legend\>)|(\<th\>)|(\<h1\>)|(\<h2\>)|(\<h3\>)|(\<h4\>)|(\<h5\>)|(\<button\>)).+((\</legend\>)|(\</th\>)|(\</h1\>)|(\</h2\>)|(\</h3\>)|(\</h4\>)|(\</h5\>)|(\</button\>))#ismuU';
$trick3=str_replace($trick5,'',$trick3);
$trick4=preg_match_all($trick5,$trick3,$trick2);
print_r($trick2);

Dabei soll $trick3=str_replace($trick5,'',$trick3); dafür sorgen, daß der RegEx sich nicht selbst findet. Das scheint aber nicht viel zu nützen. Die Ausgabe ist nämlich immernoch seltsam. Die Ausgabe von <pre> vor und </pre> nach der letzten Zeile hilft auch nicht weiter. strip_tags($trick2) vor der Ausgabe auch nicht. Abgesehen von der Formatierung finde ich auch noch seltsam, daß ich einen zweidimensionalen Array als Ausgabe erhalte. Der enthält neunzehn Arrays, von denen der erste wiederum drei Elemente enthält, die ich als Ergebnis erwarte. Die übrigen achtzehn Arrays enthalten je drei leere Einträge.

Danach sind noch die HTML-tags INPUT und OPTION zu behandeln. Bei OPTION baue ich Beschriftungen vorzugsweise per FOREACH-Schleife ein. Vielleicht sollte ich dafür einen RegEx direkt nach Arrays suchen lassen, mit denen die Schleifen gefüttert werden könnten. Da muß ich nur aufpassen, ob die auch zu etwas anderem dienen könnten. INPUT ist ziemlich flexibel und blöderweise nicht paarweise. Darum kann es nicht mit in den angegebenen RegEx.

Also falls mein hier angegebener Code auch theoretisch (obwohl ich mir das anders vorgestellt habe) eine so seltsame Ausgabe produzieren soll, dann schnappe ich mir einfach das erste untergeordnete Array und mache damit weiter. Falls die Ausgabe jedoch merkwürdig ist, dann befürchte ich, daß ich darüber nicht einfach hinweggehen kann.
Ranma

09.10.2015 06:33

8 Ranma (Gast)

Wahrscheinlich kann ich schon deshalb nicht über eine seltsame Ausgabe hinweggehen, weil danach noch der Schritt folgen soll, die der Beschriftung dienenden Wörter in dem String, der das Skript enthält, mit fremdsprachigen Wörtern zu ersetzen.

Was ich danach damit mache, habe ich mir noch nicht so genau überlegt. Vielleicht mit eval() ausführen? Würde es nur einmal ausgegeben werden müssen, dann ginge das sicher so. Wo Formulare verarbeitet werden, da bin ich selbst skeptisch.
Ranma

09.10.2015 13:16

9 Jörg Kruse

Dabei soll $trick3=str_replace($trick5,'',$trick3); dafür sorgen, daß der RegEx sich nicht selbst findet.

Wäre vielleicht einfacher, die Ersetzungen aus einer anderen Datei heraus vorzunehmen?

09.10.2015 15:58 | geändert: 09.10.2015 15:59

10 Ranma (Gast)

Nennen wir das mal Plan b. Vorerst würde das nur bedeuten, daß ich eine Zeile Code durch eine andere Zeile Code ersetze. Möglicherweise wolltest du vorschlagen, mittels PHP eine Art Stapelverarbeitung durchzuführen. Dafür habe ich PHP auch schon entdeckt. Auf die Art habe ich als nächstes vor, Wörterlisten aus den Dateien des FreeDict-Projektes in meine Datenbank zu übernehmen. Diese Dateien sind nicht sehr benutzerfreundlich aufgebaut, noch nichtmal einheitlich. Übersetzungen sind nur an Einrückungen zu erkennen. Manchmal stehen zusätzliche Informationen dahinter, unterschiedlich gekennzeichnet. Die eigentliche Lokalisierung verschiebe ich noch bis das geschafft ist. Vielleicht auch ganz an den Schluß, weil die Lokalisierung per Stapelverarbeitung nach jedem Update wiederholt werden müßte. Würde das Skript sich dagegen selbst lokalisieren, dann würde es sich dabei live aktualisieren bei jedem neuen Eintrag in die Datenbank oder Verbesserungen darin. Dann muß ich mir auch noch etwas einfallen lassen wie ich mit nichteindeutigen Einträgen (so etwas wie: table = Tabelle; table = Tisch) umgehe. Eine Sache, die solche Angebote wie Google-translate garnicht erst versuchen. Vielleicht muß ich technische Ausdrücke in eine eigene Datenbanktabelle abtrennen.
Ranma

12.10.2015 05:24