Lokalisierung und FlexForms - Typo3: Extension selbst erstellen

Lokalisierung und FlexForms - Typo3: Extension selbst erstellen
Von Lars Ebert am 18.06.12, 11:00
Kategorien: Content Management Systeme, PHP, Programmieren, Tutorials and Typo3

Unsere Extension bietet seit dem letzten Teil der Artikelserie schon eine recht gute Konfiguration über TypoScript. In diesem Artikel will ich dir zeigen, wie du dem Nutzer die Möglichkeit gebt, direkt beim Einfügen des Plugins Einstellungen zu definieren. Dazu benutzen wir FlexForms.

Außerdem lernst du, wie man die Extension in mehreren Sprachen anbieten kann.

Artikelserie: Typo3: Extension selbst erstellen

Dieser Artikel ist Teil einer mehrteiligen Artikelserie. Lies dir auch die restlichen Teile durch!

  1. Kickstarter, Grundlagen & Hallo Welt - Typo3: Extension selbst erstellen
  2. Formulare, Parameter und Eingaben - Typo3: Extension selbst erstellen
  3. Templates, CSS und TypoScript - Typo3: Extension selbst erstellen
  4. Lokalisierung und FlexForms - Typo3: Extension selbst erstellen
  5. Planung, Dokumentation und Veröffentlichung – Typo3: Extension selbst erstellen

Lokalisierung

Als erstes werden wir die Lokalisierung umsetzen. Öffne zuerst die Dateien pi1/locallang.xml und pi1/class.tx_lecontactform_pi1.php.

Schau dir die Datei locallang.xml mal an. Hier siehst du eine XML-Struktur, in der Text-Schnipsel in mehreren Sprachen hinterlegt werden können. Wir müssen nun für den Text, den wir im Plugin ausgeben, in diese Datei locallang.xml verlagern und dann vom Plugin auslesen lassen. So kann die Datei locallang.xml später in beliebige Sprachen übersetzt werden und Typo3 wählt automatisch die Systemsprache aus.

Ich fange mal einfach mit den Fehlermeldungen an, diese befinden sich in den Zeilen 87 bis 93. Meine locallang-Datei sieht danach so aus:


<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3locallang>
	<meta type="array">
		<type>module</type>
		<description>Language labels for plugin "tx_lecontactform_pi1"</description>
	</meta>
	<data type="array">
		<languageKey index="default" type="array">
			<label index="errors.name">Please enter your full name!</label>
			<label index="errors.mail">Please enter your e-mail address, so we can send you an answer.</label>
			<label index="errors.message">Is there nothing left to say? Just enter a message for us!</label>
		</languageKey>
		<languageKey index="de" type="array">
			<label index="errors.name">Bitte geben Sie Ihren Namen ein!</label>
			<label index="errors.mail">Bitte geben Sie Ihre Mail-Adresse ein. Wie sollen wir Ihnen denn sonst antworten?</label>
			<label index="errors.message">Haben Sie uns denn gar nichts zu sagen? Bitte geben Sie doch eine Nachricht an uns ein!</label>
		</languageKey>
	</data>
</T3locallang>

Die Struktur der Datei ist eigentlich recht simpel. Mit dem Tag languageKey können wir eine neue Sprache definieren. Mit dem index-Attribut können wir den Schlüssel der Sprache definieren, Englisch ist die Standard-Sprache, de steht für Deutsch.

Innerhalb des languageKey-Tags können wir dann für jeden Text-Schnipsel einen label-Tag definieren, das index-Attribut dient hier später dazu, den Schnipsel anzusprechen.

Genau das tun wir jetzt in der Datei class.tx_lecontactform_pi1.php

Bei der Ausgabe der Fehlermeldungen greifen wir jetzt auf die Locallang-Schnipsel zurück.


