Mehrsprachige TYPO3 Extensions: getRecordOverlay richtig einsetzen
-
24. Juni 2010
-
TYPO3
Bei der Entwicklung mehrsprachiger Extensions für TYPO3 kommt man früher oder später in die Verlegenheit die richtigen (also in der benötigten Sprache) Datensätze aus der Datenbank zu holen. Viele Entwickler nutzen dazu eigene WHERE Anweisungen mithilfe derer sie den richtigen Datensatz ermitteln. Das sieht dann oftmals so aus:
// don't do this!
$where = 'uid = '.$uid.' AND sys_language_uid = '.$GLOBALS['TSFE']->sys_language_uid.' AND hidden = 0 AND deleted = 0';
Schlechtes Beispiel für eine TYPO3 DatenbankabfrageDie benötigte Sprache wird direkt gesetzt was zur Folge hat das man evtl. keinen Datensatz geliefert bekommt. Dies ist logischerweise dann der Fall wenn Der Datensatz noch nicht in die betreffende Sprache übersetzt wurde. Hört sich doch gar nicht so übel an?
Nicht ganz. Einerseits bricht man mit den Coding Guidelines und andererseits macht man ein tolles TYPO3 Feature zunichte: den localization mode. Mit dem localization mode kann das Verhalten von TYPO3 bei Mehrsprachigkeit, oder besser das Verhalten von TYPO3 bei fehlenden Sprachdatensätzen, konfigurieren.
TYPO3 und Mehrsprachigkeit
TYPO3 bietet ja bekanntlich sehr flexible Möglichkeiten um die Internationalisierung (gerne mit i18n abgekürzt) umzusetzen.
Prinzipiell kann auf Seitenebene mit der Option config.sys_language_mode gearbeitet werden. Diese gibt an wie mit der Seite umgegangen wird. So kann zum Beispiel per strict eine Fehlermeldung angezeigt werden wenn die Seite nicht verfügbar ist. content_fallback hingegen bietet die Seite dann in der konfigurierten default Sprache an.
Auf Inhaltsebene werden per config.sys_language_overlay = 1 nach Übersetzungen gesucht, aber immer alle Elemente angezeigt -- notfalls eben in der default Sprache. Mit dem Wert hideNonTranslated wird nicht übersetzter Inhalt hingegen versteckt.
Das sind nur die beiden wichtigsten Einstellungen und selbst deren Funktionen habe ich hier nicht gänzlich abgedeckt. Es existieren noch viele weitere Möglichkeiten (wie etwa config.sys_language_softMergeIfNotBlank), aber der Teil hier langt zum Verständnis.
Schaut euch die untenstehende Linksammlung an, dort erfahrt ihr mehr.
SQL Anweisung für Mehrsprachige Extensions
Um das oben beschriebene Verhalten auch in eigenen Extension möglich zu machen sollte man darauf achten mehrsprachige Datensätze korrekt aus der Datenbank holen.
Zuerst holt man sich die Standardsprache aus der Datenbank. Das macht man normalerweise mit mit der WHERE Bedingung sys_language_uid = 0.
Findige TYPO3 User schaffen es aber auch einen Datensatz anzulegen, ohne vorher die Default-Sprache anzulegen. Um diesem Umstand vorzubeugen ändern wir die SQL Anweisung auf folgende Bedingungen ab: Standard-Sprache ODER den übersetzten Datensatz (der dann aber kein parent Element haben darf).
<?php
// we need at last uid, pid, sys_language_uid
$select = 'uid, pid, sys_language_uid, text, title';
$table = 'tx_myext_data';
// we try to get the default language entry (normal behaviour) or, if not possible, currently the needed language (fallback if no default language entry is available)
$where = '(sys_language_uid IN (-1,0) OR (sys_language_uid = ' .$GLOBALS['TSFE']->sys_language_uid. ' AND l18n_parent = 0))';
// always (!) use TYPO3 default function for adding hidden = 0, deleted = 0, group and date statements
$where .= $GLOBALS['TSFE']->sys_page->enableFields($table);
$order = '';
$group = '';
$limit = '';
$res = $GLOBALS['TYPO3_DB']->exec_SELECTquery($select, $table, $where, $group, $order, $limit);
while ($row = $GLOBALS['TYPO3_DB']->sql_fetch_assoc($res)) {
// check for language overlay if:
// * row is valid
// * row language is different from currently needed language
// * sys_language_contentOL is set
if (is_array($row) && $row['sys_language_uid'] != $GLOBALS['TSFE']->sys_language_content && $GLOBALS['TSFE']->sys_language_contentOL) {
$row = $GLOBALS['TSFE']->sys_page->getRecordOverlay($table, $row,$GLOBALS['TSFE']->sys_language_content, $GLOBALS['TSFE']->sys_language_contentOL);
}
if ($row) {
// get correct language uid for translated realurl link
$link_uid = ($row['_LOCALIZED_UID']) ? $row['_LOCALIZED_UID'] : $row['uid'];
// do stuff with the row entry data like built HTML or prepare further usage
}
}
?>
Mehrsprachige TYPO3 Extensions: Mehrsprachige Datensätze korrekt aus der DB holen.Es folgt eine normale TYPO3 DB Abfrage. Anschließend testen wir auf eine valides Array, ob wir eine andere Sprache überhaupt benötigen und ob die Konfiguration für den localization mode (wie er oben kurz erläutert wurde) vorhanden ist. Wenn ja, ereledigt TYPO3 den Rest: den Overlay-Datensatz mit der gewünschten Sprache ziehen, um damit den vorhandenen (alten) Datensatz ganz oder teilweise zu ersetzen bzw. die row zu löschen. Letzteres müsste evtl. bei gesetzter hideNoneTranslated Option gemacht werden.
So erhalten wir genau die Datensätze die wir brauchen und können die Ausgabe / Weiterverarbeitung angehen.
Hinweise
Gegebenenfalls muss sys_language_uid im select mit $TCA[$table]['ctrl']['languageField'] ersetzt werden (global $TCA; Anweisung nicht vergessen!). Ist aber im Normalfall nicht nötig.
Eine Problematik bleibt bestehen: Wenn der Standard-Datensatz versteckt wurde, kann keine Übersetzung gefunden werden (auch wenn diese nicht versteckt ist und angezeigt werden soll). Hier wäre generell das "mehrere Seitenbaumäume" Prinzip vorzuziehen.
Eine andere Möglichkeit wäre es die enableFields Anweisung wegzulassen und erst die fertige (bereits mit getRecordOverlay bearbeitete) row manuell auf hidden, deleted, Gruppen und Zeit zu prüfen.
Referenzen:
- Frontend Lokalisierung von TYPO3 (typo3.org docs)
- Artikel von typo3-media.de
- http://wiki.typo3.org/index.php/User:Maholtz#Mehrsprachige_Extensions_entwickeln
Wie immer freue ich mich über Feedback und Hinweise. Wenn ich kann helfe ich auch gerne, eine Antwort ist euch in jedem Fall sicher.
03. Juli 2012
Danke für den sehr guten Artikel!
14. Mai 2012
Weil es eben diese Muster Extension nicht gibt habe ich diesen Artikel geschrieben. Ich hab mir das aus vers. Extensions zusammengesucht und wollte das mal notieren.
Ich glaube das mit der Sortierung (wie auch das mit den versteckten Originaldatensätzen) kann bei dem Konzept nicht funktionieren.
Eventuell wird das bei Extbase bald implementiert. Noch ist Mehrsprachigkeit und Extbase ja auch eine einzige Katastrophe. Guckst du hier:
forge.typo3.org/issues/32072
forge.typo3.org/issues/32216
12. Mai 2012
Danke für diesen Artikel!
Wenn man nach getRecordOverlay sucht findet man in fast jedem Forum oder Maillinglist Artikel einen Link auf diese Seite.
Ideal wäre, wenn es eine Mehrsprachige Muster Extension geben würde ( multilang_example, oder so ähnlich ) bei welcher man einen Titel und einen Text übersetzen kann.
Ebenfalls müsste auch folgende Config korrekt funktionieren.
config.sys_language_mode=content_fallback;1,2,3,0
Und bei der Übersetzten Variante wir der Titel korrekt nach A-Z sortiert ( und nicht die Sortierung der Standardsprache verwendet )
04. August 2011
Hey Markus,
also wenn ich in die Tabellen einiger Extensions (tt_news, t3blog, aber auch tt_content) sehe steht da aber überall l18n_parent. I18N wird für gewöhnlich genutzt um die Gestaltung (die "Möglichkeit des Einpflegens von Sprachen") der Software zu beschreiben, während L10N meist den eigentlichen Übersetzungsvorgang beschreibt. Ich würde meinen das passt so, aber was da jetzt anerkannte Praxis ist, ka.
04. August 2011
Die Spalte heißt nicht l18n_parent sondern l10n_parent
(localisation, nicht internationalisation).
Aber sonst: guter Beitrag, danke :)