mmofacts.com

Gettext und Sprache in Datenbanken

gepostet vor 16 Jahre, 1 Monat von Fobby

Hallo zusammen,

ich habe mich bei den Möglichkeiten der Lokalisierung in PHP umgesehen und bin auf gettext gestoßen. Das gefällt mir soweit auch ganz gut, da es mit diversen po-Editoren leicht zu handhaben ist und auch nativ Plurale unterstützt.

Es gab ja auch schonmal eine Diskussion zu dem Thema (http://www.galaxy-news.de/groups/2_entwickler/forums/1419_internationalisierung.html) aber da wurde ein Problem nicht geklärt, das mir in den Sinn kam:

Ein Teil der Texte steht in der Datenbank. Das lässt sich nicht vermeiden, wenn man eine gewisse Modularität und Erweiterbarkeit per Game-Editor erreichen will ( Neue Monster, Schiffe, Meerschweinchen hinzufügen, Namen ändern, .... ). Das heißt, in der .php sieht das dann so aus: _($row['pigattribute'])

Nun suchen sich die .po-Editoren ja aber die Übersetzungstexte selbst heraus, d.h. sie scannen die Dateistruktur nach _() und gettext() und zeigen mir, was sie gefunden haben. Statt mir aber "groß", "klein", "dick", "dünn" zurückzugeben, bekomme ich in diesem Fall "$row['pigattribute']". Die erste Idee wäre, eine nirgendwo aufgerufene PHP-Datei zu erstellen, in der alle Texte eingetragen werden, die nur in der DB vorkommen. Widerspricht aber dem Grundprinzip, da ich Änderungen in der Datenbank sofort auch in der "Dirty-Help-File" übertragen muss, sonst funktioniert's nicht mehr.

Wie macht ihr das?

gepostet vor 16 Jahre, 1 Monat von buhrmi

Für Datenbank-l18n finde ich Ansatz von doctrine sehr empfehlenswert: http://www.doctrine-project.org/documentation/manual/1_1/da/one-page#behaviors:core-behaviors:i18n

Edit: Generell sollte man meiner Meinung nach die Lokalisierung der beiden Welten (script & Datenbank) gut separieren. Also nicht in einem Script eine Übersetzung eines Wertes für ein Feld in der DB speichern. Außer, die Werte sind Hardcoded oder eine *fixe* Enumeration (klein, groß, dick, etc). In diesem Fall machen wir das (auf der Arbeit) in unserem CMS über einfache Lookup-Arrays die aus diversen lokalisierungsdateien eingelesen werden.

gepostet vor 16 Jahre, 1 Monat von Fobby

Hm, ich find es einfach erstrebenswert, alles an einem Ort zu haben. Denn so wird die Übersetzung ja auf 2 Bereiche aufgeteilt - wozu? Das Themengebiet bleibt dasselbe: Übersetzung. Hmm schade, dachte, da gibt es Defaultlösungen, auf die ich einfach noch nicht gestoßen bin.

Bin für weitere Anregungen dankbar :)

gepostet vor 16 Jahre, 1 Monat von buhrmi

Alles an einem Ort zu haben ist in diesem Fall aber nicht gut. Zwar ist das Themengebiet dasselbe, aber dies ist kein echtes Argument. Es widerspricht dem Kohäsionsprinzip, zumindest bei Datenbankmodellen. Angenommen du hast eine Klasse Schiff, welche dir jede Menge Daten liefert. Unteranderem auch einen Beschreibungstext. Es liegt in der Verantwortung der Klasse, den Text zu liefern. In der gewünschten Sprache. Wenn sie das nicht alleine kann, bedeutet es, dass dieser Text irgendwo außerhalb der Klasse bzw. der Datenbank gespeichert wurde. Und dies bedeutet hohe Kopplung und schwierige Wartbarkeit. Ändert sich der Text, oder wird ein neuer Schiffstyp erstellt, muss an mehreren Stellen gearbeitet werden.

Es gibt afaik keine all-in-one Lösung oder Default-Vorgehensweise. Für statische Sachen eignen sich sprachenspezifische Templates und präprozessor-krams am besten, für kleinere Texte lookup-arrays, und für texte aus Datenbanken eben die Datenbank selber.

gepostet vor 16 Jahre von Fobby

Original von buhrmi

[...] und für texte aus Datenbanken eben die Datenbank selber.