if(!isset($this->piVars['sender_name']) || trim($this->piVars['sender_name']) == '') {
	$errors['sender_name'] = $this->pi_getLL('errors.name');
}
if(!isset($this->piVars['sender_mail']) || trim($this->piVars['sender_mail']) == '') {
	$errors['sender_mail'] = $this->pi_getLL('errors.mail');
}
if(!isset($this->piVars['message']) || trim($this->piVars['message']) == '') {
	$errors['message'] = $this->pi_getLL('errors.message');
}

Nun kommt ein wenig Arbeit auf uns zu, denn wir müssen in der gesamten Datei pi1/class.tx_lecontactform_pi1.php alle Textausgaben in die Datei pi1/locallang.xml verlagern.

Nachdem alles ersetzt wurde, sehen meine Dateien so aus.


<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3locallang>
	<meta type="array">
		<type>module</type>
		<description>Language labels for plugin "tx_lecontactform_pi1"</description>
	</meta>
	<data type="array">
		<languageKey index="default" type="array">
			<label index="errors.notsent">The message could not be sent, please check your input!</label>
			<label index="errors.name">Please enter your full name!</label>
			<label index="errors.mail">Please enter your e-mail address, so we can send you an answer.</label>
			<label index="errors.message">Is there nothing left to say? Just enter a message for us!</label>
			<label index="label.name">Name</label>
			<label index="label.mail">E-Mail</label>
			<label index="label.message">Message</label>
			<label index="label.send">Send message</label>
			<label index="placeholder.name">Your name</label>
			<label index="placeholder.mail">Your e-mail address</label>
			<label index="placeholder.message">Please enter your message for us!</label>
			<label index="contactby">Contact request by</label>
			<label index="messagesent">Your message was successfully sent. Thank you! We will get back to you as soon as possible.</label>
		</languageKey>
		<languageKey index="de" type="array">
			<label index="errors.notsent">Die Nachricht konnte nicht abgesendet werden. Bitte überprüfen Sie Ihre Eingaben!</label>
			<label index="errors.name">Bitte geben Sie Ihren Namen ein!</label>
			<label index="errors.mail">Bitte geben Sie Ihre Mail-Adresse ein. Wie sollen wir Ihnen denn sonst antworten?</label>
			<label index="errors.message">Haben Sie uns denn gar nichts zu sagen? Bitte geben Sie doch eine Nachricht an uns ein!</label>
			<label index="label.name">Name</label>
			<label index="label.mail">E-Mail</label>
			<label index="label.message">Nachricht</label>
			<label index="label.send">Nachricht versenden</label>
			<label index="placeholder.name">Ihr Name</label>
			<label index="placeholder.mail">Ihre E-Mail-Adresse</label>
			<label index="placeholder.message">Geben Sie hier Ihre Nachricht an uns ein!</label>
			<label index="contactby">Kontaktanfrage von</label>
			<label index="messagesent">Ihre Nachricht wurde erfolgreich versandt. Danke! Wir werden uns schnellstmöglich mit Ihnen in Verbindung setzen.</label>
		</languageKey>
	</data>
</T3locallang>

<?php
/***************************************************************
*  Copyright notice
*
*  (c) 2012 Lars Ebert <info@advitum.de>
*  All rights reserved
*
*  This script is part of the TYPO3 project. The TYPO3 project is
*  free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  The GNU General Public License can be found at
*  http://www.gnu.org/copyleft/gpl.html.
*
*  This script is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  This copyright notice MUST APPEAR in all copies of the script!
***************************************************************/
/**
 * [CLASS/FUNCTION INDEX of SCRIPT]
 *
 * Hint: use extdeveval to insert/update function index above.
 */

require_once(PATH_tslib.'class.tslib_pibase.php');


/**
 * Plugin 'Contact form' for the 'le_contactform' extension.
 *
 * @author	Lars Ebert <info@advitum.de>
 * @package	TYPO3
 * @subpackage	tx_lecontactform
 */
class tx_lecontactform_pi1 extends tslib_pibase {
	var $prefixId      = 'tx_lecontactform_pi1';		// Same as class name
	var $scriptRelPath = 'pi1/class.tx_lecontactform_pi1.php';	// Path to this script relative to the extension dir.
	var $extKey        = 'le_contactform';	// The extension key.
	var $pi_checkCHash = true;
	
