Mehrsprachigkeit

Hier dreht sich alles um die auf der Webseite veröffentlichten Tutorials. // This forum is all about the APF tutorials.
Antworten
Avedo

Mehrsprachigkeit

Beitrag von Avedo » 01.04.2010, 15:36:41

Guten Morgen!

Nun da die Klausur geschrieben ist, habe ich auch wieder etwas Zeit. Wie angekündigt möchte ich mich nun etwas mit der Mehrsprachigkeit einer mit dem APF erstellten Seite beschäftigen. Da ich es so oder so sehr umständlich finde, alle Inhalte in Dateien im Hintergrund ablegen zu müssen, wäre es eigentlich sehr schön, wenn man die Inhalte einfach in einer Datenbank speichert. Deshalb habe ich mir einige Gedanken zu diesem Thema gemacht.

Funktionen:
* Verwaltung von sprachabhängigen Inhalten
* CRUD-Operationen auf Sprachen
* Falls Inhalte nur in ein oder zwei Sprachen verfügbar sind, wird automatisch eine der Verfügbaren sprachen ausgewählt

Das bedeutet, dass ich die Sprachen, die ich anbieten möchte, verwalten können muss. Außerdem muss ich in der Lage sein, diesen Sprachen Inhalte zuzuordnen, die wiederum in einem eigenen Adminpanel verwaltet werden können.

Das Domänen Objekt der Sprache sieht dann wie folgt aus.

Code: Alles auswählen

<?php



/**

 * Implements the Language domain object of the langmanager modul.

 *

 * @author Andreas Wilhelm

 * @version

 * Version 0.1, 01.04.2010<br />

 */

final class Language {



	/**

	 * @private

	 * Contains the unique language id, the country code, used to identify on update/delete.

	 */

	private $id;



	/**

	 * @private

	 * The full name of the language. 

	 */

	private $language;



	/**

	 * @private

	 * The link the description for the language button. 

	 */

	private $linkDesc;



	/**

	 * @private

	 * The image used for the link.

	 */

	private $linkImage;



	public function getId() {

		return $this->id;

	}  

      

	public function getLanguage() {

		return $this->language;

	}



	public function getLinkDescription() {

		return $this->linkDesc;

	}



	public function getImageLink() {

		return $this->linkImage;

	}



	public function setId($id){

		$this->id = $id;

	}



	public function setLanguage($lang) {

		$this->language = $lang;

	}



	public function setLinkDescription($desc) {

		$this->linkDesc = $desc;

	}



	public function setImageLink($path) {

		$this->linkImage = $path;

	}

}

?>
Das des Content sieht so aus.

Code: Alles auswählen

<?php



/**

 * Implements the Content domain object of the langmanager modul.

 *

 * @author Andreas Wilhelm

 * @version

 * Version 0.1, 01.04.2010<br />

 */

final class Language {



	/**

	 * @private

	 * Contains the unique content id, used to identify on update/delete.

	 */

	private $id;



	/**

	 * @private

	 * The url name of the page. 

	 */

	private $url;



	/**

	 * @private

	 * The page title. 

	 */

	private $title;



	/**

	 * @private

	 * A short description of this content.

	 */

	private $description;



	/**

	 * @private

	 * The content of this page.

	 */

	private $content;



	/**

	 * @private

	 * The language this content is written in.

	 */

	private $lang;



	public function getId() {

		return $this->id;

	}  



	public function getUrl() {

		return $this->url;

	}

      

	public function getTitle() {

		return $this->title;

	}

      

	public function getDescription() {

		return $this->description;

	}



	public function getContent() {

		return $this->content;

	}



	public function getLanguage() {

		return $this->lang;

	}



	public function setId($id){

		$this->id = $id;

	}



	public function setTitle($title) {

		$this->title = $title;

	}



	public function setDescription($desc) {

		$this->description = $desc;

	}



	public function setContent($content) {

		$this->content = $content;

	}



	public function setLanguage($lang) {

		$this->lang = $lang;

	}

}

?>
Der Controller für die Ausgabe könnte nun so aussehen.

Code: Alles auswählen

<?php

/**

 * The content controller loads language specific content and returns it.

 *

 * @author Andreas Wilhelm

 * @version

 * Version 0.1, 18.03.2010<br />

 */