Wie stell ich mir das vor? Hab ich dann in jedem table mit Textinhalt name_de name_en name_fr ... ? Oder dort dann im Stil von LANG_SHIP_RANGER und die Klasse bastelt sich daraus, was sie braucht?

gepostet vor 16 Jahre von exe

Original von buhrmi

Alles an einem Ort zu haben ist in diesem Fall aber nicht gut. Zwar ist das Themengebiet dasselbe, aber dies ist kein echtes Argument. Es widerspricht dem Kohäsionsprinzip, zumindest bei Datenbankmodellen. Angenommen du hast eine Klasse Schiff, welche dir jede Menge Daten liefert. Unteranderem auch einen Beschreibungstext. Es liegt in der Verantwortung der Klasse, den Text zu liefern.

Das halte ich aber für gewagt. "Die Klasse" ist in dem Falle deine Businesslogik und die ist sicher nicht für die Lokalisierung zuständig. Das ist schon eher einer Sache deiner Präsentationsschicht, ergo Templates.

In der gewünschten Sprache. Wenn sie das nicht alleine kann, bedeutet es, dass dieser Text irgendwo außerhalb der Klasse bzw. der Datenbank gespeichert wurde. Und dies bedeutet hohe Kopplung und schwierige Wartbarkeit. Ändert sich der Text, oder wird ein neuer Schiffstyp erstellt, muss an mehreren Stellen gearbeitet werden.

Ich halte es eher für hohe Kopplung die Lokalisierung in der Businesslogik anzusiedeln, da du hier eine Abhängigkeit zwischen Logik und Präsentation schaffst die da nichts zu suchen hat. Hinterlegst du die Lokalisierungsdaten seperat von deiner Logik hast du diese Abhängigkeit entkoppelt bzw. sie gar nicht erst geschaffen. Änderst du einen Text musst du nicht in den Code eingreifen sondern nur deine Sprachdateien (oder -tabellen) anpassen. Wird ein neuer Schiffstyp erstellt musst du im Optimalfall auch nur eine neue Lokalisierung in die betroffene Sprachdatei eintragen.

Original von Fobby

Original von buhrmi

[...] und für texte aus Datenbanken eben die Datenbank selber.

Wie stell ich mir das vor? Hab ich dann in jedem table mit Textinhalt name_de name_en name_fr ... ? Oder dort dann im Stil von LANG_SHIP_RANGER und die Klasse bastelt sich daraus, was sie braucht?

Tabelle "localisation":

Code:

locale char(5) | key varchar | `text` text
------------------------------------------
de_De | hello.world | Hallo Welt
en_US | hello.world | Hello world

 ... wäre z.B. eine einfache Variante.

gepostet vor 16 Jahre von buhrmi

Original von Fobby

Original von buhrmi

[...] und für texte aus Datenbanken eben die Datenbank selber.

Wie stell ich mir das vor? Hab ich dann in jedem table mit Textinhalt name_de name_en name_fr ... ? Oder dort dann im Stil von LANG_SHIP_RANGER und die Klasse bastelt sich daraus, was sie braucht?

Schau dir mal an wie Doctrine das macht (siehe oben). Super elegant. Das von exe gepostete Beispiel ist eine einfache Variante von einfachen lookups, nur in der Datenbank. Da kann man auch gleich bei gettext bleiben.

Original von exe

Ich halte es eher für hohe Kopplung die Lokalisierung in der Businesslogik anzusiedeln, da du hier eine Abhängigkeit zwischen Logik und Präsentation schaffst die da nichts zu suchen hat.

 Sehe ich total anders. Die Klasse die den Beschreibungstext speichert ist mein Informationsexperte. Er hat die Verantwortung mir diese Texte so zu geben, wie ich sie haben will. Siehe auch http://en.wikipedia.org/wiki/GRASP_(Object_Oriented_Design)#Information_Expert . Es ist natürlich nicht gesagt, dass die Patterns nun der heilige Gral sind, doch sie haben sich bestimmt nicht umsonst etabliert. Hmm. Schwierige Sache das.

gepostet vor 16 Jahre von exe

Original von buhrmi

Original von Fobby

Original von buhrmi

[...] und für texte aus Datenbanken eben die Datenbank selber.

Wie stell ich mir das vor? Hab ich dann in jedem table mit Textinhalt name_de name_en name_fr ... ? Oder dort dann im Stil von LANG_SHIP_RANGER und die Klasse bastelt sich daraus, was sie braucht?