	/**
	 * The main method of the PlugIn
	 *
	 * @param	string		$content: The PlugIn content
	 * @param	array		$conf: The PlugIn configuration
	 * @return	The content that is displayed on the website
	 */
	function main($content, $conf) {
		$this->conf = $conf;
		$this->pi_setPiVarDefaults();
		$this->pi_loadLL();
		
		if($this->conf['template'] == '') {
			$this->conf['template'] = 'EXT:' . $this->extKey . '/pi1/templates/contactform.tmpl';
		}
		if($this->conf['cssFile'] == '') {
			$this->conf['cssFile'] = 'EXT:' . $this->extKey . '/pi1/css/tx_lecontactform_pi1.css';
		}
		
		$GLOBALS['TSFE']->pSetup['includeCSS.'][$this->extKey] = $this->conf['cssFile'];
		
		
/* 		$content='
			<strong>This is a few paragraphs:</strong><br />
			<p>This is line 1</p>
			<p>This is line 2</p>
	
			<h3>This is a form:</h3>
			<form action="'.$this->pi_getPageLink($GLOBALS['TSFE']->id).'" method="POST">
				<input type="text" name="'.$this->prefixId.'[input_field]" value="'.htmlspecialchars($this->piVars['input_field']).'">
				<input type="submit" name="'.$this->prefixId.'[submit_button]" value="'.htmlspecialchars($this->pi_getLL('submit_button_label')).'">
			</form>
			<br />
			<p>You can click here to '.$this->pi_linkToPage('get to this page again',$GLOBALS['TSFE']->id).'</p>
		'; */
		
		$errors = array();
		$message = '';
		$class = '';
		if(isset($this->piVars['send_message'])) {
			if(!isset($this->piVars['sender_name']) || trim($this->piVars['sender_name']) == '') {
				$errors['sender_name'] = $this->pi_getLL('errors.name');
			}
			if(!isset($this->piVars['sender_mail']) || trim($this->piVars['sender_mail']) == '') {
				$errors['sender_mail'] = $this->pi_getLL('errors.mail');
			}
			if(!isset($this->piVars['message']) || trim($this->piVars['message']) == '') {
				$errors['message'] = $this->pi_getLL('errors.message');
			}
			
			if(count($errors) == 0) {
				$subject = '=?UTF-8?B?' . base64_encode(utf8_encode($this->pi_getLL('contactby') . ' ' . htmlspecialchars($this->piVars['sender_name']))) . '?=';
				
				$header = "From:" . htmlspecialchars($this->piVars['sender_mail']) . "\nContent-Type:text/plain; charset=utf-8\nContent-Transfer-Encoding: 8bit\n";
				
				@mail('info@advitum.de', $subject, $this->piVars['message'], $header);
				
				$message = $this->pi_getLL('messagesent');
				$class = 'success';
			}
			else {
				$message = $this->pi_getLL('errors.notsent');
				$class = 'error';
			}
		}
		
		$this->template = $this->cObj->fileResource($this->conf['template']);
		
		$contactFormTemplate = $this->cObj->getSubpart($this->template, '###CONTACT_FORM###');
		$successMessageTemplate = $this->cObj->getSubpart($this->template, '###SUCCESS_MESSAGE###');
		$errorMessageTemplate = $this->cObj->getSubpart($this->template, '###ERROR_MESSAGE###');
		$validationMessageTemplate = $this->cObj->getSubpart($this->template, '###VALIDATION_MESSAGE###');
		
		$markerArray = array(
			'###FORM_ATTRIBUTES###'			=> 'class="le_contactform_form" action="' . $this->pi_getPageLink($GLOBALS['TSFE']->id) . '" method="POST"',
			'###MESSAGE###'					=> '',
			'###SENDER_NAME_ID###'			=> $this->prefixId . '_sender_name',
			'###SENDER_NAME_LABEL###'		=> $this->pi_getLL('label.name'),
			'###SENDER_NAME_NAME###'		=> $this->prefixId . '[sender_name]',
			'###SENDER_NAME_PLACEHOLDER###'	=> $this->pi_getLL('placeholder.name'),
			'###SENDER_NAME_VALUE###'		=> htmlspecialchars($this->piVars['sender_name']),
			'###SENDER_NAME_ERROR###'		=> '',
			'###SENDER_MAIL_ID###'			=> $this->prefixId . '_sender_mail',
			'###SENDER_MAIL_LABEL###'		=> $this->pi_getLL('label.mail'),
			'###SENDER_MAIL_NAME###'		=> $this->prefixId . '[sender_mail]',
			'###SENDER_MAIL_PLACEHOLDER###'	=> $this->pi_getLL('placeholder.mail'),
			'###SENDER_MAIL_VALUE###'		=> htmlspecialchars($this->piVars['sender_mail']),
			'###SENDER_MAIL_ERROR###'		=> '',
			'###MESSAGE_ID###'				=> $this->prefixId . '_message',
			'###MESSAGE_LABEL###'			=> $this->pi_getLL('label.message'),
			'###MESSAGE_NAME###'			=> $this->prefixId . '[message]',
			'###MESSAGE_PLACEHOLDER###'		=> $this->pi_getLL('placeholder.message'),
			'###MESSAGE_VALUE###'			=> htmlspecialchars($this->piVars['message']),
			'###MESSAGE_ERROR###'			=> '',
			'###SEND_NAME###'				=> $this->prefixId . '[send_message]',
			'###SEND_LABEL###'				=> $this->pi_getLL('label.send')
		);
		
		foreach ($errors as $fieldName => $errorText) {
			$validationMarkerArray = array(
				'###MESSAGE###' => $errorText
			);
			
			$markerArray['###' . strtoupper($fieldName) . '_ERROR###'] = $this->cObj->substituteMarkerArrayCached($validationMessageTemplate, $validationMarkerArray);
		}
		
		if ($class == 'error') {
			$errorMarkerArray = array(
				'###MESSAGE###' => $message
			);
			
			$markerArray['###MESSAGE###'] = $this->cObj->substituteMarkerArrayCached($errorMessageTemplate, $errorMarkerArray);
		} elseif ($class == 'success') {
			$successMarkerArray = array(
				'###MESSAGE###' => $message
			);
			
			$markerArray['###MESSAGE###'] = $this->cObj->substituteMarkerArrayCached($successMessageTemplate, $successMarkerArray);
		}
		
		$content = $this->cObj->substituteMarkerArrayCached($contactFormTemplate, $markerArray);
		
		return $this->pi_wrapInBaseClass($content);
	}
	
