PageRenderTime 32ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/admin800/tabs/AdminTranslations.php

http://marocmall.googlecode.com/
PHP | 1541 lines | 1273 code | 89 blank | 179 comment | 174 complexity | 276015c77d879acfd175bd5621a7e58f MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /*
  3. * 2007-2011 PrestaShop
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@prestashop.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
  18. * versions in the future. If you wish to customize PrestaShop for your
  19. * needs please refer to http://www.prestashop.com for more information.
  20. *
  21. * @author PrestaShop SA <contact@prestashop.com>
  22. * @copyright 2007-2011 PrestaShop SA
  23. * @version Release: $Revision: 7082 $
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. * International Registered Trademark & Property of PrestaShop SA
  26. */
  27. include_once(PS_ADMIN_DIR.'/../classes/AdminTab.php');
  28. include_once(PS_ADMIN_DIR.'/../tools/tar/Archive_Tar.php');
  29. include_once(PS_ADMIN_DIR.'/../tools/pear/PEAR.php');
  30. define ('TEXTAREA_SIZED', 70);
  31. class AdminTranslations extends AdminTab
  32. {
  33. protected $total_expression = 0;
  34. protected $all_iso_lang = array();
  35. protected $modules_translations = array();
  36. const DEFAULT_THEME_NAME = 'default';
  37. protected static $tpl_regexp = '';
  38. protected static $php_regexp = '';
  39. /**
  40. * Is true if number of var exceed the suhosin request or post limit
  41. *
  42. * @var boolean
  43. */
  44. protected $suhosin_limit_exceed = false;
  45. public function __construct()
  46. {
  47. parent::__construct();
  48. self::$tpl_regexp = '/\{l s=\''._PS_TRANS_PATTERN_.'\'( mod=\'.+\')?( js=1)?\}/U';
  49. self::$php_regexp = '/->l\(\''._PS_TRANS_PATTERN_.'\'(, \'(.+)\')?(, (.+))?\)/U';
  50. }
  51. /**
  52. * This method merge each arrays of modules translation in
  53. * the array of modules translations
  54. *
  55. * @param boolean $is_default if true a prefix is set before each keys in global $_MODULES array
  56. */
  57. protected function getModuleTranslations($is_default = false)
  58. {
  59. global $_MODULES, $_MODULE;
  60. if (!isset($_MODULE) AND !isset($_MODULES))
  61. $_MODULES = array();
  62. elseif (isset($_MODULE))
  63. {
  64. if(is_array($_MODULE) AND $is_default === true)
  65. {
  66. $_NEW_MODULE = array();
  67. foreach($_MODULE as $key=>$value)
  68. {
  69. $_NEW_MODULE[self::DEFAULT_THEME_NAME.$key] = $value;
  70. }
  71. $_MODULE = $_NEW_MODULE;
  72. }
  73. $_MODULES = (is_array($_MODULES) AND is_array($_MODULE)) ? array_merge($_MODULES, $_MODULE) : $_MODULE;
  74. }
  75. }
  76. /**
  77. * This method is only used by AdminTranslations::submitCopyLang().
  78. *
  79. * It try to create folder in new theme.
  80. *
  81. * When a translation file is copied for a module, its translation key is wrong.
  82. * We have to change the translation key and rewrite the file.
  83. *
  84. * @param string $dest file name
  85. * @return bool
  86. */
  87. protected function checkDirAndCreate($dest)
  88. {
  89. $bool = true;
  90. // To get only folder path
  91. $path = dirname($dest);
  92. // If folder wasn't already added
  93. if (!file_exists($path))
  94. {
  95. if(!mkdir($path, 0777, true))
  96. {
  97. $bool &= false;
  98. $this->_errors[] = $this->l('Cannot create the folder').' "'.$path.'". '.$this->l('Check directory writing permissions.');
  99. }
  100. }
  101. return $bool;
  102. }
  103. protected function writeTranslationFile($type, $path, $mark = false, $fullmark = false)
  104. {
  105. global $currentIndex;
  106. if ($fd = fopen($path, 'w'))
  107. {
  108. unset($_POST['submitTranslations'.$type], $_POST['lang']);
  109. unset($_POST['token']);
  110. $toInsert = array();
  111. foreach($_POST AS $key => $value)
  112. if (!empty($value))
  113. $toInsert[$key] = $value;
  114. $tab = ($fullmark ? Tools::strtoupper($fullmark) : 'LANG').($mark ? Tools::strtoupper($mark) : '');
  115. fwrite($fd, "<?php\n\nglobal \$_".$tab.";\n\$_".$tab." = array();\n");
  116. foreach($toInsert AS $key => $value)
  117. fwrite($fd, '$_'.$tab.'[\''.pSQL($key, true).'\'] = \''.pSQL($value, true).'\';'."\n");
  118. fwrite($fd, "\n?>");
  119. fclose($fd);
  120. Tools::redirectAdmin($currentIndex.'&conf=4&token='.$this->token);
  121. }
  122. else
  123. die('Cannot write language file');
  124. }
  125. public function submitCopyLang()
  126. {
  127. global $currentIndex;
  128. if (!($fromLang = strval(Tools::getValue('fromLang'))) OR !($toLang = strval(Tools::getValue('toLang'))))
  129. $this->_errors[] = $this->l('you must select 2 languages in order to copy data from one to another');
  130. elseif (!($fromTheme = strval(Tools::getValue('fromTheme'))) OR !($toTheme = strval(Tools::getValue('toTheme'))))
  131. $this->_errors[] = $this->l('you must select 2 themes in order to copy data from one to another');
  132. elseif (!Language::copyLanguageData(Language::getIdByIso($fromLang), Language::getIdByIso($toLang)))
  133. $this->_errors[] = $this->l('an error occurred while copying data');
  134. elseif ($fromLang == $toLang AND $fromTheme == $toTheme)
  135. $this->_errors[] = $this->l('nothing to copy! (same language and theme)');
  136. if (sizeof($this->_errors))
  137. return ;
  138. $bool = true;
  139. $items = Language::getFilesList($fromLang, $fromTheme, $toLang, $toTheme, false, false, true);
  140. foreach ($items AS $source => $dest)
  141. {
  142. $bool &= $this->checkDirAndCreate($dest);
  143. $bool &= @copy($source, $dest);
  144. if (strpos($dest, 'modules') AND basename($source) === $fromLang.'.php' AND $bool !== false)
  145. {
  146. $bool &= $this->changeModulesKeyTranslation($dest, $fromTheme, $toTheme);
  147. }
  148. }
  149. if ($bool)
  150. Tools::redirectLink($currentIndex.'&conf=14&token='.$this->token);
  151. $this->_errors[] = $this->l('a part of the data has been copied but some language files could not be found or copied');
  152. }
  153. /**
  154. * Change the key translation to according it to theme name.
  155. *
  156. * @param string $path
  157. * @param string $theme_from
  158. * @param string $theme_to
  159. * @return boolean
  160. */
  161. public function changeModulesKeyTranslation ($path, $theme_from, $theme_to)
  162. {
  163. $content = file_get_contents($path);
  164. $arr_replace = array();
  165. $bool_flag = true;
  166. if(preg_match_all('#\$_MODULE\[\'([^\']+)\'\]#Ui', $content, $matches))
  167. {
  168. foreach ($matches[1] as $key=>$value)
  169. {
  170. $arr_replace[$value] = str_replace($theme_from, $theme_to, $value);
  171. }
  172. $content = str_replace(array_keys($arr_replace), array_values($arr_replace), $content);
  173. $bool_flag = (file_put_contents($path, $content) === false) ? false : true;
  174. }
  175. return $bool_flag;
  176. }
  177. public function submitExportLang()
  178. {
  179. global $currentIndex;
  180. $lang = strtolower(Tools::getValue('iso_code'));
  181. $theme = strval(Tools::getValue('theme'));
  182. if ($lang AND $theme)
  183. {
  184. $items = array_flip(Language::getFilesList($lang, $theme, false, false, false, false, true));
  185. $gz = new Archive_Tar(_PS_TRANSLATIONS_DIR_.'/export/'.$lang.'.gzip', true);
  186. if ($gz->createModify($items, NULL, _PS_ROOT_DIR_));
  187. Tools::redirect('translations/export/'.$lang.'.gzip');
  188. $this->_errors[] = Tools::displayError('An error occurred while creating archive.');
  189. }
  190. $this->_errors[] = Tools::displayError('Please choose a language and theme.');
  191. }
  192. public function checkAndAddMailsFiles ($iso_code, $files_list)
  193. {
  194. $mails = scandir(_PS_MAIL_DIR_.'en/');
  195. $mails_new_lang = array();
  196. foreach ($files_list as $file)
  197. {
  198. if (preg_match('#^mails\/([a-z0-9]+)\/#Ui', $file['filename'], $matches))
  199. {
  200. $slash_pos = strrpos($file['filename'], '/');
  201. $mails_new_lang[] = substr($file['filename'], -(strlen($file['filename'])-$slash_pos-1));
  202. }
  203. }
  204. $arr_mails_needed = array_diff($mails, $mails_new_lang);
  205. foreach ($arr_mails_needed as $mail_to_add)
  206. {
  207. if ($mail_to_add !== '.' && $mail_to_add !== '..' && $mail_to_add !== '.svn')
  208. {
  209. @copy(_PS_MAIL_DIR_.'en/'.$mail_to_add, _PS_MAIL_DIR_.$iso_code.'/'.$mail_to_add);
  210. }
  211. }
  212. }
  213. public function submitImportLang()
  214. {
  215. global $currentIndex;
  216. if (!isset($_FILES['file']['tmp_name']) OR !$_FILES['file']['tmp_name'])
  217. $this->_errors[] = Tools::displayError('No file selected');
  218. else
  219. {
  220. $gz = new Archive_Tar($_FILES['file']['tmp_name'], true);
  221. $iso_code = str_replace('.gzip', '', $_FILES['file']['name']);
  222. $files_list = $gz->listContent();
  223. if ($gz->extract(_PS_TRANSLATIONS_DIR_.'../', false))
  224. {
  225. $this->checkAndAddMailsFiles($iso_code, $files_list);
  226. if (Validate::isLanguageFileName($_FILES['file']['name']))
  227. {
  228. if (!Language::checkAndAddLanguage($iso_code))
  229. $conf = 20;
  230. }
  231. Tools::redirectAdmin($currentIndex.'&conf='.(isset($conf) ? $conf : '15').'&token='.$this->token);
  232. }
  233. $this->_errors[] = Tools::displayError('Archive cannot be extracted.');
  234. }
  235. }
  236. public function submitAddLang()
  237. {
  238. global $currentIndex;
  239. $arr_import_lang = explode('|', Tools::getValue('params_import_language')); /* 0 = Language ISO code, 1 = PS version */
  240. if (Validate::isLangIsoCode($arr_import_lang[0]))
  241. {
  242. if ($content = Tools::file_get_contents('http://www.prestashop.com/download/lang_packs/gzip/'.$arr_import_lang[1].'/'.$arr_import_lang[0].'.gzip', false, stream_context_create(array('http' => array('method' => 'GET', 'timeout' => 5)))))
  243. {
  244. $file = _PS_TRANSLATIONS_DIR_.$arr_import_lang[0].'.gzip';
  245. if (file_put_contents($file, $content))
  246. {
  247. $gz = new Archive_Tar($file, true);
  248. $files_list = $gz->listContent();
  249. if ($gz->extract(_PS_TRANSLATIONS_DIR_.'../', false))
  250. {
  251. $this->checkAndAddMailsFiles($arr_import_lang[0], $files_list);
  252. if (!Language::checkAndAddLanguage($arr_import_lang[0]))
  253. $conf = 20;
  254. if (!unlink($file))
  255. $this->_errors[] = Tools::displayError('Cannot delete archive');
  256. Tools::redirectAdmin($currentIndex.'&conf='.(isset($conf) ? $conf : '15').'&token='.$this->token);
  257. }
  258. $this->_errors[] = Tools::displayError('Archive cannot be extracted.');
  259. if (!unlink($file))
  260. $this->_errors[] = Tools::displayError('Cannot delete archive');
  261. }
  262. else
  263. $this->_errors[] = Tools::displayError('Server does not have permissions for writing.');
  264. }
  265. else
  266. $this->_errors[] = Tools::displayError('Language not found');
  267. }
  268. else
  269. $this->_errors[] = Tools::displayError('Invalid parameter');
  270. }
  271. /**
  272. * This method check each file (tpl or php file), get its sentences to translate,
  273. * compare with posted values and write in iso code translation file.
  274. *
  275. * @param string $file_name
  276. * @param array $files
  277. * @param string $theme_name
  278. * @param string $module_name
  279. * @param string|boolean $dir
  280. * @return void
  281. */
  282. protected function findAndWriteTranslationsIntoFile($file_name, $files, $theme_name, $module_name, $dir = false)
  283. {
  284. // These static vars allow to use file to write just one time.
  285. static $_cache_file = array();
  286. static $str_write = '';
  287. static $array_check_duplicate = array();
  288. // Default translations and Prestashop overriding themes are distinguish
  289. $is_default = $theme_name === self::DEFAULT_THEME_NAME ? true : false;
  290. // Set file_name in static var, this allow to open and wright the file just one time
  291. if (!isset($_cache_file[($is_default ? self::DEFAULT_THEME_NAME : $theme_name).'-'.$file_name]) )
  292. {
  293. $str_write = '';
  294. $_cache_file[($is_default ? self::DEFAULT_THEME_NAME : $theme_name).'-'.$file_name] = true;
  295. if(!file_exists($file_name))
  296. file_put_contents($file_name, '');
  297. if (!is_writable($file_name))
  298. die ($this->l('Cannot write the theme\'s language file ').'('.$file_name.')'.$this->l('. Please check write permissions.'));
  299. // this string is initialized one time for a file
  300. $str_write .= "<?php\n\nglobal \$_MODULE;\n\$_MODULE = array();\n";
  301. $array_check_duplicate = array();
  302. }
  303. if (!$dir)
  304. $dir = ($theme_name == self::DEFAULT_THEME_NAME ? _PS_MODULE_DIR_.$module_name.'/' : _PS_ALL_THEMES_DIR_.$theme_name.'/modules/'.$module_name.'/');
  305. foreach ($files AS $template_file)
  306. {
  307. if ((preg_match('/^(.*).tpl$/', $template_file) OR ($is_default AND preg_match('/^(.*).php$/', $template_file))) AND file_exists($tpl = $dir.$template_file))
  308. {
  309. // Get translations key
  310. $content = file_get_contents($tpl);
  311. preg_match_all(substr($template_file, -4) == '.tpl' ? self::$tpl_regexp : self::$php_regexp, $content, $matches);
  312. // Write each translation on its module file
  313. $template_name = substr(basename($template_file), 0, -4);
  314. foreach ($matches[1] AS $key)
  315. {
  316. $post_key = md5(strtolower($module_name).'_'.($is_default ? self::DEFAULT_THEME_NAME : strtolower($theme_name)).'_'.strtolower($template_name).'_'.md5($key));
  317. $pattern = '\'<{'.strtolower($module_name).'}'.($is_default ? 'prestashop' : strtolower($theme_name)).'>'.strtolower($template_name).'_'.md5($key).'\'';
  318. if (array_key_exists($post_key, $_POST) AND !empty($_POST[$post_key]) AND !in_array($pattern, $array_check_duplicate))
  319. {
  320. $array_check_duplicate[] = $pattern;
  321. $str_write .= '$_MODULE['.$pattern.'] = \''.pSQL($_POST[$post_key]).'\';'."\n";
  322. $this->total_expression++;
  323. }
  324. }
  325. }
  326. }
  327. if (isset($_cache_file[($is_default ? self::DEFAULT_THEME_NAME : $theme_name).'-'.$file_name]) AND $str_write != "<?php\n\nglobal \$_MODULE;\n\$_MODULE = array();\n")
  328. file_put_contents($file_name, $str_write);
  329. }
  330. public function clearModuleFiles ($files, $type_clear = 'file', $path = '')
  331. {
  332. $arr_exclude = array('img', 'js', 'mails');
  333. $arr_good_ext = array('.tpl', '.php');
  334. foreach ($files as $key=>$file)
  335. {
  336. if ($file{0} === '.' OR in_array(substr($file, 0, strrpos($file,'.')), $this->all_iso_lang))
  337. unset($files[$key]);
  338. else if ($type_clear === 'file' AND !in_array(substr($file, strrpos($file,'.')),$arr_good_ext))
  339. unset($files[$key]);
  340. else if ($type_clear === 'directory' AND (!is_dir($path.$file) OR in_array($file, $arr_exclude)))
  341. unset($files[$key]);
  342. }
  343. return $files;
  344. }
  345. /**
  346. * This method get translation for each files of a module,
  347. * compare with global $_MODULES array and fill AdminTranslations::modules_translations array
  348. * With key as English sentences and values as their iso code translations.
  349. *
  350. * @param array $files
  351. * @param string $theme_name
  352. * @param string $module_name
  353. * @param string|boolean $dir
  354. * @param string $iso_code
  355. * @return void
  356. */
  357. protected function findAndFillTranslations($files, $theme_name, $module_name, $dir = false, $iso_code = '')
  358. {
  359. global $_MODULES;
  360. // added for compatibility
  361. $_MODULES = array_change_key_case($_MODULES);
  362. // Default translations and Prestashop overriding themes are distinguish
  363. $is_default = $theme_name === self::DEFAULT_THEME_NAME ? true : false;
  364. if (!$dir)
  365. $dir = ($theme_name === self::DEFAULT_THEME_NAME ? _PS_MODULE_DIR_.$module_name.'/' : _PS_ALL_THEMES_DIR_.$theme_name.'/modules/'.$module_name.'/');
  366. // Thank to this var similar keys are not duplicate
  367. // in AndminTranslation::modules_translations array
  368. // see below
  369. $array_check_duplicate = array();
  370. foreach ($files AS $template_file)
  371. {
  372. if ((preg_match('/^(.*).tpl$/', $template_file) OR ($is_default AND preg_match('/^(.*).php$/', $template_file))) AND file_exists($tpl = $dir.$template_file))
  373. {
  374. // Get translations key
  375. $content = file_get_contents($tpl);
  376. preg_match_all(substr($template_file, -4) == '.tpl' ? self::$tpl_regexp : self::$php_regexp, $content, $matches);
  377. // Write each translation on its module file
  378. $template_name = substr(basename($template_file), 0, -4);
  379. foreach ($matches[1] AS $key)
  380. {
  381. $module_key = ($is_default ? self::DEFAULT_THEME_NAME : '').'<{'.Tools::strtolower($module_name).'}'.strtolower($is_default ? 'prestashop' : $theme_name).'>'.Tools::strtolower($template_name).'_'.md5($key);
  382. // to avoid duplicate entry
  383. if (!in_array($module_key, $array_check_duplicate))
  384. {
  385. $array_check_duplicate[] = $module_key;
  386. $this->modules_translations[strtolower($is_default ? self::DEFAULT_THEME_NAME : $theme_name)][$module_name][$template_name][$key]
  387. = key_exists($module_key, $_MODULES) ? html_entity_decode($_MODULES[$module_key], ENT_COMPAT, 'UTF-8') : '';
  388. $this->total_expression++;
  389. }
  390. }
  391. }
  392. }
  393. }
  394. public function postProcess()
  395. {
  396. global $currentIndex;
  397. if (Tools::isSubmit('submitCopyLang'))
  398. {
  399. if ($this->tabAccess['add'] === '1')
  400. $this->submitCopyLang();
  401. else
  402. $this->_errors[] = Tools::displayError('You do not have permission to add here.');
  403. }
  404. elseif (Tools::isSubmit('submitExport'))
  405. {
  406. if ($this->tabAccess['add'] === '1')
  407. $this->submitExportLang();
  408. else
  409. $this->_errors[] = Tools::displayError('You do not have permission to add here.');
  410. }
  411. elseif (Tools::isSubmit('submitImport'))
  412. {
  413. if ($this->tabAccess['add'] === '1')
  414. $this->submitImportLang();
  415. else
  416. $this->_errors[] = Tools::displayError('You do not have permission to add here.');
  417. }
  418. elseif (Tools::isSubmit('submitAddLanguage'))
  419. {
  420. if ($this->tabAccess['add'] === '1')
  421. $this->submitAddLang();
  422. else
  423. $this->_errors[] = Tools::displayError('You do not have permission to add here.');
  424. }
  425. elseif (Tools::isSubmit('submitTranslationsFront'))
  426. {
  427. if ($this->tabAccess['edit'] === '1')
  428. {
  429. if (!Validate::isLanguageIsoCode(Tools::strtolower(Tools::getValue('lang'))))
  430. die(Tools::displayError());
  431. $this->writeTranslationFile('Front', _PS_THEME_DIR_.'lang/'.Tools::strtolower(Tools::getValue('lang')).'.php');
  432. }
  433. else
  434. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  435. }
  436. elseif (Tools::isSubmit('submitTranslationsPDF'))
  437. {
  438. if ($this->tabAccess['edit'] === '1')
  439. {
  440. if (!Validate::isLanguageIsoCode(Tools::strtolower(Tools::getValue('lang'))))
  441. die(Tools::displayError());
  442. $this->writeTranslationFile('PDF', _PS_TRANSLATIONS_DIR_.Tools::strtolower(Tools::getValue('lang')).'/pdf.php', 'PDF');
  443. }
  444. else
  445. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  446. }
  447. elseif (Tools::isSubmit('submitTranslationsBack'))
  448. {
  449. if ($this->tabAccess['edit'] === '1')
  450. {
  451. if (!Validate::isLanguageIsoCode(Tools::strtolower(Tools::getValue('lang'))))
  452. die(Tools::displayError());
  453. $this->writeTranslationFile('Back', _PS_TRANSLATIONS_DIR_.Tools::strtolower(Tools::getValue('lang')).'/admin.php', 'ADM');
  454. }
  455. else
  456. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  457. }
  458. elseif (Tools::isSubmit('submitTranslationsErrors'))
  459. {
  460. if ($this->tabAccess['edit'] === '1')
  461. {
  462. if (!Validate::isLanguageIsoCode(Tools::strtolower(Tools::getValue('lang'))))
  463. die(Tools::displayError());
  464. $this->writeTranslationFile('Errors', _PS_TRANSLATIONS_DIR_.Tools::strtolower(Tools::getValue('lang')).'/errors.php', false, 'ERRORS');
  465. }
  466. else
  467. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  468. }
  469. elseif (Tools::isSubmit('submitTranslationsFields'))
  470. {
  471. if ($this->tabAccess['edit'] === '1')
  472. {
  473. if (!Validate::isLanguageIsoCode(Tools::strtolower(Tools::getValue('lang'))))
  474. die(Tools::displayError());
  475. $this->writeTranslationFile('Fields', _PS_TRANSLATIONS_DIR_.Tools::strtolower(Tools::getValue('lang')).'/fields.php', false, 'FIELDS');
  476. }
  477. else
  478. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  479. }
  480. elseif (Tools::isSubmit('submitTranslationsMails') || Tools::isSubmit('submitTranslationsMailsAndStay'))
  481. {
  482. if ($this->tabAccess['edit'] === '1' && ($id_lang = Language::getIdByIso(Tools::getValue('lang'))) > 0)
  483. {
  484. $this->submitTranslationsMails($id_lang);
  485. }
  486. else
  487. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  488. }
  489. elseif (Tools::isSubmit('submitTranslationsModules'))
  490. {
  491. if ($this->tabAccess['edit'] === '1')
  492. {
  493. $array_lang_src = Language::getLanguages(false);
  494. foreach ($array_lang_src as $language)
  495. $this->all_iso_lang[] = $language['iso_code'];
  496. $lang = Tools::strtolower($_POST['lang']);
  497. if (!Validate::isLanguageIsoCode($lang))
  498. die(Tools::displayError());
  499. if (!$modules = scandir(_PS_MODULE_DIR_))
  500. $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.'));
  501. else
  502. {
  503. $arr_find_and_write = array();
  504. $arr_files = $this->getAllModuleFiles($modules, _PS_MODULE_DIR_, $lang, true);
  505. $arr_find_and_write = array_merge($arr_find_and_write, $arr_files);
  506. if(file_exists(_PS_THEME_DIR_.'/modules/'))
  507. {
  508. $modules = scandir(_PS_THEME_DIR_.'/modules/');
  509. $arr_files = $this->getAllModuleFiles($modules, _PS_THEME_DIR_.'modules/', $lang);
  510. $arr_find_and_write = array_merge($arr_find_and_write, $arr_files);
  511. }
  512. foreach ($arr_find_and_write as $key=>$value)
  513. $this->findAndWriteTranslationsIntoFile($value['file_name'], $value['files'], $value['theme'], $value['module'], $value['dir']);
  514. Tools::redirectAdmin($currentIndex.'&conf=4&token='.$this->token);
  515. }
  516. }
  517. else
  518. $this->_errors[] = Tools::displayError('You do not have permission to edit here.');
  519. }
  520. }
  521. protected function getMailPattern()
  522. {
  523. // Let the indentation like it.
  524. return '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd">
  525. <html>
  526. <head>
  527. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  528. <title>#title</title>
  529. </head>
  530. <body>
  531. #content
  532. </body>
  533. </html>';
  534. }
  535. /**
  536. * This method is used to wright translation for mails.
  537. * This wrights subject translation files
  538. * (in root/mails/lang_choosen/lang.php or root/_PS_THEMES_DIR_/mails/lang_choosen/lang.php)
  539. * and mails files.
  540. *
  541. * @param int $id_lang
  542. */
  543. protected function submitTranslationsMails ($id_lang)
  544. {
  545. global $currentIndex;
  546. $obj_lang = new Language($id_lang);
  547. $params_redirect = (Tools::isSubmit('submitTranslationsMailsAndStay') ? '&lang='.Tools::getValue('lang').'&type='.Tools::getValue('type') : '');
  548. $arr_mail_content = array();
  549. $arr_mail_path = array();
  550. if (Tools::getValue('core_mail')) {
  551. $arr_mail_content['core_mail'] = Tools::getValue('core_mail');
  552. $arr_mail_path['core_mail'] = _PS_MAIL_DIR_.$obj_lang->iso_code.'/';
  553. }
  554. if (Tools::getValue('module_mail')) {
  555. $arr_mail_content['module_mail'] = Tools::getValue('module_mail');
  556. $arr_mail_path['module_mail'] = _PS_MODULE_DIR_.'{module}'.'/mails/'.$obj_lang->iso_code.'/';
  557. }
  558. if (Tools::getValue('theme_mail')) {
  559. $arr_mail_content['theme_mail'] = Tools::getValue('theme_mail');
  560. $arr_mail_path['theme_mail'] = _PS_THEME_DIR_.'mails/'.$obj_lang->iso_code.'/';
  561. }
  562. if (Tools::getValue('theme_module_mail')) {
  563. $arr_mail_content['theme_module_mail'] = Tools::getValue('theme_module_mail');
  564. $arr_mail_path['theme_module_mail'] = _PS_THEME_DIR_.'modules/{module}'.'/mails/'.$obj_lang->iso_code.'/';
  565. }
  566. // Save each mail content
  567. foreach ($arr_mail_content as $group_name=>$all_content)
  568. {
  569. foreach ($all_content as $type_content=>$mails)
  570. {
  571. foreach ($mails as $mail_name=>$content)
  572. {
  573. $module_name = false;
  574. $module_name_pipe_pos = stripos($mail_name, '|');
  575. if ($module_name_pipe_pos)
  576. {
  577. $module_name = substr($mail_name, 0, $module_name_pipe_pos);
  578. $mail_name = substr($mail_name, $module_name_pipe_pos+1);
  579. }
  580. if ($type_content == 'html')
  581. {
  582. $content = Tools::htmlentitiesUTF8($content);
  583. $content = htmlspecialchars_decode($content);
  584. // replace correct end of line
  585. $content = str_replace("\r\n", PHP_EOL, $content);
  586. $title = '';
  587. if (Tools::getValue('title_'.$group_name.'_'.$mail_name))
  588. {
  589. $title = Tools::getValue('title_'.$group_name.'_'.$mail_name);
  590. }
  591. $string_mail = $this->getMailPattern();
  592. $content = str_replace(array('#title', '#content'), array($title, $content), $string_mail);
  593. // Magic Quotes shall... not.. PASS!
  594. if (_PS_MAGIC_QUOTES_GPC_)
  595. $content = stripslashes($content);
  596. }
  597. if (Validate::isCleanHTML($content))
  598. {
  599. $path = $arr_mail_path[$group_name];
  600. if ($module_name)
  601. $path = str_replace('{module}', $module_name, $path);
  602. file_put_contents($path.$mail_name.'.'.$type_content, $content);
  603. chmod($path.$mail_name.'.'.$type_content, 0777);
  604. }
  605. else
  606. {
  607. $this->_errors[] = Tools::displayError('HTML e-mail templates cannot contain JavaScript code.');
  608. }
  609. }
  610. }
  611. }
  612. // Update subjects
  613. $array_subjects = array();
  614. if ($subjects = Tools::getValue('subject') AND is_array($subjects))
  615. {
  616. $array_subjects['core_and_modules'] = array('translations'=>array(), 'path'=>$arr_mail_path['core_mail'].'lang.php');
  617. if (isset($arr_mail_path['theme_mail']))
  618. $array_subjects['themes_and_modules'] = array('translations'=>array(), 'path'=>$arr_mail_path['theme_mail'].'lang.php');
  619. foreach ($subjects AS $group => $subject_translation)
  620. {
  621. if ($group == 'core_mail' || $group == 'module_mail') {
  622. $array_subjects['core_and_modules']['translations'] = array_merge($array_subjects['core_and_modules']['translations'], $subject_translation);
  623. }
  624. elseif ( isset($array_subjects['themes_and_modules']) && ($group == 'theme_mail' || $group == 'theme_module_mail')) {
  625. $array_subjects['themes_and_modules']['translations'] = array_merge($array_subjects['themes_and_modules']['translations'], $subject_translation);
  626. }
  627. }
  628. }
  629. if (!empty($array_subjects)) {
  630. foreach ($array_subjects as $type=>$infos) {
  631. $this->writeSubjectTranslationFile($infos['translations'], $infos['path']);
  632. }
  633. }
  634. if (count($this->_errors) == 0)
  635. Tools::redirectAdmin($currentIndex.'&conf=4&token='.$this->token.$params_redirect);
  636. }
  637. public function display()
  638. {
  639. global $currentIndex, $cookie;
  640. $translations = array(
  641. 'front' => $this->l('Front Office translations'),
  642. 'back' => $this->l('Back Office translations'),
  643. 'errors' => $this->l('Error message translations'),
  644. 'fields' => $this->l('Field name translations'),
  645. 'modules' => $this->l('Module translations'),
  646. 'pdf' => $this->l('PDF translations'),
  647. 'mails' => $this->l('E-mail template translations'),
  648. );
  649. if ($type = Tools::getValue('type'))
  650. $this->{'displayForm'.ucfirst($type)}(Tools::strtolower(Tools::getValue('lang')));
  651. else
  652. {
  653. $languages = Language::getLanguages(false);
  654. echo '<fieldset class="width3"><legend><img src="../img/admin/translation.gif" />'.$this->l('Modify translations').'</legend>'.
  655. $this->l('Here you can modify translations for all text input into PrestaShop.').'<br />'.
  656. $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 />
  657. <form method="get" action="index.php" id="typeTranslationForm">
  658. <input type="hidden" name="tab" value="AdminTranslations" />
  659. <input type="hidden" name="lang" id="translation_lang" value="0" />
  660. <select name="type" style="float:left; margin-right:10px;">';
  661. foreach ($translations AS $key => $translation)
  662. echo '<option value="'.$key.'">'.$translation.'&nbsp;</option>';
  663. echo '</select>';
  664. foreach ($languages AS $language)
  665. echo '<a href="javascript:chooseTypeTranslation(\''.$language['iso_code'].'\')">
  666. <img src="'._THEME_LANG_DIR_.$language['id_lang'].'.jpg" alt="'.$language['iso_code'].'" title="'.$language['iso_code'].'" />
  667. </a>';
  668. echo '<input type="hidden" name="token" value="'.$this->token.'" /></form></fieldset>
  669. <br /><br /><h2>'.$this->l('Translation exchange').'</h2>';
  670. echo '<form action="'.$currentIndex.'&token='.$this->token.'" method="post" enctype="multipart/form-data">
  671. <fieldset class="width3">
  672. <legend>
  673. <img src="../img/admin/import.gif" />'.$this->l('Add / Update a language').'
  674. </legend>
  675. <div id="submitAddLangContent" style="float:left;"><p>'.$this->l('You can add or update a language directly from prestashop.com here').'</p>';
  676. $this->displayWarning($this->l('If you choose to update an existing language pack, all your previous customization in the theme named prestashop will be lost. This includes front office expressions and default e-mail templates.'));
  677. echo '<div style="font-weight:bold; float:left;">'.$this->l('Language you want to add or update:').' ';
  678. if ($lang_packs = Tools::file_get_contents('http://www.prestashop.com/download/lang_packs/get_each_language_pack.php?version='._PS_VERSION_, false, stream_context_create(array('http' => array('method' => 'GET', 'timeout' => 5)))))
  679. {
  680. // Notice : for php < 5.2 compatibility, Tools::jsonDecode. The second parameter to true will set us
  681. if ($lang_packs != '' AND $lang_packs = Tools::jsonDecode($lang_packs,true))
  682. {
  683. echo '
  684. <select id="params_import_language" name="params_import_language">
  685. <optgroup label="'.$this->l('Add a language').'">';
  686. $alreadyInstalled = '<optgroup label="'.$this->l('Update a language').'">';
  687. foreach($lang_packs AS $lang_pack)
  688. {
  689. if (!Language::isInstalled($lang_pack['iso_code']))
  690. echo '<option value="'.$lang_pack['iso_code'].'|'.$lang_pack['version'].'">'.$lang_pack['name'].'</option>';
  691. else
  692. $alreadyInstalled.='<option value="'.$lang_pack['iso_code'].'|'.$lang_pack['version'].'">'.$lang_pack['name'].'</option>';
  693. }
  694. echo '
  695. </optgroup>'.$alreadyInstalled.'</optgroup>
  696. </select> &nbsp;<input type="submit" value="'.$this->l('Add or update the language').'" name="submitAddLanguage" class="button" />';
  697. }
  698. echo '</div>';
  699. }
  700. else
  701. echo '<br /><br /><p class="error">'.$this->l('Cannot connect to prestashop.com to get languages list.').'</p></div>';
  702. echo ' </div>
  703. </fieldset>
  704. </form><br /><br />';
  705. echo '<form action="'.$currentIndex.'&token='.$this->token.'" method="post" enctype="multipart/form-data">
  706. <fieldset class="width3">
  707. <legend>
  708. <img src="../img/admin/import.gif" />'.$this->l('Import a language pack manually').'
  709. </legend>
  710. <div id="submitImportContent">'.
  711. $this->l('If the name format is: isocode.gzip (e.g. fr.gzip) and the language corresponding to this package does not exist, it will automatically be created.').
  712. $this->l('Be careful, as it will replace all existing data for the destination language!').'<br /><br />'.
  713. $this->l('Language pack to import:').' <input type="file" name="file" /> &nbsp;<input type="submit" value="'.$this->l('Import').'" name="submitImport" class="button" /></p>
  714. </div>
  715. </fieldset>
  716. </form>
  717. <br /><br />
  718. <form action="'.$currentIndex.'&token='.$this->token.'" method="post" enctype="multipart/form-data">
  719. <fieldset class="width3"><legend><img src="../img/admin/export.gif" />'.$this->l('Export a language').'</legend>
  720. <p>'.$this->l('Export data from one language to a file (language pack).').'<br />'.
  721. $this->l('Choose the theme from which you want to export translations.').'<br />
  722. <select name="iso_code" style="margin-top:10px;">';
  723. foreach ($languages AS $language)
  724. echo '<option value="'.$language['iso_code'].'">'.$language['name'].'</option>';
  725. echo '
  726. </select>
  727. &nbsp;&nbsp;&nbsp;
  728. <select name="theme" style="margin-top:10px;">';
  729. $themes = self::getThemesList();
  730. foreach ($themes AS $theme)
  731. echo '<option value="'.$theme['name'].'">'.$theme['name'].'</option>';
  732. echo '
  733. </select>&nbsp;&nbsp;
  734. <input type="submit" class="button" name="submitExport" value="'.$this->l('Export').'" />
  735. </fieldset>
  736. </form>
  737. <br /><br />';
  738. $allLanguages = Language::getLanguages(false);
  739. echo '
  740. <form action="'.$currentIndex.'&token='.$this->token.'" method="post">
  741. <fieldset class="width3"><legend><img src="../img/admin/copy_files.gif" />'.$this->l('Copy').'</legend>
  742. <p>'.$this->l('Copies data from one language to another.').'<br />'.
  743. $this->l('Be careful, as it will replace all existing data for the destination language!').'<br />'.
  744. $this->l('If necessary').', <b><a href="index.php?tab=AdminLanguages&addlang&token='.Tools::getAdminToken('AdminLanguages'.(int)(Tab::getIdFromClassName('AdminLanguages')).(int)($cookie->id_employee)).'">'.$this->l('first create a new language').'</a></b>.</p>
  745. <div style="float:left;">
  746. <p>
  747. <div style="width:75px; font-weight:bold; float:left;">'.$this->l('From:').'</div>
  748. <select name="fromLang">';
  749. foreach ($languages AS $language)
  750. echo '<option value="'.$language['iso_code'].'">'.$language['name'].'</option>';
  751. echo '
  752. </select>
  753. &nbsp;&nbsp;&nbsp;
  754. <select name="fromTheme">';
  755. $themes = self::getThemesList();
  756. foreach ($themes AS $theme)
  757. echo '<option value="'.$theme['name'].'">'.$theme['name'].'</option>';
  758. echo '
  759. </select> <span style="font-style: bold; color: red;">*</span>
  760. </p>
  761. <p>
  762. <div style="width:75px; font-weight:bold; float:left;">'.$this->l('To:').'</div>
  763. <select name="toLang">';
  764. foreach ($allLanguages AS $language)
  765. echo '<option value="'.$language['iso_code'].'">'.$language['name'].'</option>';
  766. echo '
  767. </select>
  768. &nbsp;&nbsp;&nbsp;
  769. <select name="toTheme">';
  770. $themes = self::getThemesList();
  771. foreach ($themes AS $theme)
  772. echo '<option value="'.$theme['name'].'">'.$theme['name'].'</option>';
  773. echo '
  774. </select>
  775. </p>
  776. </div>
  777. <div style="float:left;">
  778. <input type="submit" value="'.$this->l(' Copy ').'" name="submitCopyLang" class="button" style="margin:25px 0px 0px 25px;" />
  779. </div>
  780. <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>
  781. </fieldset>
  782. </form>';
  783. }
  784. }
  785. public function fileExists($dir, $file, $var)
  786. {
  787. ${$var} = array();
  788. if (!file_exists($dir))
  789. if (!mkdir($dir, 0700))
  790. die('Please create the directory '.$dir);
  791. if (!file_exists($dir.'/'.$file))
  792. if (!file_put_contents($dir.'/'.$file, "<?php\n\nglobal \$".$var.";\n\$".$var." = array();\n\n?>"))
  793. die('Please create a "'.$file.'" file in '.$dir);
  794. if (!is_writable($dir.'/'.$file))
  795. $this->displayWarning(Tools::displayError('This file must be writable:').' '.$dir.'/'.$file);
  796. include($dir.'/'.$file);
  797. return ${$var};
  798. }
  799. public function displayToggleButton($closed = false)
  800. {
  801. $str_output = '
  802. <script type="text/javascript">';
  803. if (Tools::getValue('type') == 'mails')
  804. $str_output .= '$(document).ready(function(){
  805. openCloseAllDiv(\''.$_GET['type'].'_div\', this.value == openAll); toggleElemValue(this.id, openAll, closeAll);
  806. });';
  807. $str_output .= '
  808. var openAll = \''.html_entity_decode($this->l('Expand all fieldsets'), ENT_NOQUOTES, 'UTF-8').'\';
  809. var closeAll = \''.html_entity_decode($this->l('Close all fieldsets'), ENT_NOQUOTES, 'UTF-8').'\';
  810. </script>
  811. <input type="button" class="button" id="buttonall" onclick="openCloseAllDiv(\''.$_GET['type'].'_div\', this.value == openAll); toggleElemValue(this.id, openAll, closeAll);" />
  812. <script type="text/javascript">toggleElemValue(\'buttonall\', '.($closed ? 'openAll' : 'closeAll').', '.($closed ? 'closeAll' : 'openAll').');</script>';
  813. return $str_output;
  814. }
  815. protected function displaySubmitButtons($name)
  816. {
  817. return '
  818. <input type="submit" name="submitTranslations'.ucfirst($name).'" value="'.$this->l('Update translations').'" class="button" />
  819. <input type="submit" name="submitTranslations'.ucfirst($name).'AndStay" value="'.$this->l('Update and stay').'" class="button" />';
  820. }
  821. public function displayAutoTranslate()
  822. {
  823. $languageCode = Tools::htmlentitiesUTF8(Language::getLanguageCodeByIso(Tools::getValue('lang')));
  824. return '
  825. <input type="button" class="button" onclick="translateAll();" value="'.$this->l('Translate with Google (experimental)').'" />
  826. <script type="text/javascript" src="http://www.google.com/jsapi"></script>
  827. <script type="text/javascript">
  828. var gg_translate = {
  829. language_code : \''.$languageCode.'\',
  830. not_available : \''.addslashes(html_entity_decode($this->l('this language is not available on Google Translate API'), ENT_QUOTES, 'utf-8')).'\',
  831. tooltip_title : \''.addslashes(html_entity_decode($this->l('Google translate suggests :'), ENT_QUOTES, 'utf-8')).'\'
  832. };
  833. </script>
  834. <script type="text/javascript" src="../js/gg-translate.js"></script>
  835. <script type="text/javascript">
  836. var displayOnce = 0;
  837. google.load("language", "1");
  838. function translateAll() {
  839. if (!ggIsTranslatable(gg_translate[\'language_code\']))
  840. alert(\'"\'+gg_translate[\'language_code\']+\'" : \'+gg_translate[\'not_available\']);
  841. else
  842. {
  843. $.each($(\'input[type="text"]\'), function() {
  844. var tdinput = $(this);
  845. if (tdinput.attr("value") == "" && tdinput.parent("td").prev().html()) {
  846. google.language.translate(tdinput.parent("td").prev().html(), "en", gg_translate[\'language_code\'], function(result) {
  847. if (!result.error)
  848. tdinput.val(result.translation);
  849. else if (displayOnce == 0)
  850. {
  851. displayOnce = 1;
  852. alert(result.error.message);
  853. }
  854. });
  855. }
  856. });
  857. $.each($("textarea"), function() {
  858. var tdtextarea = $(this);
  859. if (tdtextarea.html() == "" && tdtextarea.parent("td").prev().html()) {
  860. google.language.translate(tdtextarea.parent("td").prev().html(), "en", gg_translate[\'language_code\'], function(result) {
  861. if (!result.error)
  862. tdtextarea.html(result.translation);
  863. else if (displayOnce == 0)
  864. {
  865. displayOnce = 1;
  866. alert(result.error.message);
  867. }
  868. });
  869. }
  870. });
  871. }
  872. }
  873. </script>';
  874. }
  875. public function displayLimitPostWarning($count)
  876. {
  877. $str_output = '';
  878. if ((ini_get('suhosin.post.max_vars') AND ini_get('suhosin.post.max_vars') < $count)
  879. OR (ini_get('suhosin.request.max_vars') AND ini_get('suhosin.request.max_vars') < $count))
  880. {
  881. if (ini_get('suhosin.post.max_vars') < $count OR ini_get('suhosin.request.max_vars') < $count)
  882. {
  883. $this->suhosin_limit_exceed = true;
  884. $str_output .= '<div class="warning">'.$this->l('Warning, your hosting provider is using the suhosin patch for PHP, which limits the maximum number of fields to post in a form:').'<br/>'
  885. .'<b>'.ini_get('suhosin.post.max_vars').'</b> '.$this->l('for suhosin.post.max_vars.').'<br/>'
  886. .'<b>'.ini_get('suhosin.request.max_vars').'</b> '.$this->l('for suhosin.request.max_vars.').'<br/>'
  887. .$this->l('Please ask your hosting provider to increase the suhosin post and request limit to')
  888. .' <u><b>'.((int)$count + 100).'</b></u> '.$this->l('at least.').' '.$this->l('or edit the translation file manually.').'</div>';
  889. }
  890. }
  891. return $str_output;
  892. }
  893. public function displayFormFront($lang)
  894. {
  895. global $currentIndex;
  896. $_LANG = $this->fileExists(_PS_THEME_DIR_.'lang', Tools::strtolower($lang).'.php', '_LANG');
  897. $str_output = '';
  898. /* List templates to parse */
  899. $templates = array_merge(scandir(_PS_THEME_DIR_), scandir(_PS_ALL_THEMES_DIR_));
  900. $count = 0;
  901. $files = array();
  902. foreach ($templates AS $template)
  903. if (preg_match('/^(.*).tpl$/', $template) AND (file_exists($tpl = _PS_THEME_DIR_.$template) OR file_exists($tpl = _PS_ALL_THEMES_DIR_.$template)))
  904. {
  905. $template2 = substr(basename($template), 0, -4);
  906. $newLang = array();
  907. $fd = fopen($tpl, 'r');
  908. $content = fread($fd, filesize($tpl));
  909. /* Search language tags (eg {l s='to translate'}) */
  910. $regex = '/\{l s=\''._PS_TRANS_PATTERN_.'\'( js=1)?\}/U';
  911. preg_match_all($regex, $content, $matches);
  912. /* Get string translation */
  913. foreach($matches[1] AS $key)
  914. {
  915. if(empty($key))
  916. {
  917. $this->_errors[] = $this->l('Empty string found, please edit:').' <br />'._PS_THEME_DIR_.''.$template;
  918. $newLang[$key] = '';
  919. }
  920. else
  921. {
  922. $key2 = $template2.'_'.md5($key);
  923. $newLang[$key] = (key_exists($key2, $_LANG)) ? html_entity_decode($_LANG[$key2], ENT_COMPAT, 'UTF-8') : '';
  924. }
  925. }
  926. $files[$template2] = $newLang;
  927. $count += sizeof($newLang);
  928. }
  929. $str_output .= '
  930. <h2>'.$this->l('Language').' : '.Tools::strtoupper($lang).' - '.$this->l('Front-Office translations').'</h2>
  931. '.$this->l('Total expressions').' : <b>'.$count.'</b>. '.$this->l('Click the fieldset title to expand or close the fieldset.').'.<br /><br />';
  932. $str_output .= $this->displayLimitPostWarning($count);
  933. if (!$this->suhosin_limit_exceed)
  934. {
  935. $str_output .= '
  936. <form method="post" action="'.$currentIndex.'&submitTranslationsFront=1&token='.$this->token.'" class="form">';
  937. $str_output .= $this->displayToggleButton(sizeof($_LANG) >= $count);
  938. $str_output .= $this->displayAutoTranslate();
  939. $str_output .= '<input type="hidden" name="lang" value="'.$lang.'" /><input type="submit" name="submitTranslationsFront" value="'.$this->l('Update translations').'" class="button" /><br /><br />';
  940. foreach ($files AS $k => $newLang)
  941. if (sizeof($newLang))
  942. {
  943. $countValues = array_count_values($newLang);
  944. $empty = isset($countValues['']) ? $countValues[''] : 0;
  945. $str_output .= '
  946. <fieldset><legend style="cursor : pointer" onclick="$(\'#'.$k.'-tpl\').slideToggle();">'.$k.' - <font color="blue">'.sizeof($newLang).'</font> '.$this->l('expressions').' (<font color="red">'.$empty.'</font>)</legend>
  947. <div name="front_div" id="'.$k.'-tpl" style="display: '.($empty ? 'block' : 'none').';">
  948. <table cellpadding="2">';
  949. foreach ($newLang AS $key => $value)
  950. {
  951. $str_output .= '<tr><td style="width: 40%">'.stripslashes($key).'</td><td>';
  952. if (strlen($key) != 0 && strlen($key) < TEXTAREA_SIZED)
  953. $str_output .= '= <input type="text" style="width: 450px" name="'.$k.'_'.md5($key).'" value="'.stripslashes(preg_replace('/"/', '\&quot;', stripslashes($value))).'" />';
  954. elseif(strlen($key))
  955. $str_output .= '= <textarea rows="'.(int)(strlen($key) / TEXTAREA_SIZED).'" style="width: 450px" name="'.$k.'_'.md5($key).'">'.stripslashes(preg_replace('/"/', '\&quot;', stripslashes($value))).'</textarea>';
  956. else
  957. $str_output .= '<span class="error-inline">'.implode(', ', $this->_errors).'</span>';
  958. $str_output .= '</td></tr>';
  959. }
  960. $str_output .= '
  961. </table>
  962. </div>
  963. </fieldset><br />';
  964. }
  965. $str_output .= '<br /><input type="submit" name="submitTranslationsFront" value="'.$this->l('Update translations').'" class="button" /></form>';
  966. }
  967. if (!empty($this->_errors))
  968. $this->displayErrors();
  969. echo $str_output;
  970. }
  971. public function displayFormBack($lang)
  972. {
  973. global $currentIndex;
  974. $_LANGADM = $this->fileExists(_PS_TRANSLATIONS_DIR_.$lang, 'admin.php', '_LANGADM');
  975. $str_output = '';
  976. /* List templates to parse */
  977. $count = 0;
  978. $tabs = scandir(PS_ADMIN_DIR.'/tabs');
  979. $tabs[] = '../../classes/AdminTab.php';
  980. $files = array();
  981. foreach ($tabs AS $tab)
  982. if (preg_match('/^(.*)\.php$/', $tab) AND file_exists($tpl = PS_ADMIN_DIR.'/tabs/'.$tab))
  983. {
  984. $tab = basename(substr($tab, 0, -4));
  985. $fd = fopen($tpl, 'r');
  986. $content = fread($fd, filesize($tpl));
  987. fclose($fd);
  988. $regex = '/this->l\(\''._PS_TRANS_PATTERN_.'\'[\)|\,]/U';
  989. preg_match_all($regex, $content, $matches);
  990. foreach ($matches[1] AS $key)
  991. $tabsArray[$tab][$key] = stripslashes(key_exists($tab.md5($key), $_LANGADM) ? html_entity_decode($_LANGADM[$tab.md5($key)], ENT_COMPAT, 'UTF-8') : '');
  992. $count += isset($tabsArray[$tab]) ? sizeof($tabsArray[$tab]) : 0;
  993. }
  994. foreach (array('header.inc', 'footer.inc', 'index', 'login', 'password', 'functions') AS $tab)
  995. {
  996. $tab = PS_ADMIN_DIR.'/'.$tab.'.php';
  997. $fd = fopen($tab, 'r');
  998. $content = fread($fd, filesize($tab));
  999. fclose($fd);
  1000. $regex = '/translate\(\''._PS_TRANS_PATTERN_.'\'\)/U';
  1001. preg_match_all($regex, $content, $matches);
  1002. foreach ($matches[1] AS $key)
  1003. $tabsArray['index'][$key] = stripslashes(key_exists('index'.md5($key), $_LANGADM) ? html_entity_decode($_LANGADM['index'.md5($key)], ENT_COMPAT, 'UTF-8') : '');
  1004. $count += isset($tabsArray['index']) ? sizeof($tabsArray['index']) : 0;
  1005. }
  1006. $str_output .= '
  1007. <h2>'.$this->l('Language').' : '.Tools::strtoupper($lang).' - '.$this->l('Back-Office translations').'</h2>
  1008. '.$this->l('Expressions to translate').' : <b>'.$count.'</b>. '.$this->l('Click on the titles to open fieldsets').'.<br /><br />';
  1009. $str_output .= $this->displayLimitPostWarning($count);
  1010. if (!$this->suhosin_limit_exceed)
  1011. {
  1012. $str_output .= '
  1013. <form method="post" action="'.$currentIndex.'&submitTranslationsBack=1&token='.$this->token.'" class="form">';
  1014. $str_output .= $this->displayToggleButton();
  1015. $str_output .= $this->displayAutoTranslate();
  1016. $str_output .= '<input type="hidden" name="lang" value="'.$lang.'" /><input type="submit" name="submitTranslationsBack" value="'.$this->l('Update translations').'" class="button" /><br /><br />';
  1017. foreach ($tabsArray AS $k => $newLang)
  1018. if (sizeof($newLang))
  1019. {
  1020. $countValues = array_count_values($newLang);
  1021. $empty = isset($countValues['']) ? $countValues[''] : 0;
  1022. $str_output .= '
  1023. <fieldset><legend style="cursor : pointer" onclick="$(\'#'.$k.'-tpl\').slideToggle();">'.$k.' - <font color="blue">'.sizeof($newLang).'</font> '.$this->l('expressions').' (<font color="red">'.$empty.'</font>)</legend>
  1024. <div name="back_div" id="'.$k.'-tpl" style="display: '.($empty ? 'block' : 'none').';">
  1025. <table cellpadding="2">';
  1026. foreach ($newLang AS $key => $value)
  1027. {
  1028. $str_output .= '<tr><td style="width: 40%">'.stripslashes($key).'</td><td>= ';
  1029. if (strlen($key) < TEXTAREA_SIZED)
  1030. $str_output .= '<input type="text" style="width: 450px" name="'.$k.md5($key).'" value="'.stripslashes(preg_replace('/"/', '\&quot;', $value)).'" /></td></tr>';
  1031. else
  1032. $str_output .= '<textarea rows="'.(int)(strlen($key) / TEXTAREA_SIZED).'" style="width: 450px" name="'.$k.md5($key).'">'.stripslashes(preg_replace('/"/', '\&quot;', $value)).'</textarea></td></tr>';
  1033. }
  1034. $str_output .= '
  1035. </table>
  1036. </div>
  1037. </fieldset><br />';
  1038. }
  1039. $str_output .= '<br /><input type="submit" name="submitTranslationsBack" value="'.$this->l('Update translations').'" class="button" /></form>';
  1040. }
  1041. echo $str_output;
  1042. }
  1043. public function displayFormErrors($lang)
  1044. {
  1045. global $currentIndex;
  1046. $_ERRORS = $this->fileExists(_PS_TRANSLATIONS_DIR_.$lang, 'errors.php', '_ERRORS');
  1047. $str_output = '';
  1048. /* List files to parse */
  1049. $stringToTranslate = array();
  1050. $dirToParse = array(PS_ADMIN_DIR.'/../',
  1051. PS_ADMIN_DIR.'/../classes/',
  1052. PS_ADMIN_DIR.'/../controllers/',
  1053. PS_ADMIN_DIR.'/../override/classes/',
  1054. PS_ADMIN_DIR.'/../override/controllers/',
  1055. PS_ADMIN_DIR.'/',
  1056. PS_ADMIN_DIR.'/tabs/');
  1057. if (!file_exists(_PS_MODULE_DIR_))
  1058. die($this->displayWarning(Tools::displayError('Fatal error: Module directory is not here anymore ').'('._PS_MODULE_DIR_.')'));
  1059. if (!is_writable(_PS_MODULE_DIR_))
  1060. $this->displayWarning(Tools::displayError('The module directory must be writable'));
  1061. if (!$modules = scandir(_PS_MODULE_DIR_))
  1062. $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.'));
  1063. else
  1064. {
  1065. $count = 0;
  1066. foreach ($modules AS $module)
  1067. if (is_dir(_PS_MODULE_DIR_.$module) && $module != '.' && $module != '..' && $module != '.svn' )
  1068. $dirToParse[] = _PS_MODULE_DIR_.$module.'/';
  1069. }
  1070. foreach ($dirToParse AS $dir)
  1071. foreach (scandir($dir) AS $file)
  1072. if (preg_match('/\.php$/', $file) AND file_exists($fn = $dir.$file) AND $file != 'index.php')
  1073. {
  1074. if (!filesize($fn))
  1075. continue;
  1076. preg_match_all('/Tools::displayError\(\''._PS_TRANS_PATTERN_.'\'(, (true|false))?\)/U', fread(fopen($fn, 'r'), filesize($fn)), $matches);
  1077. foreach($matches[1] AS $key)
  1078. $stringToTranslate[$key] = (key_exists(md5($key), $_ERRORS)) ? html_entity_decode($_ERRORS[md5($key)], ENT_COMPAT, 'UTF-8') : '';
  1079. }
  1080. $irow = 0;
  1081. $str_output .= $this->displayAutoTranslate();
  1082. $str_output .= '<h2>'.$this->l('Language').' : '.Tools::strtoupper($lang).' - '.$this->l('Error translations').'</h2>'
  1083. .$this->l('Errors to translate').' : <b>'.sizeof($stringToTranslate).'</b><br /><br />';
  1084. $str_output .= $this->displayLimitPostWarning(sizeof($stringToTranslate));
  1085. if (!$this->suhosin_limit_exceed)
  1086. {
  1087. $str_output .= '
  1088. <form method="post" action="'.$currentIndex.'&submitTranslationsErrors=1&lang='.$lang.'&token='.$this->token.'" class="form">
  1089. <input type="submit" name="submitTranslationsErrors" value="'.$this->l('Update translations').'" class="button" /><br /><br />
  1090. <table cellpadding="0" cellspacing="0" class="table">';
  1091. ksort($stringToTranslate);
  1092. foreach ($stringToTranslate AS $key => $value)
  1093. $str_output .= '<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: 380px"></td></tr>';
  1094. $str_output .= '</table><br /><input type="submit" name="submitTranslationsErrors" value="'.$this->l('Update translations').'" class="button" /></form>';
  1095. }
  1096. echo $str_output;
  1097. }
  1098. public function displayFormFields($lang)
  1099. {
  1100. global $currentIndex;
  1101. $_FIELDS = $this->fileExists(_PS_TRANSLATIONS_DIR_.$lang, 'fields.php', '_FIELDS');
  1102. $str_output = '';
  1103. $classArray = array();
  1104. $count = 0;
  1105. foreach (scandir(_PS_CLASS_DIR_) AS $classFile)
  1106. {
  1107. if (!preg_match('/\.php$/', $classFile) OR $classFile == 'index.php')
  1108. continue;
  1109. include_once(_PS_CLASS_DIR_.$classFile);
  1110. $className = substr($classFile, 0, -4);
  1111. if (!class_exists($className))
  1112. continue;
  1113. if (!is_subclass_of($className, 'ObjectModel'))
  1114. continue;
  1115. $classArray[$className] = call_user_func(array($className, 'getValidationRules'), $className);
  1116. if (isset($classArray[$className]['validate']))
  1117. $count += sizeof($classArray[$className]['validate']);
  1118. if (isset($classArray[$className]['validateLang']))
  1119. $count += sizeof($classArray[$className]['validateLang']);
  1120. }
  1121. $str_output .= $this->displayAutoTranslate();
  1122. $str_output .= '
  1123. <h2>'.$this->l('Language').' : '.Tools::strtoupper($lang).' - '.$this->l('Field name translations').'</h2>';
  1124. $str_output .= $this->displayLimitPostWarning($count);
  1125. if (!$this->suhosin_limit_exceed)
  1126. {
  1127. $str_output .= $this->l('Fields to translate').' : <b>'.$count.'</b>. '.$this->l('Click on the titles to open fieldsets').'.<br /><br />
  1128. <form method="post" action="'.$currentIndex.'&submitTranslationsFields=1&token='.$this->token.'" class="form">';
  1129. $str_output .= $this->displayToggleButton();
  1130. $str_output .= '<input type="hidden" name="lang" value="'.$lang.'" /><input type="submit" name="submitTranslationsFields" value="'.$this->l('Update translations').'" class="button" /><br /><br />';
  1131. foreach ($classArray AS $className => $rules)
  1132. {
  1133. $translated = 0;
  1134. $toTranslate = 0;
  1135. if (isset($rules['validate']))
  1136. foreach ($rules['validate'] AS $key => $value)
  1137. (array_key_exists($className.'_'.md5($key), $_FIELDS)) ? ++$translated : ++$toTranslate;
  1138. if (isset($rules['validateLang']))
  1139. foreach ($rules['validateLang'] AS $key => $value)
  1140. (array_key_exists($className.'_'.md5($key), $_FIELDS)) ? ++$translated : ++$toTranslate;
  1141. $str_output .= '
  1142. <fieldset><legend style="cursor : pointer" onclick="$(\'#'.$className.'-tpl\').slideToggle();">'.$className.' - <font color="blue">'.($toTranslate + $translated).'</font> '.$this->l('fields').' (<font color="red">'.$toTranslate.'</font>)</legend>
  1143. <div name="fields_div" id="'.$className.'-tpl" style="display: '.($toTranslate ? 'block' : 'none').';">
  1144. <table cellpadding="2">';
  1145. if (isset($rules['validate']))
  1146. foreach ($rules['validate'] AS $key => $value)
  1147. $str_output .= '<tr><td style="text-align:right;width:200px;">'.stripslashes($key).'</td><td style="width: 680px">= <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: 620px"></td></tr>';
  1148. if (isset($rules['validateLang']))
  1149. foreach ($rules['validateLang'] AS $key => $value)
  1150. $str_output .= '<tr><td style="text-align:right;width:200px;">'.stripslashes($key).'</td><td style="width: 680px">= <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: 620px"></td></tr>';
  1151. $str_output .= '
  1152. </table>
  1153. </div>
  1154. </fieldset><br />';
  1155. }
  1156. $str_output .= '<br /><input type="submit" name="submitTranslationsFields" value="'.$this->l('Update translations').'" class="button" /></form>';
  1157. }
  1158. echo $str_output;
  1159. }
  1160. /**
  1161. * Get each informations for each mails founded in the folder $dir.
  1162. *
  1163. * @since 1.4.0.14
  1164. * @param string $dir
  1165. * @param string $lang
  1166. * @param $string $group_name
  1167. */
  1168. public function getMailFiles($dir, $lang, $group_name = 'mail')
  1169. {
  1170. $arr_return = array();
  1171. // Very usefull to name input and textarea fields
  1172. $arr_return['group_name'] = $group_name;
  1173. $arr_return['empty_values'] = 0;
  1174. $arr_return['total_filled'] = 0;
  1175. $arr_return['directory'] = $dir;
  1176. // $arr_return['subject'] = $this->getSubjectMailContent($dir.$lang);
  1177. if(file_exists($dir.'en'))
  1178. {
  1179. // Get all english files to compare with the language to translate
  1180. foreach (scandir($dir.'en') AS $email_file)
  1181. {
  1182. if (strripos($email_file, '.html') > 0 || strripos($email_file, '.txt') > 0)
  1183. {
  1184. $email_name = substr($email_file, 0, strripos($email_file, '.'));
  1185. $type = substr($email_file, strripos($email_file, '.')+1);
  1186. if (!isset($arr_return['files'][$email_name])) {
  1187. $arr_return['files'][$email_name] = array();
  1188. }
  1189. $arr_return['files'][$email_name][$type]['en'] = $this->getMailContent($dir, $email_file, 'en');
  1190. // check if the file exists in the language to translate
  1191. if (file_exists($dir.$lang.'/'.$email_file)) {
  1192. $arr_return['files'][$email_name][$type][$lang] = $this->getMailContent($dir, $email_file, $lang);
  1193. } else {
  1194. $arr_return['files'][$email_name][$type][$lang] = '';
  1195. }
  1196. if ($arr_return['files'][$email_name][$type][$lang] == '') {
  1197. $arr_return['empty_values']++;
  1198. } else {
  1199. $arr_return['total_filled']++;
  1200. }
  1201. }
  1202. }
  1203. }
  1204. return $arr_return;
  1205. }
  1206. /**
  1207. * Get content of the mail file.
  1208. *
  1209. * @since 1.4.0.14
  1210. * @param string $dir
  1211. * @param string $file
  1212. * @param string $lang iso code of a language
  1213. */
  1214. protected function getMailContent($dir, $file, $lang)
  1215. {
  1216. $arr_return = array();
  1217. $content = file_get_contents($dir.$lang.'/'.$file);
  1218. if (Tools::strlen($content) === 0) {
  1219. $content = '';
  1220. }
  1221. return $content;
  1222. }
  1223. /**
  1224. * Display mails in html format.
  1225. * This was create for factorize the html displaying
  1226. *
  1227. * @since 1.4.0.14
  1228. * @param array $mails
  1229. * @param array $all_subject_mail
  1230. * @param Language $obj_lang
  1231. * @param string $id_html use for set html id attribute for the block
  1232. * @param string $title Set the title for the block
  1233. * @param string|boolean $name_for_module is not false define add a name for disntiguish mails module
  1234. */
  1235. protected function displayMailContent($mails, $all_subject_mail, $obj_lang, $id_html, $title, $name_for_module = false)
  1236. {
  1237. $str_return = '';
  1238. $group_name = 'mail';
  1239. if (key_exists('group_name', $mails))
  1240. {
  1241. $group_name = $mails['group_name'];
  1242. }
  1243. $str_return .= '
  1244. <div class="mails_field" >
  1245. <h3 style="cursor : pointer" onclick="$(\'#'.$id_html.'\').slideToggle();">'.$title.' - <font color="red">'.$mails['empty_values'].'</font> '
  1246. .sprintf($this->l('missing translation(s) on %s template(s) for %s'), '<font color="blue">'.((int)$mails['empty_values']+(int)$mails['total_filled']).'</font>', $obj_lang->name)
  1247. .':</h3>
  1248. <div name="mails_div" id="'.$id_html.'">';
  1249. if (!empty($mails['files']))
  1250. {
  1251. foreach ($mails['files'] AS $mail_name => $mail_files)
  1252. {
  1253. if ((key_exists('html', $mail_files) OR key_exists('txt', $mail_files)))
  1254. {
  1255. if (key_exists($mail_name, $all_subject_mail))
  1256. {
  1257. $subject_mail = $all_subject_mail[$mail_name];
  1258. $str_return .= '
  1259. <div class="label-subject" style="text-align:center;">
  1260. <label style="text-align:right">'.sprintf($this->l('Subject for %s:'), '<em>'.$mail_name.'</em>').'</label>
  1261. <div class="mail-form" style="text-align:left">
  1262. <b>'.$subject_mail.'</b><br />
  1263. <input type="text" name="subject['.$group_name.']['.$subject_mail.']" value="'.(isset($mails['subject'][$subject_mail]) ? $mails['subject'][$subject_mail] : '').'" />
  1264. </div>
  1265. </div>';
  1266. } else {
  1267. $str_return .= '
  1268. <div class="label-subject">
  1269. <b>'.sprintf($this->l('No Subject was found for %s.'), '<em>'.$mail_name.'</em>').'</b>'
  1270. .'</div>';
  1271. }
  1272. if (key_exists('html', $mail_files))
  1273. {
  1274. $base_uri = str_replace(_PS_ROOT_DIR_, __PS_BASE_URI__, $mails['directory']);
  1275. $base_uri = str_replace('//', '/', $base_uri);
  1276. $url_mail = $base_uri.$obj_lang->iso_code.'/'.$mail_name.'.html';
  1277. $str_return .= $this->displayMailBlockHtml($mail_files['html'], $obj_lang->iso_code, $url_mail, $mail_name, $group_name, $name_for_module);
  1278. }
  1279. if (key_exists('txt', $mail_files)) {
  1280. $str_return .= $this->displayMailBlockTxt($mail_files['txt'], $obj_lang->iso_code, $mail_name, $group_name, $name_for_module);
  1281. }
  1282. }
  1283. }
  1284. }
  1285. else
  1286. {
  1287. $str_return .= '
  1288. <p class="error">'.$this->l('There is a problem getting the Mail files.').'<br />'
  1289. .sprintf($this->l('Please ensure that English files exist in %s folder'), '<em>'.$mails['directory'].'en</em>')
  1290. .'</p>';
  1291. }
  1292. $str_return .= '
  1293. </div><!-- #'.$id_html.' -->
  1294. <div class="clear"></div>
  1295. </div>';
  1296. return $str_return;
  1297. }
  1298. /**
  1299. * Just build the html structure for display txt mails
  1300. *
  1301. * @since 1.4.0.14
  1302. * @param array $content with english and language needed contents
  1303. * @param string $lang iso code of the needed language
  1304. * @param string $mail_name name of the file to translate (same for txt and html files)
  1305. * @param string $group_name group name allow to distinguish each block of mail.
  1306. * @param string|boolean $name_for_module is not false define add a name for disntiguish mails module
  1307. */
  1308. protected function displayMailBlockTxt($content, $lang, $mail_name, $group_name, $name_for_module = false)
  1309. {
  1310. return '
  1311. <div class="block-mail" >
  1312. <label>'.$mail_name.'.txt</label>
  1313. <div class="mail-form">
  1314. <div><textarea class="rte mailrte noEditor" cols="80" rows="30" name="'.$group_name.'[txt]['.($name_for_module ? $name_for_module.'|' : '' ).$mail_name.']" style="width:560px;margin=0;">'.Tools::htmlentitiesUTF8(stripslashes(strip_tags($content[$lang]))).'</textarea></div>
  1315. </div><!-- .mail-form -->
  1316. </div><!-- .block-mail -->';
  1317. }
  1318. /**
  1319. * Just build the html structure for display html mails.
  1320. *
  1321. * @since 1.4.0.14
  1322. * @param array $content with english and language needed contents
  1323. * @param string $lang iso code of the needed language
  1324. * @param string $url for the html page and displaying an outline
  1325. * @param string $mail_name name of the file to translate (same for txt and html files)
  1326. * @param string $group_name group name allow to distinguish each block of mail.
  1327. * @param string|boolean $name_for_module is not false define add a name for disntiguish mails module
  1328. */
  1329. protected function displayMailBlockHtml($content, $lang, $url, $mail_name, $group_name, $name_for_module = false)
  1330. {
  1331. $title = array();
  1332. // Because TinyMCE don't work correctly with <DOCTYPE>, <html> and <body> tags
  1333. if (stripos($content[$lang], '<body'))
  1334. {
  1335. $array_lang = $lang != 'en' ? array('en', $lang) : array($lang);
  1336. foreach ($array_lang as $language)
  1337. {
  1338. $title[$language] = substr($content[$language], 0, stripos($content[$language], '<body'));
  1339. preg_match('#<title>([^<]+)</title>#Ui', $title[$language], $matches);
  1340. $title[$language] = empty($matches[1])?'':$matches[1];
  1341. // The 2 lines below allow to exlude <body> tag from the content.
  1342. // This allow to exclude body tag even if attributs are setted.
  1343. $content[$language] = substr($content[$language], stripos($content[$language], '<body')+5);
  1344. $content[$language] = substr($content[$language], stripos($content[$language], '>')+1);
  1345. $content[$language] = substr($content[$language], 0, stripos($content[$language], '</body>'));
  1346. }
  1347. }
  1348. $str_return = '';
  1349. $str_return .= '
  1350. <div class="block-mail" >
  1351. <label>'.$mail_name.'.html</label>
  1352. <div class="mail-form">
  1353. <div>';
  1354. $str_return .= '
  1355. <div class="label-subject">
  1356. <b>'.$this->l('"title" tag:').'</b>&nbsp;'.(isset($title['en']) ? $title['en'] : '').'<br />
  1357. <input type="text" name="title_'.$group_name.'_'.$mail_name.'" value="'.(isset($title[$lang]) ? $title[$lang] : '').'" />
  1358. </div><!-- .label-subject -->';
  1359. $str_return .= '
  1360. <iframe style="background:white;border:1px solid #DFD5C3;" border="0" src ="'.$url.'?'.(rand(0,1000000000000)).'" width="565" height="497"></iframe>
  1361. <a style="display:block;margin-top:5px;width:130px;" href="#" onclick="$(this).parent().hide(); displayTiny($(this).parent().next()); return false;" class="button">Edit this mail template</a>
  1362. </div>
  1363. <textarea style="display:none;" class="rte mailrte" cols="80" rows="30" name="'.$group_name.'[html]['.($name_for_module ? $name_for_module.'|' : '' ).$mail_name.']">'.(isset($content[$lang]) ? Tools::htmlentitiesUTF8(stripslashes($content[$lang])) : '').'</textarea>
  1364. </div><!-- .mail-form -->
  1365. </div><!-- .block-mail -->';
  1366. return $str_return;
  1367. }
  1368. /**
  1369. * Check in each module if contains mails folder.
  1370. *
  1371. * @return array of module which has mails
  1372. */
  1373. public function getModulesHasMails()
  1374. {
  1375. $arr_modules = array();
  1376. foreach (scandir(_PS_MODULE_DIR_) AS $module_dir)
  1377. {
  1378. if ($module_dir[0] != '.' AND file_exists(_PS_MODULE_DIR_.$module_dir.'/mails'))
  1379. {
  1380. $arr_modules[$module_dir] = _PS_MODULE_DIR_.$module_dir;
  1381. }
  1382. }
  1383. return $arr_modules;
  1384. }
  1385. protected function getTinyMCEForMails($iso_lang)
  1386. {
  1387. // TinyMCE
  1388. $isoTinyMCE = (file_exists(_PS_ROOT_DIR_.'/js/tiny_mce/langs/'.$iso_lang.'.js') ? $iso_lang : 'en');
  1389. $ad = dirname($_SERVER["PHP_SELF"]);
  1390. return '
  1391. <script type="text/javascript">
  1392. var iso = \''.$isoTinyMCE.'\' ;
  1393. var pathCSS = \''._THEME_CSS_DIR_.'\' ;
  1394. var ad = \''.$ad.'\' ;
  1395. </script>
  1396. <script type="text/javascript" src="'.__PS_BASE_URI__.'js/tiny_mce/tiny_mce.js"></script>
  1397. <script type="text/javascript" src="'.__PS_BASE_URI__.'js/tinymce.inc.js"></script>
  1398. <script type="text/javascript">
  1399. function displayTiny(obj) {
  1400. tinyMCE.get(obj.attr(\'name\')).show();
  1401. }
  1402. </script>';
  1403. }
  1404. public function displayFormMails($lang, $noDisplay = false)
  1405. {
  1406. global $cookie, $currentIndex;
  1407. $core_mails = array();
  1408. $module_mails = array();
  1409. $theme_mails = array();
  1410. $str_output = '';
  1411. // get all mail subjects, this method parse each files in Prestashop !!
  1412. $subject_mail = array();
  1413. $modules_has_mails = $this->getModulesHasMails();
  1414. $arr_files_to_parse = array(
  1415. _PS_ROOT_DIR_.'/controllers',
  1416. _PS_ROOT_DIR_.'/classes',
  1417. PS_ADMIN_DIR.'/tabs',
  1418. );
  1419. $arr_files_to_parse = array_merge($arr_files_to_parse, $modules_has_mails);
  1420. foreach ($arr_files_to_parse as $path) {
  1421. $subject_mail = self::getSubjectMail($path, $subject_mail);
  1422. }
  1423. $core_mails = $this->getMailFiles(_PS_MAIL_DIR_, $lang, 'core_mail');
  1424. $core_mails['subject'] = $this->getSubjectMailContent(_PS_MAIL_DIR_.$lang);
  1425. foreach ($modules_has_mails AS $module_name=>$module_path)
  1426. {
  1427. $module_mails[$module_name] = $this->getMailFiles($module_path.'/mails/', $lang, 'module_mail');
  1428. $module_mails[$module_name]['subject'] = $core_mails['subject'];
  1429. }
  1430. // Before 1.4.0.14 each theme folder was parsed,
  1431. // This page was really to low to load.
  1432. // Now just use the current theme.
  1433. if(_THEME_NAME_ !== AdminTranslations::DEFAULT_THEME_NAME)
  1434. {
  1435. if(file_exists(_PS_THEME_DIR_.'mails'))
  1436. {
  1437. $theme_mails['theme_mail'] = $this->getMailFiles(_PS_THEME_DIR_.'mails/', $lang, 'theme_mail');
  1438. $theme_mails['theme_mail']['subject'] = $this->getSubjectMailContent(_PS_THEME_DIR_.'mails/'.$lang);
  1439. }
  1440. if (file_exists(_PS_THEME_DIR_.'/modules'))
  1441. {
  1442. foreach (scandir(_PS_THEME_DIR_.'/modules') AS $module_dir)
  1443. {
  1444. if ($module_dir[0] != '.' AND file_exists(_PS_THEME_DIR_.'modules/'.$module_dir.'/mails'))
  1445. {
  1446. $theme_mails[$module_dir] = $this->getMailFiles(_PS_THEME_DIR_.'modules/'.$module_dir.'/mails/', $lang, 'theme_module_mail');
  1447. $theme_mails[$module_dir]['subject'] = $theme_mails['theme_mail']['subject'];
  1448. }
  1449. }
  1450. }
  1451. }
  1452. if ($noDis