Schau dir mal an wie Doctrine das macht (siehe oben). Super elegant. Das von exe gepostete Beispiel ist eine einfache Variante von einfachen lookups, nur in der Datenbank. Da kann man auch gleich bei gettext bleiben.

Original von exe

Ich halte es eher für hohe Kopplung die Lokalisierung in der Businesslogik anzusiedeln, da du hier eine Abhängigkeit zwischen Logik und Präsentation schaffst die da nichts zu suchen hat.

 Sehe ich total anders. Die Klasse die den Beschreibungstext speichert ist mein Informationsexperte. Er hat die Verantwortung mir diese Texte so zu geben, wie ich sie haben will. Siehe auch http://en.wikipedia.org/wiki/GRASP_(Object_Oriented_Design)#Information_Expert . Es ist natürlich nicht gesagt, dass die Patterns nun der heilige Gral sind, doch sie haben sich bestimmt nicht umsonst etabliert. Hmm. Schwierige Sache das.

Das kommt immer ganz drauf an wie man so ein Muster interpretiert. Man könnte sagen: die Schiffsklasse muss wissen welcher Text für das Schiff passend ist. Da wäre dein Informationsexperte deine Schiffsklasse. Man könnte aber auch sagen: Lokalisierung ist keine Aufgabe der Schiffsklasse da Lokalisierung eine Präsentationssache ist. Oder anders gesagt: für die Schiffsklasse ist es vollkommen unerheblich unter welchem Namen in welcher Sprache das Schiff im User Interface angezeigt wird. Daher wird die Aufgabe der Lokalisierung an einen anderen "Informationsexperte" delegiert. Wie z.B. eine Lokalisierungsklasse welche anhand eines Textkürzels und eventuellen Eingabeparametern den passenden Text bestimmt und gemäß der Lokalisierungsregeln (Nummern-, Datumsformate, grammatikalische Regeln [Pluralformen], usw.) formatiert. Ob die Klasse nun die Texte aus einer Datenbank zieht oder einer Datei ist da auch erstmal eher egal ..

Ich würde diese Art von Muster auch nicht zu dogmatisch sehen. Sie sind meistens sowieso nur esoterische Namen für Allerweltsprobleme welche man auch ohne den Namen zu kennen lösen kann.

gepostet vor 16 Jahre von buhrmi

Wenn man unter der Klasse nur einen Key für einen Lookup in einer Übersetzung speichert, dann ist es wirklich egal ob das aus der Datenbank oder woanders her kommt. Aber es ging ja um Texte, die _in_ der Datenbank gespeichert sind.

gepostet vor 16 Jahre von Nuky

Ohne jetzt die ganze Diskussion gelesen zu haben:

Bau dir doch eine zweite Sprachendatei die du auf Knopfdruck von der Datenbank aktualisieren lässt?

gepostet vor 16 Jahre von Fobby

Hilft mir bei dem Ziel, alle Texte an einer Stelle zu haben, auch nicht weiter. Ich denke ich hab mich damit abgefunden, dass es 2 Stellen gibt. Eine Textdatei und ein Lookuptable in der Datenbank, für den ich ein kleines Tool schreibe.

Performant bleibt es am Ende trotzdem - der Table wird einmal ausgelesen und die Übersetzungsdaten im Cache gehalten. Mit der Lösung bin ich zufrieden.

gepostet vor 15 Jahre, 9 Monate von BlackScorp

also ich habe das so geregelt bei mir:

habe eine de.php en.php da drin sind variablen deklariert wie zb

de.php

$header[1] = "Erste überschrift";

en.php

$header[1] = "First Header";

danach kommt eine kleine funktion die alle header defeniert

for($i=0;$i<=count($header);$i++)
{
define(HEADER.$i,$header[$i]);
}

in der datenbank zb bei gebaude sieht das ganze so aus:

ID | Name | Description

1 | Gebaude1| HEADER2

bei der ausgabe hole ich mir die description aus der datenbank (HEADER2) und gebe es einfach in html aus. und je nach dem ob ich de.php oder en.php included habe wird bei mir ein anderer HEADER ausgegeben. und später um weitere sprachen zu adden brauche ich nur de.php zu kopieren und die einträge ersetzen.

Problematisch wirds wenn ich zb 4 sprach datein habe und dann im nachhinein ein weiteres gebaude hinzugefügt habe, muss ich dann in allen sprach-datein es nachtragen und wenn ich news eintrage stehen die in der db in einer sprache dafür muss ich dann alle news in allen sprachen selber übersetzen. aber an diesen problemen arbeite ich gerade

hoffe mein prinzip wurde vestanden;)

MFG

gepostet vor 15 Jahre, 9 Monate von Fobby

Deine Variante funktioniert, ich find es aber viel lesbarer, wenn im Quelltext _("First header") steht statt $header[1] :)

Seit wir auf Symfony umgestiegen sind, ist die Frage nach der Herangehensweise aber eh geklärt. In Templates wird die Funktion __("foo") verwendet, Tabellen mit zu übersetzenden Texten gibt man das Attribut "i18n", den Rest übernimmt Symfony, bzw. in letzterem Fall Doctrine.

Ein paar Codebeispiele gibt es hier: http://www.symfony-project.org/jobeet/1_2/Doctrine/en/19

gepostet vor 15 Jahre, 9 Monate von BlackScorp

na eigentlich steht in der *.tpl datei

{header_main}

und dann habe ich noch eine tpl klasse die dann {header_main} mit HEADERX ersetzt und HEADERX ist ja in en und de.php defeniert

em das besser nachzuvollziehen:

class.tpl.php:

PHP:

class tpl
{
private $data = array();
public function __construct($g_file = null,$g_vars=array(),$g_values=array())
{
$this->data[0] = $g_file;
$this->data[1] = $g_vars;
$this->data[2] = $g_values;
}
public function __toString()
{
$this->data[3] = file_get_contents($this->data[0]);
$this->data[3] = str_replace($this->data[1], $this->data[2], $this->data[3]);
return $this->data[3];
}
}

 de.php

PHP:

$header[0] = "Das ist die Überschrift";
$header[1] = "Und hier steht ganz viel Text";
for($i=0;$i<=count($header);$i++)
{
define(HEADER.$i,$header[$i]);
}

index.php

PHP:

if(isset($_GET["lang"]) && file_exists('lang/'.$_GET["lang"].'.php'))
include 'lang/'.$_GET["lang"].'.php';
else
include 'lang/de.php';
$form = new tpl('layout/form.tpl',array('{header}','{content}'),array(HEADER0,HEADER1));
echo $form;

 form.tpl

HTML:


{header}
{content}

 MFG

gepostet vor 15 Jahre, 9 Monate von Fobby

Ja schon, trotzdem hast du auch im Template irgendwelche symbolischen Konstanten. Mit gettext und ähnlichen Verfahren hast du stattdessen den tatsächlichen Text im Template stehen. So, wie er dann auch letztendlich ausgegeben wird - und das erhöht die Lesbarkeit schon enorm :)

Außerdem scheint mir deine Variante recht aufwändig (und damit fehleranfällig) zu sein. Alles, was ich tun muss, ist im Template wie mehrfach erwähnt _("Übersetz mich!") zu schreiben, das war's. Alle zu übersetzenden Strings extrahiert mir ein Tool. Ich muss dann nur noch über einem Übersetzungstool meiner Wahl die extrahierten Strings übersetzen. Fertig :)

gepostet vor 15 Jahre, 9 Monate von BlackScorp

naja gut mit meiner variante kann man das auch die template datein müssen eben .php sein dann würde das ganze so aussehen:




aber ich werde mich mal mit symphonie beschäftigen, wie ist es dort eigentlich mit umlauten? weil bei mir ist es so wenn ich in de.php ein text habe zb "Überschrift" steht dann bei der ausgabe  ?berschift macht symphonie auch eine umwandlung von Ü nach ü??

gepostet vor 15 Jahre, 9 Monate von Fobby

Symfony (ja, das schreibt man wirklich so ;)) arbeitet generell mit Unicode, daher sind Umlaute kein Problem.

gepostet vor 15 Jahre, 9 Monate von Drezil

Original von Fobby

Symfony (ja, das schreibt man wirklich so ;)) arbeitet generell mit Unicode, daher sind Umlaute kein Problem.

und php und utf-8 macht keine probleme? ich dachte php kann nicht so richtig mit utf-8

gepostet vor 15 Jahre, 9 Monate von TheUndeadable

> und php und utf-8 macht keine probleme? ich dachte php kann nicht so richtig mit utf-8

Wenn man aufpasst, merkt PHP nichts davon, dass man UTF-8 nutzt... Es geht schon, aber erfordert Aufmerksamkeit.

gepostet vor 15 Jahre, 9 Monate von knalli

Original von Drezil

Original von Fobby

Symfony (ja, das schreibt man wirklich so ;)) arbeitet generell mit Unicode, daher sind Umlaute kein Problem.

und php und utf-8 macht keine probleme? ich dachte php kann nicht so richtig mit utf-8

Wie bereits in der Vergangenheit öfters erwähnt: PHP und UTF-8 beißen sich nur, wenn man als Programmierer keine Ahnung hat. Erste Hürde ist das Nutzen eines Editors, der das BOM nicht schreibt.

Jetzt stellt sich allerdings dennoch die Frage, was die eventuellen Sonderzeichen (will heißen: Nicht-englischer Text) in PHP oder Templates zu suchen hat. Oder programmiert ihr auf deutsch? (Iehh :))

edit: Achso, alle Übersetzungen werden "in PHP" geschrieben. Das hatte ich überlesen. Mh. :|

gepostet vor 15 Jahre, 9 Monate von BlackScorp

ja ich erweitere gerade mein template system ich mache dann ein parser welches Ä Ö Ü in ü usw umwandelt so wie mit bb codes mal schauen ob ich es hinkriege;)

MFG

gepostet vor 15 Jahre, 2 Monate von BlackScorp

 Hallo leute,

tut mir leid dass ich diesen Thread wieder zum leben erwecke. aber irgendwie scheint das Problem mit sprachen doch größer sein als es ist. Ich habe mir dieses symphony manual durchgelesen aber ich verstehe nicht wie ich es anwenden soll. Ich habe mir mal eine Language klasse geschrieben mit einer Methode showText. das Ganze schaut wie folgt aus:

PHP:

  public function showText($textName) {
       
                $query = "SELECT * FROM ".$GLOBALS['defines']['tablePrefix']."texts "
                    ."WHERE text_name ='%s' AND language_id = %d ";
                $sql = DataBase::getInstance()->sql($query,$textName,$_SESSION['languageId']);
                while($result = mysql_fetch_object($sql)) {
                    $this->languageText = $result->text_content;
               
            }
            return $this->languageText;
        }

Funktioniert auch wunderbar nur Problem ist dass ich ja damit bei jedem Text aufruf eine SQL Query ausführe. Habe mal just for fun die anzahl der querys ausgegeben es waren 100 stück. weil ich bei jedem button, jeder überschrift usw diese methode angewandt habe.

meine Frage wäre nun, wie könnte man es am besten lösen dass ich über ein Admin Control Pannel texte für verschieden sprachen bearbeiten/erstellen/löschen kann und dennoch beim aufruf der texte nicht auf eine datenbank zurückgreifen muss?

MFG

gepostet vor 15 Jahre, 2 Monate von Kampfhoernchen

Generiere ein Array mit

$_LANG['meinbutton1'] = 'Text1';

$_LANG['meineueberschrift'] = 'Ü1';

usw.

Dieses kann du relativ einfach schreiben und in der Sprachklasse inkludierst du das dann entsprechend.

Natürlich kannst du das auf verschiedene Dateien aufteilen, um kein übermäßig langes Array zu erzeugen. Z.B. eine Sprachdatei für jedes Template.

gepostet vor 15 Jahre, 2 Monate von buhrmi

Meine Meinung zu dem ganzen ist unverändert.

Es gibt zwei Welten:

Texte die aus der Datenbank gezogen werden liegen auch in der Datenbank übersetzt vor.

Alles andere (Templates, Fehlermeldungen, etc.) passiert wie Kampfhörnchen gesagt hat über eine Sprachdatei in irgendeinem Format. PHP Array oder whatever.

gepostet vor 15 Jahre, 2 Monate von knalli

Original von BlackScorp

 Hallo leute,

tut mir leid dass ich diesen Thread wieder zum leben erwecke. aber irgendwie scheint das Problem mit sprachen doch größer sein als es ist. Ich habe mir dieses symphony manual durchgelesen aber ich verstehe nicht wie ich es anwenden soll. Ich habe mir mal eine Language klasse geschrieben mit einer Methode showText. das Ganze schaut wie folgt aus:

PHP:

  public function showText($textName) {
       
                $query = "SELECT * FROM ".$GLOBALS['defines']['tablePrefix']."texts "
                    ."WHERE text_name ='%s' AND language_id = %d ";
                $sql = DataBase::getInstance()->sql($query,$textName,$_SESSION['languageId']);
                while($result = mysql_fetch_object($sql)) {
                    $this->languageText = $result->text_content;
               
            }
            return $this->languageText;
        }

Funktioniert auch wunderbar nur Problem ist dass ich ja damit bei jedem Text aufruf eine SQL Query ausführe. Habe mal just for fun die anzahl der querys ausgegeben es waren 100 stück. weil ich bei jedem button, jeder überschrift usw diese methode angewandt habe.

Ja super, funktioniert vielleicht, ist aber total kranker Code, sry :)

  1. SELECT * (MySQL)?
  2. Unübersichtliche (mM, subjektiv!) Stringkonkatination, bessere ist die (s)printf-Familie.
  3. Nutzen einer Schleife bei einem Single-Result.. entweder es ist jetzt ein result oder eine Liste von results.
  4. Btw: Gibt es keinen Standardwert?
  5. => Einige Anomalien.

meine Frage wäre nun, wie könnte man es am besten lösen dass ich über ein Admin Control Pannel texte für verschieden sprachen bearbeiten/erstellen/löschen kann und dennoch beim aufruf der texte nicht auf eine datenbank zurückgreifen muss?

Um diese Frage zu beantworten: 

  1. Bei jedem Request alle Texte laden und intern in einem Array zwischencachen.
  2. Wie 1., aber den Cache in einem (serialisierten) Objekt/Array temporär zwischenspeichern (Jeder Request = 1 Dateizugriff, das Erstellen wird beim Deploy gemacht, also wenn sich Texte ändern)
  3. Wie 1. oder 2., aber andere Möglichkeiten nutzen, bspw. Memcache.
  4. Eine Variation der genannten Optionen, unter zusätzlicher Gruppenfilterung (welche Texte werden wann genutzt). Damit kann man auf lange Hinsicht die Texte pro Web-Request auf ein DB-Query limitieren & gleichzeitig aber nur die notwendigen Texte laden. 

Oder: Datei als XML oder serialisiertem Array speichern (zum Bearbeiten) und danach eine entsprechende "$LANG"-Datei generieren.

gepostet vor 15 Jahre, 2 Monate von BlackScorp

Hi leute,

vielen dank für die Zahlreichen antworten. Mittlerweile habe ich meine showText in getTexts Methode überarbeitet. Ich hole mir nun alle benötigten Texte auf einmal aus der DB und Speicher das Ganze in ein Array. Ungefair so:

PHP:

 public function getTexts($textNames) {
        $this->languageText =array();
        $query = "SELECT text_name,text_content FROM ".$GLOBALS['defines']['tablePrefix']."texts "
            ."WHERE text_name IN ('".implode("','",str_replace($textNames,'%s',$textNames))."') AND language_id = %d AND project_id = %d";
          
        $sql = DataBase::getInstance()->sql($query,$textNames,$_SESSION['languageId'],$GLOBALS['defines']['projectId']);
        while($result = mysql_fetch_object($sql)) {
           
            $this->languageText[$result->text_name]= $result->text_content;
        }
        return $this->languageText;
    }

 Somit habe ich die Anzahl der Querys von 50+ auf 4 Reduziert.

Dann kam hier XML Speichern und $LANG Datei generieren zu sprache. Nun habe ich mir folgendes Überlegt.

Die Sprachtabelle soll nur als Zwischenspeicher dienen, damit ich zb beim ändern eines bestimmten Textes nicht auf die Aufwendingen string funktionen zrückgreifen muss, sondern bequem über SQL Query filtere.

Beim Editieren/Erstellen/Löschen wird jedesmal eine komplett neue lang.php erstellt und die vorhandene überschrieben.

Die eigentliche Seite führt kein einzigen Query aus um auf die Sprachtabelle zuzugreifen, sondern holt sich die Texte aus der Datenbank.

Was haltet ihr von der Überlegung?

Ein kleinen Hacken hat das Ganze, und zwar: Wenn angenommen ich mein Script weitergebe und der Benutzer den Textinhalt in der lang.php per Hand ändert. Und paar Tage später macht er das Selbe im ACP, so wird die alte lang.php überschrieben und seine änderungen, die er vor Tagen getätigt hat ist weg.

Also was könnte man Ignorieren? Redundanz zwischen Datei und DB oder Ständiger aufruf zur DB.

Wegen memcache. Aktuell will ich mir kein Server mieten und der FreeWebspace hat diese Funktion nicht.