	function wrapMessage($message, $prefix, $suffix) {
		if(trim($message) != '') {
			return $prefix . $message . $suffix;
		}
		else {
			return '';
		}
	}
}



if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/le_contactform/pi1/class.tx_lecontactform_pi1.php'])	{
	include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/le_contactform/pi1/class.tx_lecontactform_pi1.php']);
}

?>

Noch sollte sich bei der Anzeige des Kontaktformulars nichts geändert haben, aber wenn die Sprache im Haupttemplate der Seite die Sprache auf Englisch umstellen, spricht das Kontaktformular plötzlich eine andere Sprache!

Das Kontaktformular ist ins Englische übersetzt
Siehe da, unser Plugin hat keine Schwierigkeiten mit der snglischen Sprache.

Jetzt ist es auch kein Problem, weitere Sprachen hinzuzufügen, schließlich muss man einfach nur die Locallang-Datei anpassen und das Plugin greift automatisch darauf zu.

Auf der nächsten Seite werden wir die flexible FlexForm-Konfiguration hinzufügen.

Flexible Konfiguration der Extension mit Flexforms

Als nächstes wollen wir dem Nutzer zusätzliche Plugin-Konfiguraionen anbieten. Dazu fügen wir ein FlexForm zu dem Plugin dazu. Im Speziellen soll der Nutzer die Ziel-Adresse für die Mails eingeben können.