class content_controller extends base_controller {
	function content_v1_controller() {
	}

	function transformContent() {
		// Fetch an instance of the database class.
		$SQL = $this->__getServiceObject('core::database','MySQLHandler');

		// Get the url parameter ...
		$page = RequestHandler::getValue('Seite','Startseite');

		// ... and protect the parameter against SQL-Injections.
		$page = $SQL->escapeValue($page);

		// The get the language parameter ...
		$lang = RequestHandler::getValue('Sprache','English');

		// ... and protect it also.
		$lang = $SQL->escapeValue($lang);

		// Now create the select statment to fetch the language specific content ...
		$select = '
			SELECT 
				content 
			FROM 
				ent_content 
			WHERE 
				url = \'' . $page . '\'
				AND lang =  \'' . $lang . '\' 
			LIMIT 1';

		// ... and send it to the database.
		$result = $SQL->executeTextStatement($select);

		// Finally fetch the returned data ...
		$data = $SQL->fetchData($result);

		// ... and print out the content.
		$this->__Content = $data['content'];
	}
}

?>
Was meint ihr? Geht das so? Und was sollte ich als nächstes tun?

Liebe Grüße,

Andreas

Benutzeravatar
dr.e.
Administrator
Beiträge: 4538
Registriert: 04.11.2007, 16:13:53

Re: Mehrsprachigkeit

Beitrag von dr.e. » 01.04.2010, 15:56:58

Hallo Andreas,