MFG

gepostet vor 15 Jahre, 2 Monate von knalli

Original von BlackScorp

Hi leute,

vielen dank für die Zahlreichen antworten. Mittlerweile habe ich meine showText in getTexts Methode überarbeitet. Ich hole mir nun alle benötigten Texte auf einmal aus der DB und Speicher das Ganze in ein Array. Ungefair so:

PHP:

 public function getTexts($textNames) {
        $this->languageText =array();
        $query = "SELECT text_name,text_content FROM ".$GLOBALS['defines']['tablePrefix']."texts "
            ."WHERE text_name IN ('".implode("','",str_replace($textNames,'%s',$textNames))."') AND language_id = %d AND project_id = %d";
          
        $sql = DataBase::getInstance()->sql($query,$textNames,$_SESSION['languageId'],$GLOBALS['defines']['projectId']);
        while($result = mysql_fetch_object($sql)) {
           
            $this->languageText[$result->text_name]= $result->text_content;
        }
        return $this->languageText;
    }

 Somit habe ich die Anzahl der Querys von 50+ auf 4 Reduziert.

Sehr gut. Bei Bedarf kannst du noch eine Convenient-Methode bauen, etwa getText($textName) die aber (nur) den Cache nutzt.

Dann kam hier XML Speichern und $LANG Datei generieren zu sprache. Nun habe ich mir folgendes Überlegt.

Die Sprachtabelle soll nur als Zwischenspeicher dienen, damit ich zb beim ändern eines bestimmten Textes nicht auf die Aufwendingen string funktionen zrückgreifen muss, sondern bequem über SQL Query filtere.

Ok.

Beim Editieren/Erstellen/Löschen wird jedesmal eine komplett neue lang.php erstellt und die vorhandene überschrieben.

Ok.

Die eigentliche Seite führt kein einzigen Query aus um auf die Sprachtabelle zuzugreifen, sondern holt sich die Texte aus der Datenbank.

Ok, sehr gut.

Was haltet ihr von der Überlegung?

Ein kleinen Hacken hat das Ganze, und zwar: Wenn angenommen ich mein Script weitergebe und der Benutzer den Textinhalt in der lang.php per Hand ändert. Und paar Tage später macht er das Selbe im ACP, so wird die alte lang.php überschrieben und seine änderungen, die er vor Tagen getätigt hat ist weg.

  1. Sicher meintest du dann auch lang-de oder lang-de_DE.php? Weil muss ja abhängig von der Sprache sein..
  2. a) in einem Cache/Temp-Verzeichnis ablegen und b) in der Konfiguration ausdrücklich als automatisch generierte Datei deklarieren - wer das ignoriert, Pech.

Also was könnte man Ignorieren? Redundanz zwischen Datei und DB oder Ständiger aufruf zur DB.

Wegen memcache. Aktuell will ich mir kein Server mieten und der FreeWebspace hat diese Funktion nicht.

MFG

gepostet vor 15 Jahre, 2 Monate von BlackScorp

naja eigentlich dachte ich so ein inhalt inder lang.php

$text['text1']['de'] = 'Hallo Welt';

$text['text1']['en'] = 'Hello World';

aber für jede sprache eine eigene Datei wäre bestimmt sinnvoller damit nicht unnötige elemente in einem array auftauchen.

Ich werde das gleich mal umsetzen. Danke für die Tipps

EDIT: noch mal ne Frage. du hast gemeint :

Bei Bedarf kannst du noch eine Convenient-Methode bauen, etwa getText($textName) die aber (nur) den Cache nutzt.

meinste jetzt den Browsercache? kann ich überhaupt drauf zugreifen ? oder ist da das memcache gemeint?

gepostet vor 15 Jahre, 2 Monate von knalli

Frei nach dem Muster