Leg als erstes eine neue Datei flexform_ds_pi1.xml im Ordner pi1 mit folgendem Inhalt an:


<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3DataStructure>
	<sheets>
		<sContactForm>
			<ROOT>
				<TCEforms>
					<sheetTitle>LLL:EXT:le_contactform/locallang_db.xml:tt_content.list_type_pi1</sheetTitle>
				</TCEforms>
				<type>array</type>
				<el>
					<cMailTo>
						<TCEforms>
							<label>LLL:EXT:le_contactform/locallang_db.xml:mail-to</label>
							<config>
								<type>input</type>
								<size>100</size>
							</config>
						</TCEforms>
					</cMailTo>
				</el>
			</ROOT>
		</sContactForm>
	</sheets>
</T3DataStructure>

In dieser Datei definieren wir die Formularfelder, die der Nutzer später ausfüllen kann. Hier greifen wir wieder auf Sprach-Schnipsel zu, allerdings aus der Datei locallang_db.xml, hier findet sich bei mir nun folgender Inhalt:


<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<T3locallang>
	<meta type="array">
		<type>database</type>
		<description>Language labels for database tables/fields belonging to extension 'le_contactform'</description>
	</meta>
	<data type="array">
		<languageKey index="default" type="array">
			<label index="tt_content.list_type_pi1">Contact form</label>
			<label index="mail-to">Target e-mail address</label>
		</languageKey>
		<languageKey index="de" type="array">
			<label index="tt_content.list_type_pi1">Kontaktformular</label>
			<label index="mail-to">Ziel-Mailadresse</label>
		</languageKey>
	</data>
</T3locallang>

Als nächstes müssen wir Typo3 noch mitteilen, dass wir FlexForms verwenden wollen. Dazu ändern wir nun die Datei ext_tables.php. Hier müssen wir zwei Zeilen hinzufügen:


$TCA['tt_content']['types']['list']['subtypes_addlist'][$_EXTKEY.'_pi1']='pi_flexform';
t3lib_extMgm::addPiFlexFormValue($_EXTKEY.'_pi1', 'FILE:EXT:'.$_EXTKEY.'/pi1/flexform_ds_pi1.xml');

Jetzt wird dem Nutzer im Backend die Möglichkeit gegeben, die Mail-Adresse zu konfigurieren.

Dem Nutzer wird das FlexForm angezeigt
Durch das Flexform kann der Nutzer nun das Plugin konfigurieren.

Nun müssen wir nur noch im Plugin auf den konfigurierten Wert zugreifen.

Zunächst laden wir das gesamte FlexForm in eine PHP-Variable mit der Zeile:


$this->pi_initPIflexForm();

Diese fügen wir am Besten am Anfang der Methode main() ein.

Anschließend können wir einfach auf den Wert zugreifen. In der Zeile 102 unseres Plugins schreiben wir nun


@mail($this->pi_getFFvalue($this->cObj->data['pi_flexform'], "cMailTo", "sContactForm"), $subject, $this->piVars['message'], $header);

So ließt das Plugin direkt den Wert aus der Konfiguration und sendet die Mail an diese Adresse.

Fazit und Ausblick

Mit Typo3 kann man sehr flexible Plugins und Extensions schreiben, in diesem Artikel hast du nun auch noch gelernt, wie man mehrsprachige Plugins programmiert und dem Nutzer zusätzliche Konfigurations-Möglichkeiten anbietet. Mit FlexForms sind viele Dinge möglich, zum Beispiel die Auswahl eines Ansichts-Modus, wie in meiner Extension simplecalendar. Genau das wird Thema des nächsten Artikels dieser Reihe werden.

Nächster Artikel der Serie

Dieser Artikel ist Teil der Artikelserie »Typo3: Extension selbst erstellen«.

Hier geht es zum nächsten Artikel der Serie: Planung, Dokumentation und Veröffentlichung – Typo3: Extension selbst erstellen