Inhalte in der datenbank zu verwalten sich sicher die bessere Möglichkeit. Die APF-Seite ist auch nur der Einfachheit halber so umgesetzt, das APF ist also nicht darauf beschränkt. :)
Was meint ihr? Geht das so? Und was sollte ich als nächstes tun?
Der Ansatz ist sicher korrekt so. Nur wenn du schon Domänen-Objekte modellierst, würde ich diese auch verwenden. Das bedeutet, dass ich einen ContentManager einführen würde, der bei Übergabe einer ID oder auch eines URL-Kenners eines Inhalts (z.B. http://ww.test.de/faqs soll ja auch die FAQ-Seite anzeigen) und der gewünschten Sprache diesen zurückliefert. API-technisch kann das z.B. so aussehen:

Code: Alles auswählen

ContentManager getContent($id, Language $lang)
ContentManager getContent($urlName, Language $lang)
In der Datenbank würde ich - da du Sprachen verwaltbar machen möchtest - diese vom Inhalt trennen. Bedeutet folgende Tabellen:
  • language: Alle Attribute der Sprache aus deinem Domänen-Objekt
  • content: Alle Attribute des Inhalts (ID, URL-Kenner, Inhalt, Erstellungs- und Ändeurngsdatum, ...) aus deinem Domänen-Objekt
  • language2content: Verknüpfung der Inhalte mit der Sprache
Im Controller fragst du dann den ContentManager den Inhalt zu laden und stellst den Inhalt lediglich dar. Noch ein Tipp: sofern du vor hast im Inhalt weitere APF-XML-Tags zu platzieren um z.B. Module einzubinden, würde ich keinen Controller sondern eine Taglib nutzen, die selbstverständlich auch einen ContentManager nutzen kann. Dort kannst du dann in der Methode onParseTime() viel einfacher die Tags interpretieren als in einem Controller.
Viele Grüße,
Christian

Avedo

Re: Mehrsprachigkeit

Beitrag von Avedo » 01.04.2010, 16:47:18

Guten Abend!

Danke für deine Antwort. Habe mich nun daran gemacht einen ContentMapper zu schreiben, auf den dann der ContentManager zurückgreifen kann. Dazu habe ich mir nochmal das Beispiel guestbook2009 angesehen und dabei ist mir die nachfolgende Methode aufgefallen.

Code: Alles auswählen

      /**
       * @private
       *
       * @return GenericDomainObject The active language's representation object.
       *
       * @author Christian Achatz
       * @version
       * Version 0.1, 06.05.2009<br />
       */
      private function __getCurrentLanguage(){

         $crit = new GenericCriterionObject();
         $crit->addPropertyIndicator('ISOCode',$this->__Language);
         $orm = &$this->__getGenericORMapper();
         return $orm->loadObjectByCriterion('Language',$crit);

       // end function
      }
Wie sieht dieses Language Objekt aus und wie wird es gesetzt? Wird es direkt durch den Aufruf

Code: Alles auswählen

$fC->set('Language','lang-code');
im FrontController gesetzt?

Ds wäre sehr wichtig zu wissen, um die dort abgelegetn Daten eventuell einfach in mein Modul spezifisches Domänen Objekt zu laden.

Liebe Grüße,

Andreas

Benutzeravatar
dr.e.
Administrator
Beiträge: 4538
Registriert: 04.11.2007, 16:13:53

Re: Mehrsprachigkeit

Beitrag von dr.e. » 01.04.2010, 18:19:16

Hallo Andreas,

$this->__Language wird in coreObject (1.11) und APFObject (1.12) definiert. Es dient dazu den aktuellen Sprachkürzel (ISO) aufzunehmen. Die Eigenschaft wird entsprechend in jedes Objekt injiziert und kann daher im Document-Controller, in einer Taglib und in einem Objekt, das mit __get[AndInit]ServiceObject() oder __getDIServiceObject() erzeugt wurde, genutzt werden.

Bei der Implementierung habe ich mich entschieden, "einfach nur" das ISO-Kürzel als Text zu verwenden ("de" by default) und keine eigene Objekt-Repräsentation eingeführt. Gesetzt und initialisiert wird das Ganze beim Erzeugen des Page- oder Front-Controller (wie du in deinem Code-Snippet schon richtig beschrieben hast). Du kannst die Eigenschaft natürlich in einer Front-Controller-Action (prepagecreate) oder in der index.php (Beispiele hier im Forum) nach deinen Wünschen setzen.

Beim Gästebuch wird die Sprache als eigenes Domänen-Objekt auf Basis der ISO-Länder-Kürzel erzeugt, weil es zur Domäne gehört. Diese Vorgehensweise kannst du natürlich adaptieren.
Viele Grüße,
Christian

Avedo

Re: Mehrsprachigkeit

Beitrag von Avedo » 08.04.2010, 21:27:01

Guten Abend!

So ich habe mir nun vorgenommen, dass ich bevor ich irgendetwas anderes mache, die Mehrsprachigkeit in den Griff bekommen möchte. Ich habe ja, wie man meinem ersten Post entnehmen konnte, zwei Domänen-Objekte, eines für die Sprache und eines für den eigentlichen Content vorgesehen. Die Objekte sind so erstmal fertig. Allerdings benötige ich nun einen Mapper, der die Kommunikation mit der Datenbank übernimmt. Nun habe ich leider einige Probleme.

Wie ist es mir zum Beispiel möglich mit Hilfe der hinterlegten Konfigurationen eine Verbindung zur Datenbank herzustellen? Oder brauche ich das garnicht und könnte zum Beispiel ein Objekt direkt aus der Registry laden? Wie sieht außerdem das APFObject aus? Von diesem kann ich ja erfahren, welche Sprache momentan vom Benutzer gewünscht wird, da diese Information sowohl vom PageManager, als auch in meinem Fall vom FrontController gesetzt wird. Wie sollte ich des weiteren meinen Mapper am geschicktesten aufbauen? Dieser wird ja von meinem ContentManager benötigt, der die Methoden zum Laden der sprachabhängigen Inhalte bereitstellen soll. Sollte der ContentManager außerdem alle Methoden zur Verfügung stellen, die zum Anlegen, Bearbeiten und Lesen von Sprachinformationen und Content benötigt werden?

Abschließend würde mich noch interessieren, was du damit meinst, dass ich lieber eine TagLib, als einen DocumentController verwenden soll. Welchem Zweck dient das bzw. wieso ist es mir nur auf diese Weise möglich im Inhalt weitere APF-XML-Tags zu platzieren?

Viele Fragen, ich hoffe aber, dass sie mir dennoch beantwortet werden. :?

Liebe Grüße,

Andreas

Benutzeravatar
dr.e.
Administrator
Beiträge: 4538
Registriert: 04.11.2007, 16:13:53

Re: Mehrsprachigkeit

Beitrag von dr.e. » 09.04.2010, 09:47:22

Hallo Andreas,

ich gehe die Fragen mal step-by-step durch:
Wie ist es mir zum Beispiel möglich mit Hilfe der hinterlegten Konfigurationen eine Verbindung zur Datenbank herzustellen?
Hierzu nutzt du den ConnectionManager, der dir an Hand einer Verbindungs-Kennung eine Verbindung zurückliefert. Da der Page-Controller oder der ServiceManager bereits alle wichtigen Informationen in die jeweiligen Objekte injizieren, reicht es einfach, den ConnectionManager als Service zu beziehen und diesen nach der gewünschten Connection zu fragen. Der ConnectionManager selbst, erwartet dann in der Datei /apps/config/core/database/{CONTEXT}/{ENVIRONMENT}_connections.ini eine Sektion mit der relevanten Datenbank-Verbindung.
Oder brauche ich das garnicht und könnte zum Beispiel ein Objekt direkt aus der Registry laden?

Nein, die Registry kann dafür nicht genutzt werden. Es gibt Frameworks, die solche Verfahren anwenden, das würde aber eine Einschränkung der möglichen DB-Verbindungen bedeuten. Weiterhin sind DB-Verbindungen eine Angelegenheit der jeweiligen Daten-Schichten der Anwendungen und keine globale variable.
Wie sieht außerdem das APFObject aus? Von diesem kann ich ja erfahren, welche Sprache momentan vom Benutzer gewünscht wird, da diese Information sowohl vom PageManager, als auch in meinem Fall vom FrontController gesetzt wird.
Das APFObject ist - wie Object - eine Basis-Klasse für alle möglichen Klassen des APF. Es gibt also keine explizite Instanz von diesem Objekt, sondern die Eigenschaften und Methoden stecken jeweils in den Instanzen deiner Applikation. In einer solchen Instanz hast du die Variable $this->__Language, die die aktuell gewählte Sprache beinhaltet. Das ist in einer Taglib genauso der Fall wie in einem Service-Objekt, das mit dem Service-Manager erzeugt wurde (__get[AndInit]ServiceObject() oder __getDIServiceObject()). Diese Information kannst du dann also z.B. auch in deinem Mapper nutzen.
Wie sollte ich des weiteren meinen Mapper am geschicktesten aufbauen?
Hast du dir mal die Tutorials Kommentar-Funktion und Kontakt-Formular angesehen? Dort findest du einfache Beispiele, wie ein Mapper aufgebaut werden kann. Kommst du damit nicht zurecht, können wir gerne ein konkretes Beispiel besprechen.
Dieser wird ja von meinem ContentManager benötigt, der die Methoden zum Laden der sprachabhängigen Inhalte bereitstellen soll. Sollte der ContentManager außerdem alle Methoden zur Verfügung stellen, die zum Anlegen, Bearbeiten und Lesen von Sprachinformationen und Content benötigt werden?
Ob du die Verwaltung der Sprach-Informationen dort integrierst oder einen eigenen Manager bereitstellst, ist mehr oder weniger Geschmacksache. Weniger deshalb, weil eine Klasse per se nur eine explizite Aufgabe erfüllen soll - in diesem Fall wären es dann zwei. Für den Anfang ist es aber kein Problem, denn es wird sicher nicht die Notwendigkeit geben, das Sprach-Handling in einer anderen Komponente weiter zu verwenden. Sollte das doch mal der Fall sein, kannst du das ja auch nachträglich herauslösen.
Abschließend würde mich noch interessieren, was du damit meinst, dass ich lieber eine TagLib, als einen DocumentController verwenden soll. Welchem Zweck dient das bzw. wieso ist es mir nur auf diese Weise möglich im Inhalt weitere APF-XML-Tags zu platzieren?
Was den Unterschied angeht, kannst du dir mal Taglib vs. Template durchlesen. Im Allgemeinen gilt die Regel: "Wenn du mit einem Template nicht mehr weiter kommst, schreibe eine Taglib." Einfache Inhalte kannst du jederzeit im Controller einbinden, sofern der Inhalt jedoch APF-XML-tags beinhaltet, die auch im gleichen Zug mit der Einbindung geparst werden sollen, ist eine Taglib erforderlich. Der Grund ist recht simpel: nur eine Taglib kann auf den DOM-Baum Einfluss nehmen und das Parsen von APF-XML-Tags ist eine Einflussnahme, da neue Kind-Knoten erstellt werden.
Viele Grüße,
Christian

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast