PageRenderTime 456ms CodeModel.GetById 101ms app.highlight 231ms RepoModel.GetById 110ms app.codeStats 1ms

/ace/prestashop/admin7/tabs/AdminTranslations.php

https://github.com/sealence/local
PHP | 858 lines | 773 code | 60 blank | 25 comment | 118 complexity | 37459addb2c18472ff85903e7b4664bd MD5 | raw file
  1<?php
  2
  3/**
  4  * Translations tab for admin panel, AdminTranslations.php
  5  * @category admin
  6  *
  7  * @author PrestaShop <support@prestashop.com>
  8  * @copyright PrestaShop
  9  * @license http://www.opensource.org/licenses/osl-3.0.php Open-source licence 3.0
 10  * @version 1.2
 11  *
 12  */
 13
 14include_once(PS_ADMIN_DIR.'/../classes/AdminTab.php');
 15define ('TEXTAREA_SIZED', 70);
 16
 17class AdminTranslations extends AdminTab
 18{
 19	private function getModuleTranslations()
 20	{
 21		global $_MODULES, $_MODULE;
 22
 23		if (!isset($_MODULE) AND !isset($_MODULES))
 24			$_MODULES = array();
 25		elseif (isset($_MODULE))
 26			$_MODULES = (is_array($_MODULES) AND is_array($_MODULE)) ? array_merge($_MODULES, $_MODULE) : $_MODULE;
 27	}
 28
 29	private function checkDirAndCreate($dest)
 30	{
 31		$bool = true;
 32		$dir = trim(str_replace(_PS_ROOT_DIR_, '', dirname($dest)), '/');
 33		$subdir = explode('/', $dir);
 34		for ($i = 0, $path = ''; $subdir[$i]; $i++)
 35		{
 36			$path .= $subdir[$i].'/';
 37			if (!createDir(_PS_ROOT_DIR_.'/'.$path, 0777))
 38			{
 39				$bool &= false;
 40				$this->_errors[] = $this->l('Cannot create the folder').' "'.$path.'". '.$this->l('Check directory writing permisions.');
 41				break ;
 42			}
 43		}
 44		return $bool;
 45	}
 46
 47	private function writeTranslationFile($type, $path, $mark = false, $fullmark = false)
 48	{
 49		global $currentIndex;
 50
 51		if ($fd = fopen($path, 'w'))
 52		{
 53			unset($_POST['submitTranslations'.$type], $_POST['lang']);
 54			unset($_POST['token']);
 55			$toInsert = array();
 56			foreach($_POST as $key => $value)
 57				if (!empty($value))
 58					$toInsert[$key] = /*htmlentities(*/$value/*, ENT_COMPAT, 'UTF-8')*/;
 59
 60			$tab = ($fullmark ? Tools::strtoupper($fullmark) : 'LANG').($mark ? Tools::strtoupper($mark) : '');
 61			fwrite($fd, "<?php\n\nglobal \$_".$tab.";\n\$_".$tab." = array();\n");
 62			foreach($toInsert as $key => $value)
 63				fwrite($fd, '$_'.$tab.'[\''.pSQL($key, true).'\'] = \''.pSQL($value, true).'\';'."\n");
 64			fwrite($fd, "\n?>");
 65			fclose($fd);
 66			Tools::redirectAdmin($currentIndex.'&conf=4&token='.$this->token);
 67		}
 68		else
 69			die('Cannot write language file');
 70	}
 71
 72	public function submitCopyLang()
 73	{
 74		global $currentIndex;
 75
 76		if (!($fromLang = strval(Tools::getValue('fromLang'))) OR !($toLang = strval(Tools::getValue('toLang'))))
 77			$this->_errors[] = $this->l('you must select 2 languages in order to copy data from one to another');
 78		elseif (!($fromTheme = strval(Tools::getValue('fromTheme'))) OR !($toTheme = strval(Tools::getValue('toTheme'))))
 79			$this->_errors[] = $this->l('you must select 2 themes in order to copy data from one to another');
 80		elseif (!Language::copyLanguageData(Language::getIdByIso($fromLang), Language::getIdByIso($toLang)))
 81			$this->_errors[] = $this->l('an error occurred while copying data');
 82		elseif ($fromLang == $toLang AND $fromTheme == $toTheme)
 83			$this->_errors[] = $this->l('nothing to copy! (same language and theme)');
 84		if (sizeof($this->_errors))
 85			return ;
 86
 87		$bool = true;
 88		$items = Language::getFilesList($fromLang, $fromTheme, $toLang, $toTheme, false, false, true);
 89		foreach ($items as $source => $dest)
 90		{
 91			$bool &= $this->checkDirAndCreate($dest);
 92			$bool &= @copy($source, $dest);
 93		}
 94		if ($bool)
 95			Tools::redirectLink($currentIndex.'&conf=14&token='.$this->token);
 96		$this->_errors[] = $this->l('a part of the data has been copied but some language files could not be found or copied');
 97	}
 98
 99	public function submitExportLang()
100	{
101		global $currentIndex;
102
103		$lang = strtolower(Tools::getValue('iso_code'));
104		$theme = strval(Tools::getValue('theme'));
105		if ($lang AND $theme)
106		{
107			$items = array_flip(Language::getFilesList($lang, $theme, false, false, false, false, true));
108			$gz = new Archive_Tar(_PS_TRANSLATIONS_DIR_.'/export/'.$lang.'.gzip', true);
109			if ($gz->createModify($items, NULL, _PS_ROOT_DIR_));
110				Tools::redirect('translations/export/'.$lang.'.gzip');
111			$this->_errors[] = Tools::displayError('an error occurred while creating archive');
112		}
113		$this->_errors[] = Tools::displayError('please choose a language and a theme');
114	}
115
116	public function submitImportLang()
117	{
118		global $currentIndex;
119
120		if (!isset($_FILES['file']['tmp_name']) OR !$_FILES['file']['tmp_name'])
121			$this->_errors[] = Tools::displayError('no file selected');
122		else
123		{
124			$gz = new Archive_Tar($_FILES['file']['tmp_name'], true);
125			if ($gz->extract(_PS_TRANSLATIONS_DIR_.'../', false))
126				Tools::redirectAdmin($currentIndex.'&conf=15&token='.$this->token);
127			$this->_errors[] = Tools::displayError('archive cannot be extracted');
128		}
129	}
130
131	public function findAndWriteTranslationsIntoFile($filename, $files, $themeName, $moduleName, $dir = false)
132	{
133		static $_cacheFile = array();
134		
135		if (!isset($_cacheFile[$filename]))
136		{
137			$_cacheFile[$filename] = true;
138			if (!$fd = fopen($filename, 'w'))
139				die ($this->l('Cannot write the theme\'s language file ').'('.$filename.')'.$this->l('. Please check write permissions.'));
140			fwrite($fd, "<?php\n\nglobal \$_MODULE;\n\$_MODULE = array();\n");
141			fclose($fd);
142		}
143
144		$tplRegex = '/\{l s=\''._PS_TRANS_PATTERN_.'\'( mod=\'.+\')?( js=1)?\}/U';
145		$phpRegex = '/->l\(\''._PS_TRANS_PATTERN_.'\'(, \'(.+)\')?(, (.+))?\)/U';
146
147		if (!$dir)
148			$dir = ($themeName == 'prestashop' ? _PS_MODULE_DIR_.$moduleName.'/' : _PS_ALL_THEMES_DIR_.$themeName.'/modules/'.$moduleName.'/');
149		if (!$writeFd = fopen($filename, 'a+'))
150			die ($this->l('Cannot write the theme\'s language file ').'('.$filename.')'.$this->l('. Please check write permissions.'));
151		else
152		{
153			$_tmp = array();
154			foreach ($files AS $templateFile)
155			{
156				if ((preg_match('/^(.*).tpl$/', $templateFile) OR ($themeName == 'prestashop' AND preg_match('/^(.*).php$/', $templateFile))) AND file_exists($tpl = $dir.$templateFile))
157				{
158						/* Get translations key */
159						$readFd = fopen($tpl, 'r');
160						$content = (filesize($tpl) ? fread($readFd, filesize($tpl)) : '');
161						preg_match_all(substr($templateFile, -4) == '.tpl' ? $tplRegex : $phpRegex, $content, $matches);
162						fclose($readFd);
163
164						/* Write each translation on its module file */
165						$templateName = substr(basename($templateFile), 0, -4);
166						foreach ($matches[1] as $key)
167						{
168							$postKey = md5($moduleName.'_'.$themeName.'_'.$templateName.'_'.md5($key));
169							$pattern = '\'<{'.$moduleName.'}'.$themeName.'>'.Tools::strtolower($templateName).'_'.md5($key).'\'';
170							if (array_key_exists($postKey, $_POST) AND !empty($_POST[$postKey]) AND !array_key_exists($pattern, $_tmp))
171							{
172								$_tmp[$pattern] = true;
173								fwrite($writeFd, '$_MODULE['.$pattern.'] = \''.pSQL($_POST[$postKey]).'\';'."\n");
174							}
175						}
176				}
177			}
178			fclose($writeFd);
179		}
180	}
181
182	public function findAndFillTranslations($files, &$translationsArray, $themeName, $moduleName, $dir = false)
183	{
184		global $_MODULES;
185		$tplRegex = '/\{l s=\''._PS_TRANS_PATTERN_.'\'( mod=\'.+\')?( js=1)?\}/U';
186		$phpRegex = '/->l\(\''._PS_TRANS_PATTERN_.'\'(, \'(.+)\')?(, (.+))?\)/U';
187
188		$count = 0;
189		if (!$dir)
190			$dir = ($themeName == 'prestashop' ? _PS_MODULE_DIR_.$moduleName.'/' : _PS_ALL_THEMES_DIR_.$themeName.'/modules/'.$moduleName.'/');
191		foreach ($files AS $templateFile)
192			if ((preg_match('/^(.*).tpl$/', $templateFile) OR ($themeName == 'prestashop' AND preg_match('/^(.*).php$/', $templateFile))) AND file_exists($tpl = $dir.$templateFile))
193			{
194					/* Get translations key */
195					$readFd = fopen($tpl, 'r');
196					$content = (filesize($tpl) ? fread($readFd, filesize($tpl)) : '');
197					preg_match_all(substr($templateFile, -4) == '.tpl' ? $tplRegex : $phpRegex, $content, $matches);
198					fclose($readFd);
199	
200					/* Write each translation on its module file */
201					$templateName = substr(basename($templateFile), 0, -4);
202					foreach ($matches[1] as $key)
203					{
204						$moduleKey = '<{'.$moduleName.'}'.$themeName.'>'.Tools::strtolower($templateName).'_'.md5($key);
205						$translationsArray[$themeName][$moduleName][$templateName][$key] = key_exists($moduleKey, $_MODULES) ? html_entity_decode($_MODULES[$moduleKey], ENT_COMPAT, 'UTF-8') : '';
206					}
207					$count += isset($translationsArray[$themeName][$moduleName][$templateName]) ? sizeof($translationsArray[$themeName][$moduleName][$templateName]) : 0;
208			}
209		return ($count);
210	}
211
212	public function postProcess()
213	{
214		global $currentIndex;
215
216		if (Tools::isSubmit('submitCopyLang'))
217		{
218		 	if ($this->tabAccess['add'] === '1')
219				$this->submitCopyLang();
220			else
221				$this->_errors[] = Tools::displayError('You do not have permission to add anything here.');
222		}
223		elseif (Tools::isSubmit('submitExport'))
224		{
225			if ($this->tabAccess['add'] === '1')
226				$this->submitExportLang();
227			else
228				$this->_errors[] = Tools::displayError('You do not have permission to add anything here.');
229		}
230		elseif (Tools::isSubmit('submitImport'))
231		{
232		 	if ($this->tabAccess['add'] === '1')
233				$this->submitImportLang();
234			else
235				$this->_errors[] = Tools::displayError('You do not have permission to add anything here.');
236		}
237		elseif (Tools::isSubmit('submitTranslationsFront'))
238		{
239			if ($this->tabAccess['edit'] === '1')
240				$this->writeTranslationFile('Front', _PS_THEME_DIR_.'lang/'.Tools::strtolower(Tools::getValue('lang')).'.php');
241			else
242				$this->_errors[] = Tools::displayError('You do not have permission to edit anything here.');
243		}
244		elseif (Tools::isSubmit('submitTranslationsPDF'))
245		{
246		 	if ($this->tabAccess['edit'] === '1')
247				$this->writeTranslationFile('PDF', _PS_TRANSLATIONS_DIR_.Tools::strtolower(Tools::getValue('lang')).'/pdf.php', 'PDF');
248			else
249				$this->_errors[] = Tools::displayError('You do not have permission to edit anything here.');
250		}
251		elseif (Tools::isSubmit('submitTranslationsBack'))
252		{
253		 	if ($this->tabAccess['edit'] === '1')
254				$this->writeTranslationFile('Back', _PS_TRANSLATIONS_DIR_.Tools::strtolower(Tools::getValue('lang')).'/admin.php', 'ADM');
255			else
256				$this->_errors[] = Tools::displayError('You do not have permission to edit anything here.');
257		}
258		elseif (Tools::isSubmit('submitTranslationsErrors'))
259		{
260		 	if ($this->tabAccess['edit'] === '1')
261				$this->writeTranslationFile('Errors', _PS_TRANSLATIONS_DIR_.Tools::strtolower(Tools::getValue('lang')).'/errors.php', false, 'ERRORS');
262			else
263				$this->_errors[] = Tools::displayError('You do not have permission to edit anything here.');
264		}
265		elseif (Tools::isSubmit('submitTranslationsFields'))
266		{
267		 	if ($this->tabAccess['edit'] === '1')
268				$this->writeTranslationFile('Fields', _PS_TRANSLATIONS_DIR_.Tools::strtolower(Tools::getValue('lang')).'/fields.php', false, 'FIELDS');
269			else
270				$this->_errors[] = Tools::displayError('You do not have permission to edit anything here.');
271
272		}
273		elseif (Tools::isSubmit('submitTranslationsModules'))
274		{
275		if ($this->tabAccess['edit'] === '1')
276			{
277				$lang = Tools::strtolower($_POST['lang']);
278				if (!$modules = scandir(_PS_MODULE_DIR_))
279					$this->displayWarning(Tools::displayError('There are no modules in your copy of PrestaShop. Use the Modules tab to activate them or go to our Website to download additional Modules.'));
280				else
281				{
282					foreach ($modules AS $module)
283					if ($module{0} != '.' AND is_dir(_PS_MODULE_DIR_.$module))
284					{
285						$filename = _PS_MODULE_DIR_.$module.'/'.$lang.'.php';
286						$content = scandir(_PS_MODULE_DIR_.$module);
287						foreach ($content as $cont)
288							if ($cont{0} != '.' AND $cont != 'img' AND $cont != 'mails' AND $cont != 'js' AND is_dir(_PS_MODULE_DIR_.$module.'/'.$cont))
289								if ($files = @scandir(_PS_MODULE_DIR_.$module.'/'.$cont))
290									$this->findAndWriteTranslationsIntoFile($filename, $files, 'prestashop', $module, _PS_MODULE_DIR_.$module.'/'.$cont.'/');
291						if ($files = @scandir(_PS_MODULE_DIR_.$module.'/'))
292							$this->findAndWriteTranslationsIntoFile($filename, $files, 'prestashop', $module);
293					}
294				}
295				/* Search language tags (eg {l s='to translate'}) */
296				if ($themes = scandir(_PS_ALL_THEMES_DIR_))
297				
298					foreach ($themes AS $theme)
299						if ($theme{0} != '.' AND is_dir(_PS_ALL_THEMES_DIR_.$theme) AND file_exists(_PS_ALL_THEMES_DIR_.$theme.'/modules/'))
300						{
301							if ($modules = scandir(_PS_ALL_THEMES_DIR_.$theme.'/modules/'))
302								foreach ($modules AS $module)
303									if ($module{0} != '.' AND is_dir(_PS_ALL_THEMES_DIR_.$theme.'/modules/'.$module) AND $files = scandir(_PS_ALL_THEMES_DIR_.$theme.'/modules/'.$module.'/'))
304										$this->findAndWriteTranslationsIntoFile(_PS_ALL_THEMES_DIR_.$theme.'/modules/'.$module.'/'.$lang.'.php', $files, $theme, $module);
305						}
306				Tools::redirectAdmin($currentIndex.'&conf=4&token='.$this->token);
307			}
308			else
309				$this->_errors[] = Tools::displayError('You do not have permission to edit anything here.');
310		}
311	}
312
313	public function display()
314	{
315		global $currentIndex, $cookie;
316
317		$translations = array(
318						'front' => $this->l('Front Office translations'),
319						'back' => $this->l('Back Office translations'),
320						'errors' => $this->l('Errors messages translations'),
321						'fields' => $this->l('Fields name translations'),
322						'modules' => $this->l('Modules translations'),
323						'pdf' => $this->l('PDF translations'),
324						);
325
326		if ($type = Tools::getValue('type'))
327			$this->{'displayForm'.$type}(Tools::strtolower(Tools::getValue('lang')));
328		else
329		{
330			$languages = Language::getLanguages();
331			echo '<fieldset class="width2"><legend><img src="../img/admin/translation.gif" />'.$this->l('Modify translations').'</legend>'.
332			$this->l('Here you can modify translations for every text input on PrestaShop.').'<br />'.
333			$this->l('First, select a section (such as Back Office or Modules), then click the flag representing the language you want to edit.').'<br /><br />
334			<form method="get" action="index.php" id="typeTranslationForm">
335				<input type="hidden" name="tab" value="AdminTranslations" />
336				<input type="hidden" name="lang" id="translation_lang" value="0" />
337				<select name="type" style="float:left; margin-right:10px;">';
338			foreach ($translations as $key => $translation)
339				echo '<option value="'.$key.'">'.$translation.'&nbsp;</option>';
340			echo '</select>';
341			foreach ($languages as $language)
342				echo '<a href="javascript:chooseTypeTranslation(\''.$language['iso_code'].'\')">
343						<img src="'._THEME_LANG_DIR_.$language['id_lang'].'.jpg" alt="'.$language['iso_code'].'" title="'.$language['iso_code'].'" />
344					</a>';
345			echo '<input type="hidden" name="token" value="'.$this->token.'" /></form></fieldset>
346			<br /><br /><h2>'.$this->l('Translation exchange').'</h2>
347			<form action="'.$currentIndex.'&token='.$this->token.'" method="post" enctype="multipart/form-data">
348				<fieldset class="width2"><legend><img src="../img/admin/import.gif" />'.$this->l('Import a language pack').'</legend>
349					<p>'.$this->l('Import data from file (language pack).').'<br />'.
350					$this->l('Be careful, as it will replace all existing data for the destination language!').'<br />'.
351					$this->l('Browse your computer for the language file to be imported:').'</p>
352					<div style="float:left;">
353						<p>
354							<div style="width:75px; font-weight:bold; float:left;">'.$this->l('From:').'</div>
355							<input type="file" name="file" />
356						</p>
357					</div>
358					<div style="float:left;">
359						<input type="submit" value="'.$this->l('Import').'" name="submitImport" class="button" style="margin:10px 0px 0px 25px;" />
360					</div>
361				</fieldset>
362			</form>
363			<br /><br />
364			<form action="'.$currentIndex.'&token='.$this->token.'" method="post" enctype="multipart/form-data">
365				<fieldset class="width2"><legend><img src="../img/admin/export.gif" />'.$this->l('Export a language').'</legend>
366					<p>'.$this->l('Export data from one language to a file (language pack).').'<br />'.
367					$this->l('Choose the theme from which you want to export translations.').'<br />
368					<select name="iso_code" style="margin-top:10px;">';
369				foreach ($languages as $language)
370					echo '<option value="'.$language['iso_code'].'">'.$language['name'].'</option>';
371				echo '
372					</select>
373					&nbsp;&nbsp;&nbsp;
374					<select name="theme" style="margin-top:10px;">';
375				$themes = self::getThemesList();
376				foreach ($themes as $theme)
377					echo '<option value="'.$theme['name'].'">'.$theme['name'].'</option>';
378				echo '
379					</select>&nbsp;&nbsp;
380					<input type="submit" class="button" name="submitExport" value="'.$this->l('Export').'" />
381				</fieldset>
382			</form>
383			<br /><br />';
384			$allLanguages = Language::getLanguages(false);
385			echo '
386			<form action="'.$currentIndex.'&token='.$this->token.'" method="post">
387				<fieldset class="width2"><legend><img src="../img/admin/copy_files.gif" />'.$this->l('Copy').'</legend>
388					<p>'.$this->l('Copies data from one language to another.').'<br />'.
389					$this->l('Be careful, as it will replace all existing data for the destination language!').'<br />'.
390					$this->l('If necessary').', <b><a href="index.php?tab=AdminLanguages&addlang&token='.Tools::getAdminToken('AdminLanguages'.intval(Tab::getIdFromClassName('AdminLanguages')).intval($cookie->id_employee)).'">'.$this->l('first create a new language').'</a></b>.</p>
391					<div style="float:left;">
392						<p>
393							<div style="width:75px; font-weight:bold; float:left;">'.$this->l('From:').'</div>
394							<select name="fromLang">';
395					foreach	($languages AS $language)
396						echo '<option value="'.$language['iso_code'].'">'.$language['name'].'</option>';
397					echo '
398							</select>
399							&nbsp;&nbsp;&nbsp;
400							<select name="fromTheme">';
401						$themes = self::getThemesList();
402						foreach ($themes as $theme)
403							echo '<option value="'.$theme['name'].'">'.$theme['name'].'</option>';
404						echo '
405							</select> <span style="font-style: bold; color: red;">*</span>
406						</p>
407						<p>
408							<div style="width:75px; font-weight:bold; float:left;">'.$this->l('To:').'</div>
409							<select name="toLang">';
410					foreach	($allLanguages AS $language)
411						echo '<option value="'.$language['iso_code'].'">'.$language['name'].'</option>';
412					echo '
413							</select>
414							&nbsp;&nbsp;&nbsp;
415							<select name="toTheme">';
416						$themes = self::getThemesList();
417						foreach ($themes as $theme)
418							echo '<option value="'.$theme['name'].'">'.$theme['name'].'</option>';
419						echo '
420							</select>
421						</p>
422					</div>
423					<div style="float:left;">
424						<input type="submit" value="'.$this->l('   Copy   ').'" name="submitCopyLang" class="button" style="margin:25px 0px 0px 25px;" />
425					</div>
426					<p style="clear: left; padding: 16px 0px 0px 0px;"><span style="font-style: bold; color: red;">*</span> '.$this->l('Language files (as indicated at Tools >> Languages >> Edition) must be complete to allow copying of translations').'</p>
427				</fieldset>
428			</form>';
429		}
430	}
431
432	function fileExists($dir, $file, $var)
433	{
434		${$var} = array();
435		if (!file_exists($dir))
436			if (!mkdir($dir, 0700))
437				die('Please create the directory '.$dir);
438		if (!file_exists($dir.'/'.$file))
439			if (!file_put_contents($dir.'/'.$file, "<?php\n\nglobal \$".$var.";\n\$".$var." = array();\n\n?>"))
440				die('Please create a "'.$file.'" file in '.$dir);
441		if (!is_writable($dir.'/'.$file))
442			$this->displayWarning(Tools::displayError('This file has to be writable:').' '.$dir.'/'.$file);
443		include($dir.'/'.$file);
444		return ${$var};
445	}
446
447	function displayToggleButton()
448	{
449		echo '
450		<script type="text/javascript">
451			var openAll = \''.html_entity_decode($this->l('Expand all fieldsets'), ENT_NOQUOTES, 'UTF-8').'\';
452			var closeAll = \''.html_entity_decode($this->l('Close all fieldsets'), ENT_NOQUOTES, 'UTF-8').'\';
453		</script>
454		<input type="button" class="button" id="buttonall" onclick="openCloseAllDiv(\''.$_GET['type'].'_div\', this.value == openAll); toggleElemValue(this.id, openAll, closeAll);" />
455		<script type="text/javascript">toggleElemValue(\'buttonall\', openAll, closeAll);</script>';
456	}
457
458	function displayFormfront($lang)
459	{
460		global $currentIndex;
461		$_LANG = $this->fileExists(_PS_THEME_DIR_.'lang', Tools::strtolower($lang).'.php', '_LANG');
462
463		/* List templates to parse */
464		$templates = scandir(_PS_THEME_DIR_);
465		$count = 0;
466		$files = array();
467		foreach ($templates AS $template)
468			if (preg_match('/^(.*).tpl$/', $template) AND file_exists($tpl = _PS_THEME_DIR_.$template))
469			{
470				$template = substr(basename($template), 0, -4);
471				$newLang = array();
472				$fd = fopen($tpl, 'r');
473				$content = fread($fd, filesize($tpl));
474
475				/* Search language tags (eg {l s='to translate'}) */
476				$regex = '/\{l s=\''._PS_TRANS_PATTERN_.'\'( js=1)?\}/U';
477				preg_match_all($regex, $content, $matches);
478
479				/* Get string translation */
480				foreach($matches[1] as $key)
481				{
482					$key2 = $template.'_'.md5($key);
483					$newLang[$key] = (key_exists($key2, $_LANG)) ? html_entity_decode($_LANG[$key2], ENT_COMPAT, 'UTF-8') : '';
484				}
485				$files[$template] = $newLang;
486				$count += sizeof($newLang);
487			}
488
489		echo '
490		<h2>'.$this->l('Language').' : '.Tools::strtoupper($lang).'</h2>
491		'.$this->l('Total expressions').' : <b>'.$count.'</b>. '.$this->l('Click the fieldset title to expand or close the fieldset.').'.<br /><br />
492		<form method="post" action="'.$currentIndex.'&submitTranslationsFront=1&token='.$this->token.'" class="form">';
493		$this->displayToggleButton();
494		echo '<input type="hidden" name="lang" value="'.$lang.'" /><input type="submit" name="submitTranslationsFront" value="'.$this->l('Update translations').'" class="button" /><br /><br />';
495		foreach ($files as $k => $newLang)
496			if (sizeof($newLang))
497			{
498				$countValues = array_count_values($newLang);
499				$empty = isset($countValues['']) ? $countValues[''] : 0;
500			 	echo '
501				<fieldset><legend style="cursor : pointer" onclick="openCloseLayer(\''.$k.'\')">'.$k.' - <font color="blue">'.sizeof($newLang).'</font> '.$this->l('expressions').' (<font color="red">'.$empty.'</font>)</legend>
502					<div name="front_div" id="'.$k.'" style="display: '.($empty ? 'block' : 'none').';">
503						<table cellpadding="2">';
504				foreach ($newLang as $key => $value)
505				{
506					echo '<tr><td style="width: 40%">'.stripslashes($key).'</td><td>= ';
507					if (strlen($key) < TEXTAREA_SIZED)
508						echo '<input type="text" style="width: 450px" name="'.$k.'_'.md5($key).'" value="'.stripslashes(preg_replace('/"/', '\&quot;', stripslashes($value))).'" /></td></tr>';
509					else
510						echo '<textarea rows="'.intval(strlen($key) / TEXTAREA_SIZED).'" style="width: 450px" name="'.$k.'_'.md5($key).'">'.stripslashes(preg_replace('/"/', '\&quot;', stripslashes($value))).'</textarea></td></tr>';
511				}
512				echo '
513						</table>
514					</div>
515				</fieldset><br />';
516			}
517		echo '<br /><input type="submit" name="submitTranslationsFront" value="'.$this->l('Update translations').'" class="button" /></form>';
518	}
519
520	function displayFormback($lang)
521	{
522		global $currentIndex;
523		$_LANGADM = $this->fileExists(_PS_TRANSLATIONS_DIR_.$lang, 'admin.php', '_LANGADM');
524
525		/* List templates to parse */
526		$count = 0;
527		$tabs = scandir(PS_ADMIN_DIR.'/tabs');
528		$tabs[] = '../../classes/AdminTab.php';
529		$files = array();
530		foreach ($tabs AS $tab)
531			if (preg_match('/^(.*)\.php$/', $tab) AND file_exists($tpl = PS_ADMIN_DIR.'/tabs/'.$tab))
532			{
533				$tab = basename(substr($tab, 0, -4));
534				$fd = fopen($tpl, 'r');
535				$content = fread($fd, filesize($tpl));
536				fclose($fd);
537				$regex = '/this->l\(\''._PS_TRANS_PATTERN_.'\'[\)|\,]/U';
538				preg_match_all($regex, $content, $matches);
539				foreach ($matches[1] as $key)
540					$tabsArray[$tab][$key] = stripslashes(key_exists($tab.md5($key), $_LANGADM) ? html_entity_decode($_LANGADM[$tab.md5($key)], ENT_COMPAT, 'UTF-8') : '');
541				$count += isset($tabsArray[$tab]) ? sizeof($tabsArray[$tab]) : 0;
542			}
543		foreach (array('header.inc', 'index', 'login', 'password') as $tab)
544		{
545			$tab = PS_ADMIN_DIR.'/'.$tab.'.php';
546			$fd = fopen($tab, 'r');
547			$content = fread($fd, filesize($tab));
548			fclose($fd);
549			$regex = '/translate\(\''._PS_TRANS_PATTERN_.'\'\)/U';
550			preg_match_all($regex, $content, $matches);
551			foreach ($matches[1] as $key)
552				$tabsArray['index'][$key] = stripslashes(key_exists('index'.md5($key), $_LANGADM) ? html_entity_decode($_LANGADM['index'.md5($key)], ENT_COMPAT, 'UTF-8') : '');
553			$count += isset($tabsArray['index']) ? sizeof($tabsArray['index']) : 0;
554		}
555
556		echo '
557		<h2>'.$this->l('Language').' : '.Tools::strtoupper($lang).'</h2>
558		'.$this->l('Expressions to translate').' : <b>'.$count.'</b>. '.$this->l('Click on the titles to open fieldsets').'.<br /><br />
559		<form method="post" action="'.$currentIndex.'&submitTranslationsBack=1&token='.$this->token.'" class="form">';
560		$this->displayToggleButton();
561		echo '<input type="hidden" name="lang" value="'.$lang.'" /><input type="submit" name="submitTranslationsBack" value="'.$this->l('Update translations').'" class="button" /><br /><br />';
562		foreach ($tabsArray as $k => $newLang)
563			if (sizeof($newLang))
564			{
565				$countValues = array_count_values($newLang);
566				$empty = isset($countValues['']) ? $countValues[''] : 0;
567			 	echo '
568				<fieldset><legend style="cursor : pointer" onclick="openCloseLayer(\''.$k.'\')">'.$k.' - <font color="blue">'.sizeof($newLang).'</font> '.$this->l('expressions').' (<font color="red">'.$empty.'</font>)</legend>
569					<div name="back_div" id="'.$k.'" style="display: '.($empty ? 'block' : 'none').';">
570						<table cellpadding="2">';
571				foreach ($newLang as $key => $value)
572				{
573					echo '<tr><td style="width: 40%">'.stripslashes($key).'</td><td>= ';
574					if (strlen($key) < TEXTAREA_SIZED)
575						echo '<input type="text" style="width: 450px" name="'.$k.md5($key).'" value="'.stripslashes(preg_replace('/"/', '\&quot;', $value)).'" /></td></tr>';
576					else
577						echo '<textarea rows="'.intval(strlen($key) / TEXTAREA_SIZED).'" style="width: 450px" name="'.$k.md5($key).'">'.stripslashes(preg_replace('/"/', '\&quot;', $value)).'</textarea></td></tr>';
578				}
579				echo '
580						</table>
581					</div>
582				</fieldset><br />';
583			}
584		echo '<br /><input type="submit" name="submitTranslationsBack" value="'.$this->l('Update translations').'" class="button" /></form>';
585	}
586
587	function displayFormerrors($lang)
588	{
589		global $currentIndex;
590		$_ERRORS = $this->fileExists(_PS_TRANSLATIONS_DIR_.$lang, 'errors.php', '_ERRORS');
591
592		/* List files to parse */
593		$stringToTranslate = array();
594		$dirToParse = array(PS_ADMIN_DIR.'/../',
595							PS_ADMIN_DIR.'/../classes/',
596							PS_ADMIN_DIR.'/',
597							PS_ADMIN_DIR.'/tabs/');
598		if (!file_exists(_PS_MODULE_DIR_))
599				die($this->displayWarning(Tools::displayError('Fatal error: Module directory is not here anymore ').'('._PS_MODULE_DIR_.')'));
600			if (!is_writable(_PS_MODULE_DIR_))
601				$this->displayWarning(Tools::displayError('The module directory must be writable'));
602			if (!$modules = scandir(_PS_MODULE_DIR_))
603				$this->displayWarning(Tools::displayError('There are no modules in your copy of PrestaShop. Use the Modules tab to activate them or go to our Website to download additional Modules.'));
604			else
605			{
606				$count = 0;
607
608				foreach ($modules AS $module)
609					if (is_dir(_PS_MODULE_DIR_.$module) && $module != '.' && $module != '..' && $module != '.svn' )
610						$dirToParse[] = _PS_MODULE_DIR_.$module.'/';
611			}
612		foreach ($dirToParse AS $dir)
613			foreach (scandir($dir) AS $file)
614				if (preg_match('/.php$/', $file) AND file_exists($fn = $dir.$file) AND $file != 'index.php')
615				{
616					preg_match_all('/Tools::displayError\(\''._PS_TRANS_PATTERN_.'\'(, true)?\)/U', fread(fopen($fn, 'r'), filesize($fn)), $matches);
617					foreach($matches[1] as $key)
618						$stringToTranslate[$key] = (key_exists(md5($key), $_ERRORS)) ? html_entity_decode($_ERRORS[md5($key)], ENT_COMPAT, 'UTF-8') : '';
619				}
620		$irow = 0;
621		echo '<h2>'.$this->l('Language').' : '.Tools::strtoupper($lang).'</h2>'.$this->l('Errors to translate').' : <b>'.sizeof($stringToTranslate).'</b><br /><br />
622		<form method="post" action="'.$currentIndex.'&submitTranslationsErrors=1&lang='.$lang.'&token='.$this->token.'" class="form">
623		<input type="submit" name="submitTranslationsErrors" value="'.$this->l('Update translations').'" class="button" /><br /><br />
624		<table cellpadding="0" cellspacing="0" class="table">';
625		ksort($stringToTranslate);
626		foreach ($stringToTranslate as $key => $value)
627			echo '<tr '.(empty($value) ? 'style="background-color:#FBB"' : (++$irow % 2 ? 'class="alt_row"' : '')).'><td>'.stripslashes($key).'</td><td style="width: 430px">= <input type="text" name="'.md5($key).'" value="'.preg_replace('/"/', '&quot;', stripslashes($value)).'" style="width: 400px"></td></tr>';
628		echo '</table><br /><input type="submit" name="submitTranslationsErrors" value="'.$this->l('Update translations').'" class="button" /></form>';
629	}
630
631	function displayFormfields($lang)
632	{
633		global $currentIndex;
634		$_FIELDS = $this->fileExists(_PS_TRANSLATIONS_DIR_.$lang, 'fields.php', '_FIELDS');
635
636		$classArray = array();
637		$count = 0;
638		foreach (scandir(_PS_CLASS_DIR_) AS $classFile)
639		{
640			if (!preg_match('/\.php$/', $classFile) OR $classFile == 'index.php')
641				continue;
642			include_once(_PS_CLASS_DIR_.$classFile);
643			$className = substr($classFile, 0, -4);
644			if (!class_exists($className))
645				continue;
646			if (!is_subclass_of($className, 'ObjectModel'))
647				continue;
648			$classArray[$className] = call_user_func(array($className, 'getValidationRules'), $className);
649			if (isset($classArray[$className]['validate']))
650				$count += sizeof($classArray[$className]['validate']);
651			if (isset($classArray[$className]['validateLang']))
652				$count += sizeof($classArray[$className]['validateLang']);
653		}
654
655
656		echo '
657		<h2>'.$this->l('Language').' : '.Tools::strtoupper($lang).'</h2>
658		'.$this->l('Fields to translate').' : <b>'.$count.'</b>. '.$this->l('Click on the titles to open fieldsets').'.<br /><br />
659		<form method="post" action="'.$currentIndex.'&submitTranslationsFields=1&token='.$this->token.'" class="form">';
660		$this->displayToggleButton();
661		echo '<input type="hidden" name="lang" value="'.$lang.'" /><input type="submit" name="submitTranslationsFields" value="'.$this->l('Update translations').'" class="button" /><br /><br />';
662		foreach ($classArray AS $className => $rules)
663		{
664			$translated = 0;
665			$toTranslate = 0;
666			if (isset($rules['validate']))
667				foreach ($rules['validate'] AS $key => $value)
668					(array_key_exists($className.'_'.md5($key), $_FIELDS)) ? ++$translated : ++$toTranslate;
669			if (isset($rules['validateLang']))
670				foreach ($rules['validateLang'] AS $key => $value)
671					(array_key_exists($className.'_'.md5($key), $_FIELDS)) ? ++$translated : ++$toTranslate;
672			echo '
673			<fieldset class="width3"><legend style="cursor : pointer" onclick="openCloseLayer(\''.$className.'\')">'.$className.' - <font color="blue">'.($toTranslate + $translated).'</font> '.$this->l('fields').' (<font color="red">'.$toTranslate.'</font>)</legend>
674			<div name="fields_div" id="'.$className.'" style="display: '.($toTranslate ? 'block' : 'none').';">
675				<table cellpadding="2">';
676			if (isset($rules['validate']))
677				foreach ($rules['validate'] AS $key => $value)
678					echo '<tr><td>'.stripslashes($key).'</td><td style="width: 380px">= <input type="text" name="'.$className.'_'.md5(addslashes($key)).'" value="'.(array_key_exists($className.'_'.md5(addslashes($key)), $_FIELDS) ? html_entity_decode($_FIELDS[$className.'_'.md5(addslashes($key))], ENT_NOQUOTES, 'UTF-8') : '').'" style="width: 350px"></td></tr>';
679			if (isset($rules['validateLang']))
680				foreach ($rules['validateLang'] AS $key => $value)
681					echo '<tr><td>'.stripslashes($key).'</td><td style="width: 380px">= <input type="text" name="'.$className.'_'.md5(addslashes($key)).'" value="'.(array_key_exists($className.'_'.md5(addslashes($key)), $_FIELDS) ? html_entity_decode($_FIELDS[$className.'_'.md5(addslashes($key))], ENT_COMPAT, 'UTF-8') : '').'" style="width: 350px"></td></tr>';
682			echo '
683				</table>
684			</div>
685			</fieldset><br />';
686		}
687		echo '<br /><input type="submit" name="submitTranslationsFields" value="'.$this->l('Update translations').'" class="button" /></form>';
688	}
689
690	function displayFormModules($lang)
691	{
692		global $currentIndex, $_MODULES;
693
694		if (!file_exists(_PS_MODULE_DIR_))
695			die($this->displayWarning(Tools::displayError('Fatal error: Module directory is not here anymore ').'('._PS_MODULE_DIR_.')'));
696		if (!is_writable(_PS_MODULE_DIR_))
697			$this->displayWarning(Tools::displayError('The module directory must be writable'));
698		if (!$modules = scandir(_PS_MODULE_DIR_))
699			$this->displayWarning(Tools::displayError('There are no modules in your copy of PrestaShop. Use the Modules tab to activate them or go to our Website to download additional Modules.'));
700		else
701		{
702			$allfiles = array();
703			$count = 0;
704
705			foreach ($modules AS $module)
706				if ($module{0} != '.' AND is_dir(_PS_MODULE_DIR_.$module))
707				{
708					@include_once(_PS_MODULE_DIR_.$module.'/'.$lang.'.php');
709					self::getModuleTranslations();
710					
711					$content = scandir(_PS_MODULE_DIR_.$module);
712					foreach ($content as $cont)
713						if ($cont{0} != '.' AND $cont != 'img' AND $cont != 'mails' AND $cont != 'js' AND is_dir(_PS_MODULE_DIR_.$module.'/'.$cont))
714							if ($files = @scandir(_PS_MODULE_DIR_.$module.'/'.$cont))
715								$count += $this->findAndFillTranslations($files, $allfiles, 'prestashop', $module, 	_PS_MODULE_DIR_.$module.'/'.$cont.'/');
716
717					if ($files = @scandir(_PS_MODULE_DIR_.$module.'/'))
718						$count += $this->findAndFillTranslations($files, $allfiles, 'prestashop', $module);
719				}
720
721			if ($themes = scandir(_PS_ALL_THEMES_DIR_))
722				foreach ($themes AS $theme)
723					if ($theme{0} != '.' AND is_dir(_PS_ALL_THEMES_DIR_.$theme) AND file_exists(_PS_ALL_THEMES_DIR_.$theme.'/modules/'))
724						{
725							$modules = scandir(_PS_ALL_THEMES_DIR_.$theme.'/modules/');
726							if ($modules)
727								foreach ($modules AS $module)
728									if ($module{0} != '.' AND is_dir(_PS_ALL_THEMES_DIR_.$theme.'/modules/'.$module))
729									{
730										@include_once(_PS_ALL_THEMES_DIR_.$theme.'/modules/'.$module.'/'.$lang.'.php');
731										self::getModuleTranslations();
732
733										$files = scandir(_PS_ALL_THEMES_DIR_.$theme.'/modules/'.$module.'/');
734										if ($files)
735											$count += $this->findAndFillTranslations($files, $allfiles, $theme, $module);
736									}
737						}
738
739			echo '
740			<h2>'.$this->l('Language').' : '.Tools::strtoupper($lang).'</h2>
741			'.$this->l('Total expressions').' : <b>'.$count.'</b>. '.$this->l('Click the fieldset title to expand or close the fieldset.').'.<br /><br />
742			<form method="post" action="'.$currentIndex.'&submitTranslationsModules=1&token='.$this->token.'" class="form">';
743			$this->displayToggleButton();
744			echo '<input type="hidden" name="lang" value="'.$lang.'" /><input type="submit" name="submitTranslationsModules" value="'.$this->l('Update translations').'" class="button" /><br /><br />';
745			foreach ($allfiles AS $theme_name => $theme)
746				foreach ($theme AS $module_name => $module)
747					foreach ($module AS $template_name => $newLang)
748						if (sizeof($newLang))
749						{
750							$countValues = array_count_values($newLang);
751							$empty = isset($countValues['']) ? $countValues[''] : 0;
752							echo '
753							<fieldset><legend style="cursor : pointer" onclick="openCloseLayer(\''.$theme_name.'_'.$module_name.'_'.$template_name.'\')">'.$theme_name.' - '.$template_name.' - <font color="blue">'.sizeof($newLang).'</font> '.$this->l('expressions').' (<font color="red">'.$empty.'</font>)</legend>
754								<div name="modules_div" id="'.$theme_name.'_'.$module_name.'_'.$template_name.'" style="display: '.($empty ? 'block' : 'none').';">
755									<table cellpadding="2">';
756							foreach ($newLang as $key => $value)
757							{
758								echo '<tr><td style="width: 40%">'.stripslashes($key).'</td><td>= ';
759								if (strlen($key) < TEXTAREA_SIZED)
760									echo '<input type="text" style="width: 450px" name="'.md5($module_name.'_'.$theme_name.'_'.$template_name.'_'.md5($key)).'" value="'.stripslashes(preg_replace('/"/', '\&quot;', stripslashes($value))).'" /></td></tr>';
761								else
762									echo '<textarea rows="'.intval(strlen($key) / TEXTAREA_SIZED).'" style="width: 450px" name="'.md5($module_name.'_'.$theme_name.'_'.$template_name.'_'.md5($key)).'">'.stripslashes(preg_replace('/"/', '\&quot;', stripslashes($value))).'</textarea></td></tr>';
763							}
764							echo '
765									</table>
766								</div>
767							</fieldset><br />';
768						}
769			echo '<br /><input type="submit" name="submitTranslationsModules" value="'.$this->l('Update translations').'" class="button" /></form>';
770
771		}
772	}
773
774	function displayFormPDF()
775	{
776		global $currentIndex;
777
778		$lang = Tools::strtolower(Tools::getValue('lang'));
779		$_LANG = array();
780		if (!file_exists(_PS_TRANSLATIONS_DIR_.$lang))
781			if (!mkdir(_PS_TRANSLATIONS_DIR_.$lang, 0700))
782				die('Please create a "'.$iso.'" directory in '._PS_TRANSLATIONS_DIR_);
783		if (!file_exists(_PS_TRANSLATIONS_DIR_.$lang.'/pdf.php'))
784			if (!file_put_contents(_PS_TRANSLATIONS_DIR_.$lang.'/pdf.php', "<?php\n\nglobal \$_LANGPDF;\n\$_LANGPDF = array();\n\n?>"))
785				die('Please create a "'.Tools::strtolower($lang).'.php" file in '.realpath(PS_ADMIN_DIR.'/'));
786		unset($_LANGPDF);
787		@include(_PS_TRANSLATIONS_DIR_.$lang.'/pdf.php');
788		$files = array();
789		$count = 0;
790		$tab = 'PDF_invoice';
791		$pdf = _PS_CLASS_DIR_.'PDF.php';
792		$newLang = array();
793		$fd = fopen($pdf, 'r');
794		$content = fread($fd, filesize($pdf));
795		fclose($fd);
796		$regex = '/self::l\(\''._PS_TRANS_PATTERN_.'\'[\)|\,]/U';
797		preg_match_all($regex, $content, $matches);
798		foreach($matches[1] as $key)
799			$tabsArray[$tab][$key] = stripslashes(key_exists($tab.md5(addslashes($key)), $_LANGPDF) ? html_entity_decode($_LANGPDF[$tab.md5(addslashes($key))], ENT_COMPAT, 'UTF-8') : '');
800		$count += isset($tabsArray[$tab]) ? sizeof($tabsArray[$tab]) : 0;
801
802		echo '
803		<h2>'.$this->l('Language').' : '.Tools::strtoupper($lang).'</h2>
804		'.$this->l('Expressions to translate').' : <b>'.$count.'</b>. '.$this->l('Click on the titles to open fieldsets').'.<br /><br />
805		<form method="post" action="'.$currentIndex.'&submitTranslationsPDF=1&token='.$this->token.'" class="form">
806				<script type="text/javascript">
807					var openAll = \''.html_entity_decode($this->l('Expand all fieldsets'), ENT_NOQUOTES, 'UTF-8').'\';
808					var closeAll = \''.html_entity_decode($this->l('Close all fieldsets'), ENT_NOQUOTES, 'UTF-8').'\';
809				</script>
810				<input type="hidden" name="lang" value="'.$lang.'" />
811				<input type="button" class="button" id="buttonall" onclick="openCloseAllDiv(\'pdf_div\', this.value == openAll); toggleElemValue(this.id, openAll, closeAll);" />
812				<script type="text/javascript">
813					toggleElemValue(\'buttonall\', openAll, closeAll);
814				</script>';
815		echo '<input type="submit" name="submitTranslationsPDF" value="'.$this->l('Update translations').'" class="button" /><br /><br />';
816		foreach ($tabsArray as $k => $newLang)
817			if (sizeof($newLang))
818			{
819				$countValues = array_count_values($newLang);
820				$empty = isset($countValues['']) ? $countValues[''] : 0;
821			 	echo '
822				<fieldset style="width: 700px"><legend style="cursor : pointer" onclick="openCloseLayer(\''.$k.'\')">'.$k.' - <font color="blue">'.sizeof($newLang).'</font> '.$this->l('expressions').' (<font color="red">'.$empty.'</font>)</legend>
823					<div name="pdf_div" id="'.$k.'" style="display: '.($empty ? 'block' : 'none').';">
824						<table cellpadding="2">';
825				foreach ($newLang as $key => $value)
826				{
827					echo '
828					<tr>
829						<td>'.stripslashes($key).'</td>
830						<td style="width: 280px">
831							= <input type="text" name="'.$k.md5($key).'" value="'.stripslashes(preg_replace('/"/', '\&quot;', $value)).'" style="width: 250px">
832						</td>
833					</tr>';
834				}
835				echo '
836						</table>
837					</div>
838				</fieldset><br />';
839			}
840		echo '<br /><input type="submit" name="submitTranslationsPDF" value="'.$this->l('Update translations').'" class="button" /></form>';
841	}
842
843	/**
844	  * Return an array with themes and thumbnails
845	  *
846	  * @return array
847	  */
848	static public function getThemesList()
849	{
850		$dir = opendir(_PS_ALL_THEMES_DIR_);
851		while ($folder = readdir($dir))
852			if ($folder != '.' AND $folder != '..' AND file_exists(_PS_ALL_THEMES_DIR_.'/'.$folder.'/preview.jpg'))
853				$themes[$folder]['name'] = $folder;
854		closedir($dir);
855		return isset($themes) ? $themes : array();
856	}
857}
858?>