function getText($key) {

// Load texts from database and pump into cache unless initialized.

if (!$this->initialized) {

$this->writeToCache($this->loadTexts($this->currentLocale), $this->currentLocale);

return $this->readFromCache($key, $this->currentLocale);

Ka, wie das bei dir aussieht.. wäre der Name "Abkürzungsmethode" verständlicher? :)

gepostet vor 15 Jahre, 2 Monate von BlackScorp

naja das ist mir schon klar aber diese funktionen readFromCache und writeToCache hat da php bereits funktionen? also PHP 5.2.x nicht 5.3. So dass ich die PHP funktionen in die methoden einbauen kann?

MFG

gepostet vor 15 Jahre, 2 Monate von BlackScorp

habe mir mal ySlow installiert und der sagte bei der Statistik folgendes:

The page has a total of 18 HTTP requests and a total weight of 468.4K bytes with empty cache

Dieses empty cache kann ich irgendwie da ein Array/Objekt/Sonstwas reinpacken und bei bedarf ansprechen? Wenn ja, mit welcher PHP Funktion? Und von Welchen Cache wird da überhaupt gesprochen?

MFG

gepostet vor 15 Jahre, 2 Monate von force4

Vom Browsercache. *guess*

gepostet vor 15 Jahre, 2 Monate von knalli

Manchmal frage ich mich, ob du uns einfach nur verschaukeln willst.

naja das ist mir schon klar aber diese funktionen readFromCache und writeToCache hat da php bereits funktionen? also PHP 5.2.x nicht 5.3. So dass ich die PHP funktionen in die methoden einbauen kann?

Die waren bleistifthaft "benamt" und dienen als Hinweis, wie du sie zu implementieren hast bzw. welche Art von Funktionalität ich meine.. nein, es gibt keine in PHP-fertigen Methoden(!). Sehen wir von magischen mal ab..

Dieses empty cache kann ich irgendwie da ein Array/Objekt/Sonstwas reinpacken und bei bedarf ansprechen? Wenn ja, mit welcher PHP Funktion? Und von Welchen Cache wird da überhaupt gesprochen?

Dir ist schon klar, das ySlow aus Sicht des Browsers testet und es dem Tool eigentlich sowas von Schnuppe ist, ob du als Webserver eine LAMPe, Katze (Tomcat) oder eine vorgestempelte Beamtenkontrollbehörde einsetzt. Will heißen: Nein. Und Browsercache (s.o.).

gepostet vor 15 Jahre, 2 Monate von Redrick

Original von knalli

Manchmal frage ich mich, ob du uns einfach nur verschaukeln willst.

knalli, die letzte bastion, wenn die bröckelt....

@BlackScorp:  man kann auch zuviele Fragen stellen, dann bleiben die motivation und eigenitiative auf der strecke und vorallem verwirrst du dich selbst schon. Wie zum geier bist auf auf yslow gekommen, hast du nicht die ganze zeit davon gesprochen die datenbank per php auszulesen und die ausgelesenen daten "flüssig" im speicher zu halten zu wollen bzw die diese einmalig im filesystem als includes abzulegen?

wenn ja, dann mach das endlich, die logic von knalli, sowie struktur von hörnchen reichen da vollkommen aus

gepostet vor 15 Jahre, 2 Monate von BlackScorp

ehm nein ySlow hat mich halt nur ein wenig verwirrt und es war nur sone kurze frage nebenbei.Hatte eigentlich nichts mit thema zu tun. Irgendwie verstehe ich das cachen überhaupt nicht. Also sobald ich im PHP Code hinschreibe $foo['bar'] = 'bar'; dann ist es im cache und wenn ich folgendes tue:

if(empty($foo['bar'])){

$foo['bar'] = 'bar';

}else{

echo $foo['bar'];

dann habe ich aus dem cache ein wert geladen, falls die variable belegt ist oder wie?

 Aber wie du es schon sagtest Redrick ich werde einfach mal weiter programmieren. und mein Code ändern. Tut mir leid wenn cih zu viele Fragen stelle

MFG  

gepostet vor 15 Jahre, 2 Monate von Redrick

cache ist IMHO ein weit dehnbarer begriff aber als Pufferspeicher-Definition immer richtig

und ich denke da lohnt sich echt mal nen blick in die wiki

http://de.wikipedia.org/wiki/Dynamischer_Speicher

sowie querverweis auf

http://de.wikipedia.org/wiki/Puffer_(Informatik) wo auch wiederum vorgriff auf Cache geleistet wird

http://de.wikipedia.org/wiki/Cache

browsercache-bedarf welchen yslow misst kannst du auf die Definition des "gebräuchlichen" Speicherchip-cache nur bedingt anwenden, du legst die Daten nicht mehr im speicher ab sondern auf Platte, ist eigentlich auch wumpe, denn da du die inhalte zwischenspeicherst auf dem client, verkürzt du damit die zugriffszeiten auf den server, und somit ist die aufgabe des cachings/pufferspeichers erfüllt

Auf diese Diskussion antworten