PageRenderTime 60ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/controllers/admin/AdminTranslationsController.php

https://bitbucket.org/yhjohn/ayanapure.com
PHP | 2591 lines | 1835 code | 302 blank | 454 comment | 358 complexity | 843b8fbac240f4a7e92a45a2b1eabce9 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /*
  3. * 2007-2012 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-2012 PrestaShop SA
  23. * @version Release: $Revision: 7310 $
  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. define ('TEXTAREA_SIZED', 70);
  28. class AdminTranslationsControllerCore extends AdminController
  29. {
  30. /** Name of theme by default */
  31. const DEFAULT_THEME_NAME = 'default';
  32. /** @var string : Link which list all pack of language */
  33. protected $link_lang_pack = 'http://www.prestashop.com/download/lang_packs/get_each_language_pack.php';
  34. /** @var int : number of sentence which can be translated */
  35. protected $total_expression = 0;
  36. /** @var int : number of sentence which aren't translated */
  37. protected $missing_translations = 0;
  38. /** @var array : List of ISO code for all languages */
  39. protected $all_iso_lang = array();
  40. /** @var array */
  41. protected $modules_translations = array();
  42. /** @var array : List of folder which must be ignored */
  43. protected static $ignore_folder = array('.', '..', '.svn', '.htaccess', 'index.php');
  44. /** @var array : List of theme by translation type : FRONT, BACK, ERRORS... */
  45. protected $translations_informations = array();
  46. /** @var array : List of theme by translation type : FRONT, BACK, ERRORS... */
  47. protected $translations_type_for_theme = array('front', 'modules', 'pdf', 'mails');
  48. /** @var array : List of all languages */
  49. protected $languages;
  50. /** @var array : List of all themes */
  51. protected $themes;
  52. /** @var string : Directory of selected theme */
  53. protected $theme_selected;
  54. /** @var string : Name of translations type */
  55. protected $type_selected;
  56. /** @var object : Language for the selected language */
  57. protected $lang_selected;
  58. /** @var boolean : Is true if number of var exceed the suhosin request or post limit */
  59. protected $post_limit_exceed = false;
  60. public function __construct()
  61. {
  62. $this->multishop_context = Shop::CONTEXT_ALL;
  63. parent::__construct();
  64. $this->table = 'translations';
  65. // Include all file for create or read an archive
  66. include_once(_PS_ADMIN_DIR_.'/../tools/tar/Archive_Tar.php');
  67. include_once(_PS_ADMIN_DIR_.'/../tools/pear/PEAR.php');
  68. }
  69. /*
  70. * Set the type which is selected
  71. */
  72. public function setTypeSelected($type_selected)
  73. {
  74. $this->type_selected = $type_selected;
  75. }
  76. /**
  77. * AdminController::initContent() override
  78. * @see AdminController::initContent()
  79. */
  80. public function initContent()
  81. {
  82. if (!is_null($this->type_selected))
  83. {
  84. $method_name = 'initForm'.$this->type_selected;
  85. if (method_exists($this, $method_name))
  86. $this->content = $this->initForm($method_name);
  87. else
  88. {
  89. $this->errors[] = sprintf(Tools::displayError('"%s" does not exist. Maybe you typed the URL manually.'), $this->type_selected);
  90. $this->content = $this->initMain();
  91. }
  92. }
  93. else
  94. $this->content = $this->initMain();
  95. $this->context->smarty->assign(array('content' => $this->content));
  96. }
  97. /**
  98. * This function create vars by default and call the good method for generate form
  99. *
  100. * @param $method_name
  101. * @return call the method $this->method_name()
  102. */
  103. public function initForm($method_name)
  104. {
  105. // Create a title for each translation page
  106. $title = sprintf(
  107. $this->l('%1$s (Language: %2$s, Theme: %3$s)'),
  108. $this->translations_informations[$this->type_selected]['name'],
  109. $this->lang_selected->name,
  110. $this->theme_selected
  111. );
  112. // Set vars for all forms
  113. $this->tpl_view_vars = array(
  114. 'lang' => $this->lang_selected->iso_code,
  115. 'title' => $title,
  116. 'type' => $this->type_selected,
  117. 'theme' => $this->theme_selected,
  118. 'post_limit_exceeded' => $this->post_limit_exceed,
  119. 'url_submit' => self::$currentIndex.'&submitTranslations'.ucfirst($this->type_selected).'=1&token='.$this->token,
  120. 'toggle_button' => $this->displayToggleButton(),
  121. 'textarea_sized' => TEXTAREA_SIZED,
  122. 'auto_translate' => ''
  123. );
  124. // Call method initForm for a type
  125. return $this->{$method_name}();
  126. }
  127. /**
  128. * AdminController::initToolbar() override
  129. * @see AdminController::initToolbar()
  130. */
  131. public function initToolbar()
  132. {
  133. $this->toolbar_btn['save-and-stay'] = array(
  134. 'short' => 'SaveAndStay',
  135. 'href' => '#',
  136. 'desc' => $this->l('Save and stay'),
  137. );
  138. $this->toolbar_btn['save'] = array(
  139. 'href' => '#',
  140. 'desc' => $this->l('Update translations')
  141. );
  142. $this->toolbar_btn['cancel'] = array(
  143. 'href' => self::$currentIndex.'&token='.$this->token,
  144. 'desc' => $this->l('Cancel')
  145. );
  146. }
  147. /**
  148. * Generate the Main page
  149. */
  150. public function initMain()
  151. {
  152. // Block add/update a language
  153. $packs_to_install = array();
  154. $packs_to_update = array();
  155. $token = Tools::getAdminToken('AdminLanguages'.(int)Tab::getIdFromClassName('AdminLanguages').(int)$this->context->employee->id);
  156. $file_name = $this->link_lang_pack.'?version='._PS_VERSION_;
  157. $array_stream_context = array('http' => array('method' => 'GET', 'timeout' => 5));
  158. if ($lang_packs = Tools::file_get_contents($file_name, false, @stream_context_create($array_stream_context)))
  159. // Notice : for php < 5.2 compatibility, Tools::jsonDecode. The second parameter to true will set us
  160. if ($lang_packs != '' && $lang_packs = Tools::jsonDecode($lang_packs, true))
  161. foreach ($lang_packs as $key => $lang_pack)
  162. {
  163. if (!Language::isInstalled($lang_pack['iso_code']))
  164. $packs_to_install[$key] = $lang_pack;
  165. else
  166. $packs_to_update[$key] = $lang_pack;
  167. }
  168. $this->tpl_view_vars = array(
  169. 'theme_default' => self::DEFAULT_THEME_NAME,
  170. 'theme_lang_dir' =>_THEME_LANG_DIR_,
  171. 'token' => $this->token,
  172. 'languages' => $this->languages,
  173. 'translations_type' => $this->translations_informations,
  174. 'translations_type_for_theme' => $this->translations_type_for_theme,
  175. 'packs_to_install' => $packs_to_install,
  176. 'packs_to_update' => $packs_to_update,
  177. 'url_submit' => self::$currentIndex.'&token='.$this->token,
  178. 'themes' => $this->themes,
  179. 'id_theme_current' => $this->context->shop->id_theme,
  180. 'url_create_language' => 'index.php?controller=AdminLanguages&addlang&token='.$token,
  181. );
  182. $this->toolbar_scroll = false;
  183. $this->base_tpl_view = 'main.tpl';
  184. return parent::renderView();
  185. }
  186. /**
  187. * This method merge each arrays of modules translation in the array of modules translations
  188. */
  189. protected function getModuleTranslations()
  190. {
  191. global $_MODULE;
  192. $name_var = $this->translations_informations[$this->type_selected]['var'];
  193. if (!isset($_MODULE) && !isset($GLOBALS[$name_var]))
  194. $GLOBALS[$name_var] = array();
  195. else if (isset($_MODULE))
  196. if (is_array($GLOBALS[$name_var]) && is_array($_MODULE))
  197. $GLOBALS[$name_var] = array_merge($GLOBALS[$name_var], $_MODULE);
  198. else
  199. $GLOBALS[$name_var] = $_MODULE;
  200. }
  201. /**
  202. * This method is only used by AdminTranslations::submitCopyLang().
  203. *
  204. * It try to create folder in new theme.
  205. *
  206. * When a translation file is copied for a module, its translation key is wrong.
  207. * We have to change the translation key and rewrite the file.
  208. *
  209. * @param string $dest file name
  210. * @return bool
  211. */
  212. protected function checkDirAndCreate($dest)
  213. {
  214. $bool = true;
  215. // To get only folder path
  216. $path = dirname($dest);
  217. // If folder wasn't already added
  218. if (!Tools::file_exists_cache($path))
  219. if (!mkdir($path, 0777, true))
  220. {
  221. $bool &= false;
  222. $this->errors[] = sprintf($this->l('Cannot create the folder "%s". Check directory writing permisions.'), $path);
  223. }
  224. return $bool;
  225. }
  226. /**
  227. * Read the Post var and write the translation file.
  228. * This method overwrites the old translation file.
  229. *
  230. * @param bool $override_file : set true if this file is a override
  231. */
  232. protected function writeTranslationFile($override_file = false)
  233. {
  234. $type = Tools::toCamelCase($this->type_selected, true);
  235. $translation_informations = $this->translations_informations[$this->type_selected];
  236. if ($override_file)
  237. $file_path = $translation_informations['override']['dir'].$translation_informations['override']['file'];
  238. else
  239. $file_path = $translation_informations['dir'].$translation_informations['file'];
  240. if (!file_exists($file_path))
  241. throw new PrestaShopException(sprintf(Tools::displayError('This file doesn\'t exists: "%s". Please create this file.'), $file_path));
  242. if ($fd = fopen($file_path, 'w'))
  243. {
  244. // Get value of button save and stay
  245. $save_and_stay = Tools::getValue('submitTranslations'.$type.'AndStay');
  246. // Get language
  247. $lang = strtolower(Tools::getValue('lang'));
  248. // Unset all POST which are not translations
  249. unset(
  250. $_POST['submitTranslations'.$type],
  251. $_POST['submitTranslations'.$type.'AndStay'],
  252. $_POST['lang'],
  253. $_POST['token'],
  254. $_POST['theme'],
  255. $_POST['type']
  256. );
  257. // Get all POST which aren't empty
  258. $to_insert = array();
  259. foreach ($_POST as $key => $value)
  260. if (!empty($value))
  261. $to_insert[$key] = $value;
  262. // translations array is ordered by key (easy merge)
  263. ksort($to_insert);
  264. $tab = $translation_informations['var'];
  265. fwrite($fd, "<?php\n\nglobal \$".$tab.";\n\$".$tab." = array();\n");
  266. foreach ($to_insert as $key => $value)
  267. fwrite($fd, '$'.$tab.'[\''.pSQL($key, true).'\'] = \''.pSQL($value, true).'\';'."\n");
  268. fwrite($fd, "\n?>");
  269. fclose($fd);
  270. // Redirect
  271. if ($save_and_stay)
  272. $this->redirect(true);
  273. else
  274. $this->redirect();
  275. }
  276. else
  277. throw new PrestaShopException(sprintf(Tools::displayError('Cannot write this file: "%s"'), $file_path));
  278. }
  279. public function submitCopyLang()
  280. {
  281. if (!($from_lang = strval(Tools::getValue('fromLang'))) || !($to_lang = strval(Tools::getValue('toLang'))))
  282. $this->errors[] = $this->l('You must select 2 languages in order to copy data from one to another');
  283. else if (!($from_theme = strval(Tools::getValue('fromTheme'))) || !($to_theme = strval(Tools::getValue('toTheme'))))
  284. $this->errors[] = $this->l('You must select 2 themes in order to copy data from one to another');
  285. else if (!Language::copyLanguageData(Language::getIdByIso($from_lang), Language::getIdByIso($to_lang)))
  286. $this->errors[] = $this->l('An error occurred while copying data');
  287. else if ($from_lang == $to_lang && $from_theme == $to_theme)
  288. $this->errors[] = $this->l('Nothing to copy! (same language and theme)');
  289. if (count($this->errors))
  290. return;
  291. $bool = true;
  292. $items = Language::getFilesList($from_lang, $from_theme, $to_lang, $to_theme, false, false, true);
  293. foreach ($items as $source => $dest)
  294. {
  295. $bool &= $this->checkDirAndCreate($dest);
  296. $bool &= @copy($source, $dest);
  297. if (strpos($dest, 'modules') && basename($source) === $from_lang.'.php' && $bool !== false)
  298. $bool &= $this->changeModulesKeyTranslation($dest, $from_theme, $to_theme);
  299. }
  300. if ($bool)
  301. $this->redirect(false, 14);
  302. $this->errors[] = $this->l('A part of the data has been copied but some language files could not be found or copied');
  303. }
  304. /**
  305. * Change the key translation to according it to theme name.
  306. *
  307. * @param string $path
  308. * @param string $theme_from
  309. * @param string $theme_to
  310. * @return boolean
  311. */
  312. public function changeModulesKeyTranslation($path, $theme_from, $theme_to)
  313. {
  314. $content = file_get_contents($path);
  315. $arr_replace = array();
  316. $bool_flag = true;
  317. if (preg_match_all('#\$_MODULE\[\'([^\']+)\'\]#Ui', $content, $matches))
  318. {
  319. foreach ($matches[1] as $key => $value)
  320. $arr_replace[$value] = str_replace($theme_from, $theme_to, $value);
  321. $content = str_replace(array_keys($arr_replace), array_values($arr_replace), $content);
  322. $bool_flag = (file_put_contents($path, $content) === false) ? false : true;
  323. }
  324. return $bool_flag;
  325. }
  326. public function exportTabs()
  327. {
  328. // Get name tabs by iso code
  329. $tabs = Tab::getTabs($this->lang_selected->id);
  330. // Get name of the default tabs
  331. $tabs_default_lang = Tab::getTabs(1);
  332. $tabs_default = array();
  333. foreach ($tabs_default_lang as $tab)
  334. $tabs_default[$tab['class_name']] = pSQL($tab['name']);
  335. // Create content
  336. $content = "<?php\n\n\$tabs = array();";
  337. if (!empty($tabs))
  338. foreach ($tabs as $tab)
  339. if ($tabs_default[$tab['class_name']] != pSQL($tab['name']))
  340. $content .= "\n\$tabs['".$tab['class_name']."'] = '".pSQL($tab['name'])."';";
  341. $content .= "\n\nreturn \$tabs;";
  342. $dir = _PS_TRANSLATIONS_DIR_.$this->lang_selected->iso_code.DIRECTORY_SEPARATOR;
  343. $path = $dir.'tabs.php';
  344. // Check if tabs.php exists for the selected Iso Code
  345. if (!Tools::file_exists_cache($dir))
  346. if (!mkdir($dir, 0777, true))
  347. throw new PrestaShopException('The file '.$dir.' cannot be created.');
  348. if (!file_put_contents($path, $content))
  349. throw new PrestaShopException('File "'.$path.'" doesn\'t exists and cannot be created in '.$dir);
  350. if (!is_writable($path))
  351. $this->displayWarning(sprintf(Tools::displayError('This file must be writable: %s'), $path));
  352. }
  353. public function submitExportLang()
  354. {
  355. if ($this->lang_selected->iso_code && $this->theme_selected)
  356. {
  357. $this->exportTabs();
  358. $items = array_flip(Language::getFilesList($this->lang_selected->iso_code, $this->theme_selected, false, false, false, false, true));
  359. $gz = new Archive_Tar(_PS_TRANSLATIONS_DIR_.'/export/'.$this->lang_selected->iso_code.'.gzip', true);
  360. $file_name = Tools::getCurrentUrlProtocolPrefix().Tools::getShopDomain().__PS_BASE_URI__.'translations/export/'.$this->lang_selected->iso_code.'.gzip';
  361. if ($gz->createModify($items, null, _PS_ROOT_DIR_));
  362. {
  363. ob_start();
  364. header('Pragma: public');
  365. header('Expires: 0');
  366. header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
  367. header('Cache-Control: public');
  368. header('Content-Description: File Transfer');
  369. header('Content-type: application/octet-stream');
  370. header('Content-Disposition: attachment; filename="'.$this->lang_selected->iso_code.'.gzip'.'"');
  371. header('Content-Transfer-Encoding: binary');
  372. ob_end_flush();
  373. @readfile($file_name);
  374. }
  375. $this->errors[] = Tools::displayError('An error occurred while creating archive.');
  376. }
  377. $this->errors[] = Tools::displayError('Please choose a language and a theme.');
  378. }
  379. public static function checkAndAddMailsFiles($iso_code, $files_list)
  380. {
  381. // 1 - Scan mails files
  382. $mails = scandir(_PS_MAIL_DIR_.'en/');
  383. $mails_new_lang = array();
  384. // Get all email files
  385. foreach ($files_list as $file)
  386. {
  387. if (preg_match('#^mails\/([a-z0-9]+)\/#Ui', $file['filename'], $matches))
  388. {
  389. $slash_pos = strrpos($file['filename'], '/');
  390. $mails_new_lang[] = substr($file['filename'], -(strlen($file['filename']) - $slash_pos - 1));
  391. }
  392. }
  393. // Get the difference
  394. $arr_mails_needed = array_diff($mails, $mails_new_lang);
  395. // Add mails files
  396. foreach ($arr_mails_needed as $mail_to_add)
  397. if (!in_array($mail_to_add, self::$ignore_folder))
  398. @copy(_PS_MAIL_DIR_.'en/'.$mail_to_add, _PS_MAIL_DIR_.$iso_code.'/'.$mail_to_add);
  399. // 2 - Scan modules files
  400. $modules = scandir(_PS_MODULE_DIR_);
  401. $module_mail_en = array();
  402. $module_mail_iso_code = array();
  403. foreach ($modules as $module)
  404. {
  405. if (!in_array($module, self::$ignore_folder) && Tools::file_exists_cache(_PS_MODULE_DIR_.$module.'/mails/en/'))
  406. {
  407. $arr_files = scandir(_PS_MODULE_DIR_.$module.'/mails/en/');
  408. foreach ($arr_files as $file)
  409. {
  410. if (!in_array($file, self::$ignore_folder))
  411. {
  412. if (Tools::file_exists_cache(_PS_MODULE_DIR_.$module.'/mails/en/'.$file))
  413. $module_mail_en[] = _PS_MODULE_DIR_.$module.'/mails/ISO_CODE/'.$file;
  414. if (Tools::file_exists_cache(_PS_MODULE_DIR_.$module.'/mails/'.$iso_code.'/'.$file))
  415. $module_mail_iso_code[] = _PS_MODULE_DIR_.$module.'/mails/ISO_CODE/'.$file;
  416. }
  417. }
  418. }
  419. }
  420. // Get the difference in this modules
  421. $arr_modules_mails_needed = array_diff($module_mail_en, $module_mail_iso_code);
  422. // Add mails files for this modules
  423. foreach ($arr_modules_mails_needed as $file)
  424. {
  425. $file_en = str_replace('ISO_CODE', 'en', $file);
  426. $file_iso_code = str_replace('ISO_CODE', $iso_code, $file);
  427. $dir_iso_code = substr($file_iso_code, 0, -(strlen($file_iso_code) - strrpos($file_iso_code, '/') - 1));
  428. if (!file_exists($dir_iso_code))
  429. mkdir($dir_iso_code);
  430. if (Tools::file_exists_cache($file_en))
  431. copy($file_en, $file_iso_code);
  432. }
  433. }
  434. /**
  435. * Move theme translations in selected themes
  436. *
  437. * @param array $files
  438. * @param array $themes_selected
  439. */
  440. public function checkAndAddThemesFiles($files, $themes_selected)
  441. {
  442. foreach ($files as $file)
  443. {
  444. // Check if file is a file theme
  445. if (preg_match('#^themes\/([a-z0-9]+)\/lang\/#Ui', $file['filename'], $matches))
  446. {
  447. $slash_pos = strrpos($file['filename'], '/');
  448. $name_file = substr($file['filename'], -(strlen($file['filename']) - $slash_pos - 1));
  449. $name_default_theme = $matches[1];
  450. $deleted_old_theme = false;
  451. // Get the old file theme
  452. if (file_exists(_PS_THEME_DIR_.'lang/'.$name_file))
  453. $theme_file_old = _PS_THEME_DIR_.'lang/'.$name_file;
  454. else
  455. {
  456. $deleted_old_theme = true;
  457. $theme_file_old = str_replace(self::DEFAULT_THEME_NAME, $name_default_theme, _PS_THEME_DIR_.'lang/'.$name_file);
  458. }
  459. // Move the old file theme in the new folder
  460. foreach ($themes_selected as $theme_name)
  461. if (file_exists($theme_file_old))
  462. copy($theme_file_old, str_replace($name_default_theme, $theme_name, $theme_file_old));
  463. if ($deleted_old_theme)
  464. @unlink($theme_file_old);
  465. }
  466. }
  467. }
  468. /**
  469. * Add new translations tabs by code ISO
  470. *
  471. * @param array $iso_code
  472. * @param array $files
  473. */
  474. public static function addNewTabs($iso_code, $files)
  475. {
  476. foreach ($files as $file)
  477. {
  478. // Check if file is a file theme
  479. if (preg_match('#^translations\/'.$iso_code.'\/tabs.php#Ui', $file['filename'], $matches) && Validate::isLanguageIsoCode($iso_code))
  480. {
  481. // Include array width new translations tabs
  482. $tabs = include _PS_ROOT_DIR_.DIRECTORY_SEPARATOR.$file['filename'];
  483. foreach ($tabs as $class_name => $translations)
  484. {
  485. // Get instance of this tab by class name
  486. $tab = Tab::getInstanceFromClassName($class_name);
  487. //Check if class name exists
  488. if (isset($tab->class_name) && !empty($tab->class_name))
  489. {
  490. $id_lang = Language::getIdByIso($iso_code);
  491. $tab->name[(int)$id_lang] = pSQL($translations);
  492. // Update this tab
  493. $tab->update();
  494. }
  495. }
  496. }
  497. }
  498. }
  499. public function submitImportLang()
  500. {
  501. if (!isset($_FILES['file']['tmp_name']) || !$_FILES['file']['tmp_name'])
  502. $this->errors[] = Tools::displayError('No file selected');
  503. else
  504. {
  505. $gz = new Archive_Tar($_FILES['file']['tmp_name'], true);
  506. $filename = $_FILES['file']['name'];
  507. $iso_code = str_replace(array('.tar.gz', '.gzip'), '', $filename);
  508. if (Validate::isLangIsoCode($iso_code))
  509. {
  510. $themes_selected = Tools::getValue('theme', array(self::DEFAULT_THEME_NAME));
  511. $files_list = $gz->listContent();
  512. if ($gz->extract(_PS_TRANSLATIONS_DIR_.'../', false))
  513. {
  514. AdminTranslationsController::checkAndAddMailsFiles($iso_code, $files_list);
  515. $this->checkAndAddThemesFiles($files_list, $themes_selected);
  516. AdminTranslationsController::addNewTabs($iso_code, $files_list);
  517. if (Validate::isLanguageFileName($filename))
  518. {
  519. if (!Language::checkAndAddLanguage($iso_code))
  520. $conf = 20;
  521. }
  522. $this->redirect(false, (isset($conf) ? $conf : '15'));
  523. }
  524. $this->errors[] = Tools::displayError('Archive cannot be extracted.');
  525. }
  526. else
  527. $this->errors[] = sprintf(Tools::displayError('ISO CODE invalid "%1$s" for the following file: "%2$s"'), $iso_code, $filename);
  528. }
  529. }
  530. public function submitAddLang()
  531. {
  532. $arr_import_lang = explode('|', Tools::getValue('params_import_language')); /* 0 = Language ISO code, 1 = PS version */
  533. if (Validate::isLangIsoCode($arr_import_lang[0]))
  534. {
  535. if ($content = Tools::file_get_contents(
  536. 'http://www.prestashop.com/download/lang_packs/gzip/'.$arr_import_lang[1].'/'.$arr_import_lang[0].'.gzip', false,
  537. @stream_context_create(array('http' => array('method' => 'GET', 'timeout' => 5)))))
  538. {
  539. $file = _PS_TRANSLATIONS_DIR_.$arr_import_lang[0].'.gzip';
  540. if (file_put_contents($file, $content))
  541. {
  542. $gz = new Archive_Tar($file, true);
  543. $files_list = $gz->listContent();
  544. if ($gz->extract(_PS_TRANSLATIONS_DIR_.'../', false))
  545. {
  546. AdminTranslationsController::checkAndAddMailsFiles($arr_import_lang[0], $files_list);
  547. AdminTranslationsController::addNewTabs($arr_import_lang[0], $files_list);
  548. if (!Language::checkAndAddLanguage($arr_import_lang[0]))
  549. $conf = 20;
  550. if (!unlink($file))
  551. $this->errors[] = Tools::displayError('Cannot delete archive');
  552. $this->redirect(false, (isset($conf) ? $conf : '15'));
  553. }
  554. $this->errors[] = Tools::displayError('Archive cannot be extracted.');
  555. if (!unlink($file))
  556. $this->errors[] = Tools::displayError('Cannot delete archive');
  557. }
  558. else
  559. $this->errors[] = Tools::displayError('Server does not have permissions for writing.');
  560. }
  561. else
  562. $this->errors[] = Tools::displayError('Language not found');
  563. }
  564. else
  565. $this->errors[] = Tools::displayError('Invalid parameter');
  566. }
  567. /**
  568. * This method check each file (tpl or php file), get its sentences to translate,
  569. * compare with posted values and write in iso code translation file.
  570. *
  571. * @param string $file_name
  572. * @param array $files
  573. * @param string $theme_name
  574. * @param string $module_name
  575. * @param string|boolean $dir
  576. * @return void
  577. */
  578. protected function findAndWriteTranslationsIntoFile($file_name, $files, $theme_name, $module_name, $dir = false)
  579. {
  580. // These static vars allow to use file to write just one time.
  581. static $cache_file = array();
  582. static $str_write = '';
  583. static $array_check_duplicate = array();
  584. // Default translations and Prestashop overriding themes are distinguish
  585. $is_default = $theme_name === self::DEFAULT_THEME_NAME ? true : false;
  586. // Set file_name in static var, this allow to open and wright the file just one time
  587. if (!isset($cache_file[$theme_name.'-'.$file_name]))
  588. {
  589. $str_write = '';
  590. $cache_file[$theme_name.'-'.$file_name] = true;
  591. if (!Tools::file_exists_cache($file_name))
  592. file_put_contents($file_name, '');
  593. if (!is_writable($file_name))
  594. throw new PrestaShopException(sprintf(
  595. Tools::displayError('Cannot write to the theme\'s language file (%s). Please check write permissions.'),
  596. $file_name
  597. ));
  598. // this string is initialized one time for a file
  599. $str_write .= "<?php\n\nglobal \$_MODULE;\n\$_MODULE = array();\n";
  600. $array_check_duplicate = array();
  601. }
  602. foreach ($files as $file)
  603. {
  604. if (preg_match('/^(.*).(tpl|php)$/', $file) && Tools::file_exists_cache($file_path = $dir.$file) && !in_array($file, self::$ignore_folder))
  605. {
  606. // Get content for this file
  607. $content = file_get_contents($file_path);
  608. // Get file type
  609. $type_file = substr($file, -4) == '.tpl' ? 'tpl' : 'php';
  610. // Parse this content
  611. $matches = $this->userParseFile($content, $this->type_selected, $type_file);
  612. // Write each translation on its module file
  613. $template_name = substr(basename($file), 0, -4);
  614. foreach ($matches as $key)
  615. {
  616. if ($is_default)
  617. {
  618. $post_key = md5(strtolower($module_name).'_'.self::DEFAULT_THEME_NAME.'_'.strtolower($template_name).'_'.md5($key));
  619. $pattern = '\'<{'.strtolower($module_name).'}prestashop>'.strtolower($template_name).'_'.md5($key).'\'';
  620. }
  621. else
  622. {
  623. $post_key = md5(strtolower($module_name).'_'.strtolower($theme_name).'_'.strtolower($template_name).'_'.md5($key));
  624. $pattern = '\'<{'.strtolower($module_name).'}'.strtolower($theme_name).'>'.strtolower($template_name).'_'.md5($key).'\'';
  625. }
  626. if (array_key_exists($post_key, $_POST) && !empty($_POST[$post_key]) && !in_array($pattern, $array_check_duplicate))
  627. {
  628. $array_check_duplicate[] = $pattern;
  629. $str_write .= '$_MODULE['.$pattern.'] = \''.pSQL(str_replace(array("\r\n", "\r", "\n"), ' ', $_POST[$post_key])).'\';'."\n";
  630. $this->total_expression++;
  631. }
  632. }
  633. }
  634. }
  635. if (isset($cache_file[$theme_name.'-'.$file_name]) && $str_write != "<?php\n\nglobal \$_MODULE;\n\$_MODULE = array();\n")
  636. file_put_contents($file_name, $str_write);
  637. }
  638. /**
  639. * Clear the list of module file by type (file or directory)
  640. *
  641. * @param $files : list of files
  642. * @param string $type_clear (file|directory)
  643. * @param string $path
  644. * @return array : list of a good files
  645. */
  646. public function clearModuleFiles($files, $type_clear = 'file', $path = '')
  647. {
  648. // List of directory which not must be parsed
  649. $arr_exclude = array('img', 'js', 'mails');
  650. // List of good extention files
  651. $arr_good_ext = array('.tpl', '.php');
  652. foreach ($files as $key => $file)
  653. {
  654. if ($file{0} === '.' || in_array(substr($file, 0, strrpos($file, '.')), $this->all_iso_lang))
  655. unset($files[$key]);
  656. else if ($type_clear === 'file' && !in_array(substr($file, strrpos($file, '.')), $arr_good_ext))
  657. unset($files[$key]);
  658. else if ($type_clear === 'directory' && (!is_dir($path.$file) || in_array($file, $arr_exclude)))
  659. unset($files[$key]);
  660. }
  661. return $files;
  662. }
  663. /**
  664. * This method get translation for each files of a module,
  665. * compare with global $_MODULES array and fill AdminTranslations::modules_translations array
  666. * With key as English sentences and values as their iso code translations.
  667. *
  668. * @param array $files
  669. * @param string $theme_name
  670. * @param string $module_name
  671. * @param string|boolean $dir
  672. * @param string $iso_code
  673. * @return void
  674. */
  675. protected function findAndFillTranslations($files, $theme_name, $module_name, $dir = false)
  676. {
  677. $name_var = $this->translations_informations[$this->type_selected]['var'];
  678. // added for compatibility
  679. $GLOBALS[$name_var] = array_change_key_case($GLOBALS[$name_var]);
  680. // Default translations and Prestashop overriding themes are distinguish
  681. $is_default = $theme_name === self::DEFAULT_THEME_NAME ? true : false;
  682. // Thank to this var similar keys are not duplicate
  683. // in AndminTranslation::modules_translations array
  684. // see below
  685. $array_check_duplicate = array();
  686. foreach ($files as $file)
  687. {
  688. if ((preg_match('/^(.*).tpl$/', $file) || preg_match('/^(.*).php$/', $file)) && Tools::file_exists_cache($file_path = $dir.$file))
  689. {
  690. // Get content for this file
  691. $content = file_get_contents($file_path);
  692. // Module files can now be ignored by adding this string in a file
  693. if (strpos($content, 'IGNORE_THIS_FILE_FOR_TRANSLATION') !== false)
  694. continue;
  695. // Get file type
  696. $type_file = substr($file, -4) == '.tpl' ? 'tpl' : 'php';
  697. // Parse this content
  698. $matches = $this->userParseFile($content, $this->type_selected, $type_file);
  699. // Write each translation on its module file
  700. $template_name = substr(basename($file), 0, -4);
  701. foreach ($matches as $key)
  702. {
  703. $module_key = '<{'.Tools::strtolower($module_name).'}'.
  704. strtolower($is_default ? 'prestashop' : $theme_name).'>'.Tools::strtolower($template_name).'_'.md5($key);
  705. // to avoid duplicate entry
  706. if (!in_array($module_key, $array_check_duplicate))
  707. {
  708. $array_check_duplicate[] = $module_key;
  709. if (!isset($this->modules_translations[$theme_name][$module_name][$template_name][$key]['trad']))
  710. $this->total_expression++;
  711. if (array_key_exists($module_key, $GLOBALS[$name_var]))
  712. $this->modules_translations[$theme_name][$module_name][$template_name][$key]['trad'] = html_entity_decode($GLOBALS[$name_var][$module_key], ENT_COMPAT, 'UTF-8');
  713. else
  714. {
  715. $this->modules_translations[$theme_name][$module_name][$template_name][$key]['trad'] = '';
  716. $this->missing_translations++;
  717. }
  718. $this->modules_translations[$theme_name][$module_name][$template_name][$key]['use_sprintf'] = $this->checkIfKeyUseSprintf($key);
  719. }
  720. }
  721. }
  722. }
  723. }
  724. /**
  725. * Get list of files which must be parsed by directory and by type of translations
  726. *
  727. * @return array : list of files by directory
  728. */
  729. public function getFileToParseByTypeTranslation()
  730. {
  731. $directories = array();
  732. switch ($this->type_selected)
  733. {
  734. case 'front':
  735. $directories['tpl'] = array(_PS_ALL_THEMES_DIR_.'/' => scandir(_PS_ALL_THEMES_DIR_));
  736. self::$ignore_folder[] = 'modules';
  737. $directories['tpl'] = array_merge($directories['tpl'], $this->listFiles(_PS_THEME_SELECTED_DIR_));
  738. if (Tools::file_exists_cache(_PS_THEME_OVERRIDE_DIR_))
  739. $directories['tpl'] = array_merge($directories['tpl'], $this->listFiles(_PS_THEME_OVERRIDE_DIR_));
  740. break;
  741. case 'back':
  742. $directories = array(
  743. 'php' => array(
  744. _PS_ADMIN_CONTROLLER_DIR_.'/' => scandir(_PS_ADMIN_CONTROLLER_DIR_),
  745. _PS_OVERRIDE_DIR_.'controllers/admin/' => scandir(_PS_OVERRIDE_DIR_.'controllers/admin/'),
  746. _PS_CLASS_DIR_.'helper/' => scandir(_PS_CLASS_DIR_.'helper/'),
  747. _PS_CLASS_DIR_.'controller/' => array('AdminController.php'),
  748. _PS_CLASS_DIR_ => array('PaymentModule.php')
  749. ),
  750. 'tpl' => $this->listFiles(_PS_ADMIN_DIR_.'/themes/'),
  751. 'specific' => array(
  752. _PS_ADMIN_DIR_.'/' => array(
  753. 'header.inc.php',
  754. 'footer.inc.php',
  755. 'index.php',
  756. 'login.php',
  757. 'password.php',
  758. 'functions.php'
  759. )
  760. )
  761. );
  762. // For translate the template which are overridden
  763. if (file_exists(_PS_OVERRIDE_DIR_.'controllers'.DIRECTORY_SEPARATOR.'admin'.DIRECTORY_SEPARATOR.'templates'))
  764. $directories['tpl'] = array_merge($directories['tpl'], $this->listFiles(_PS_OVERRIDE_DIR_.'controllers'.DIRECTORY_SEPARATOR.'admin'.DIRECTORY_SEPARATOR.'templates'));
  765. break;
  766. case 'errors':
  767. $directories['php'] = array(
  768. _PS_ROOT_DIR_.'/' => scandir(_PS_ROOT_DIR_),
  769. _PS_ADMIN_DIR_.'/' => scandir(_PS_ADMIN_DIR_),
  770. _PS_FRONT_CONTROLLER_DIR_ => scandir(_PS_FRONT_CONTROLLER_DIR_),
  771. _PS_ADMIN_CONTROLLER_DIR_ => scandir(_PS_ADMIN_CONTROLLER_DIR_),
  772. _PS_OVERRIDE_DIR_.'controllers/front/' => scandir(_PS_OVERRIDE_DIR_.'controllers/front/'),
  773. _PS_OVERRIDE_DIR_.'controllers/admin/' => scandir(_PS_OVERRIDE_DIR_.'controllers/admin/')
  774. );
  775. // Get all files for folders classes/ and override/classes/ recursively
  776. $directories['php'] = array_merge($directories['php'], $this->listFiles(_PS_CLASS_DIR_, array(), 'php'));
  777. $directories['php'] = array_merge($directories['php'], $this->listFiles(_PS_OVERRIDE_DIR_.'classes/', array(), 'php'));
  778. break;
  779. case 'fields':
  780. $directories['php'] = $this->listFiles(_PS_CLASS_DIR_, array(), 'php');
  781. break;
  782. case 'pdf':
  783. $tpl_theme = Tools::file_exists_cache(_PS_THEME_SELECTED_DIR_.'pdf/') ? scandir(_PS_THEME_SELECTED_DIR_.'pdf/') : array();
  784. $directories = array(
  785. 'php' => array(
  786. _PS_CLASS_DIR_.'pdf/' => scandir(_PS_CLASS_DIR_.'pdf/'),
  787. _PS_OVERRIDE_DIR_.'classes/pdf/' => scandir(_PS_OVERRIDE_DIR_.'classes/pdf/')
  788. ),
  789. 'tpl' => array(
  790. _PS_PDF_DIR_ => scandir(_PS_PDF_DIR_),
  791. _PS_THEME_SELECTED_DIR_.'pdf/' => $tpl_theme
  792. )
  793. );
  794. break;
  795. case 'mails':
  796. $directories['php'] = array(
  797. _PS_FRONT_CONTROLLER_DIR_ => scandir(_PS_FRONT_CONTROLLER_DIR_),
  798. _PS_ADMIN_CONTROLLER_DIR_ => scandir(_PS_ADMIN_CONTROLLER_DIR_),
  799. _PS_OVERRIDE_DIR_.'controllers/front/' => scandir(_PS_OVERRIDE_DIR_.'controllers/front/'),
  800. _PS_OVERRIDE_DIR_.'controllers/admin/' => scandir(_PS_OVERRIDE_DIR_.'controllers/admin/'),
  801. _PS_ADMIN_DIR_.'/' => scandir(_PS_ADMIN_DIR_),
  802. _PS_ADMIN_DIR_.'/tabs/' => scandir(_PS_ADMIN_DIR_.'/tabs')
  803. );
  804. // Get all files for folders classes/ and override/classes/ recursively
  805. $directories['php'] = array_merge($directories['php'], $this->listFiles(_PS_CLASS_DIR_, array(), 'php'));
  806. $directories['php'] = array_merge($directories['php'], $this->listFiles(_PS_OVERRIDE_DIR_.'classes/', array(), 'php'));
  807. $directories['php'] = array_merge($directories['php'], $this->getModulesHasMails());
  808. break;
  809. }
  810. return $directories;
  811. }
  812. /**
  813. * This method parse a file by type of translation and type file
  814. *
  815. * @param $content
  816. * @param $type_translation : front, back, errors, modules...
  817. * @param string|bool $type_file : (tpl|php)
  818. * @return return $matches
  819. */
  820. protected function userParseFile($content, $type_translation, $type_file = false)
  821. {
  822. switch ($type_translation)
  823. {
  824. case 'front':
  825. // Parsing file in Front office
  826. $regex = '/\{l\s*s=\''._PS_TRANS_PATTERN_.'\'(\s*sprintf=.*)?(\s*js=1)?\s*\}/U';
  827. break;
  828. case 'back':
  829. // Parsing file in Back office
  830. if ($type_file == 'php')
  831. $regex = '/this->l\(\''._PS_TRANS_PATTERN_.'\'[\)|\,]/U';
  832. else if ($type_file == 'specific')
  833. $regex = '/translate\(\''._PS_TRANS_PATTERN_.'\'\)/U';
  834. else
  835. $regex = '/\{l\s*s\s*=\''._PS_TRANS_PATTERN_.'\'(\s*sprintf=.*)?(\s*js=1)?(\s*slashes=1)?\s*\}/U';
  836. break;
  837. case 'errors':
  838. // Parsing file for all errors syntax
  839. $regex = '/Tools::displayError\(\''._PS_TRANS_PATTERN_.'\'(,\s*(true|false))?\)/U';
  840. break;
  841. case 'modules':
  842. // Parsing modules file
  843. if ($type_file == 'php')
  844. $regex = '/->l\(\''._PS_TRANS_PATTERN_.'\'(, ?\'(.+)\')?(, ?(.+))?\)/U';
  845. else
  846. $regex = '/\{l\s*s=\''._PS_TRANS_PATTERN_.'\'(\s*sprintf=.*)?(\s*mod=\'.+\')?(\s*js=1)?\s*\}/U';
  847. break;
  848. case 'pdf':
  849. // Parsing PDF file
  850. if ($type_file == 'php')
  851. $regex = '/HTMLTemplate.*::l\(\''._PS_TRANS_PATTERN_.'\'[\)|\,]/U';
  852. else
  853. $regex = '/\{l\s*s=\''._PS_TRANS_PATTERN_.'\'(\s*sprintf=.*)?(\s*js=1)?(\s*pdf=\'true\')?\s*\}/U';
  854. break;
  855. }
  856. preg_match_all($regex, $content, $matches);
  857. return $matches[1];
  858. }
  859. /**
  860. * Get all translations informations for all type of translations
  861. *
  862. * array(
  863. * 'type' => array(
  864. * 'name' => string : title for the translation type,
  865. * 'var' => string : name of var for the translation file,
  866. * 'dir' => string : dir of translation file
  867. * 'file' => string : file name of translation file
  868. * )
  869. * )
  870. */
  871. public function getTranslationsInformations()
  872. {
  873. $this->translations_informations = array(
  874. 'front' => array(
  875. 'name' => $this->l('Front Office translations'),
  876. 'var' => '_LANG',
  877. 'dir' => _PS_THEME_SELECTED_DIR_.'lang/',
  878. 'file' => $this->lang_selected->iso_code.'.php'
  879. ),
  880. 'back' => array(
  881. 'name' => $this->l('Back Office translations'),
  882. 'var' => '_LANGADM',
  883. 'dir' => _PS_TRANSLATIONS_DIR_.$this->lang_selected->iso_code.'/',
  884. 'file' => 'admin.php'
  885. ),
  886. 'errors' => array(
  887. 'name' => $this->l('Error message translations'),
  888. 'var' => '_ERRORS',
  889. 'dir' => _PS_TRANSLATIONS_DIR_.$this->lang_selected->iso_code.'/',
  890. 'file' => 'errors.php'
  891. ),
  892. 'fields' => array(
  893. 'name' => $this->l('Field name translations'),
  894. 'var' => '_FIELDS',
  895. 'dir' => _PS_TRANSLATIONS_DIR_.$this->lang_selected->iso_code.'/',
  896. 'file' => 'fields.php'
  897. ),
  898. 'modules' => array(
  899. 'name' => $this->l('Installed module translations'),
  900. 'var' => '_MODULES',
  901. 'dir' => _PS_MODULE_DIR_,
  902. 'file' => '',
  903. 'override' => array(
  904. 'dir' => _PS_THEME_SELECTED_DIR_.'modules/',
  905. 'file' => ''
  906. )
  907. ),
  908. 'pdf' => array(
  909. 'name' => $this->l('PDF translations'),
  910. 'var' => '_LANGPDF',
  911. 'dir' => _PS_TRANSLATIONS_DIR_.$this->lang_selected->iso_code.'/',
  912. 'file' => 'pdf.php',
  913. 'override' => array(
  914. 'dir' => _PS_THEME_SELECTED_DIR_.'pdf/lang/',
  915. 'file' => $this->lang_selected->iso_code.'.php'
  916. )
  917. ),
  918. 'mails' => array(
  919. 'name' => $this->l('E-mail template translations'),
  920. 'var' => '_LANGMAIL',
  921. 'dir' => _PS_MAIL_DIR_.$this->lang_selected->iso_code.'/',
  922. 'file' => 'lang.php',
  923. 'override' => array(
  924. 'dir' => _PS_THEME_SELECTED_DIR_.'mails/'.$this->lang_selected->iso_code.'/',
  925. 'file' => 'lang.php'
  926. )
  927. )
  928. );
  929. }
  930. /**
  931. * Get all informations on : languages, theme and the translation type.
  932. */
  933. public function getInformations()
  934. {
  935. // Get all Languages
  936. $this->languages = Language::getLanguages(false);
  937. // Get all iso_code of languages
  938. foreach ($this->languages as $language)
  939. $this->all_iso_lang[] = $language['iso_code'];
  940. // Get all themes
  941. $this->themes = Theme::getThemes();
  942. // Get folder name of theme
  943. if (($theme = Tools::getValue('theme')) && !is_array($theme))
  944. $this->theme_selected = Tools::safeOutput($theme);
  945. else
  946. $this->theme_selected = self::DEFAULT_THEME_NAME;
  947. // Set the path of selected theme
  948. define('_PS_THEME_SELECTED_DIR_', _PS_ROOT_DIR_.'/themes/'.$this->theme_selected.'/');
  949. // Get type of translation
  950. if (($type = Tools::getValue('type')) && !is_array($type))
  951. $this->type_selected = strtolower(Tools::safeOutput($type));
  952. // Get selected language
  953. if (Tools::getValue('lang') || Tools::getValue('iso_code'))
  954. {
  955. $iso_code = Tools::getValue('lang') ? Tools::getValue('lang') : Tools::getValue('iso_code');
  956. if (!Validate::isLangIsoCode($iso_code) || !in_array($iso_code, $this->all_iso_lang))
  957. throw new PrestaShopException(sprintf(Tools::displayError('Invalid iso code "%s"'), $iso_code));
  958. $this->lang_selected = new Language((int)Language::getIdByIso($iso_code));
  959. }
  960. else
  961. $this->lang_selected = new Language((int)Language::getIdByIso('en'));
  962. // Get all information for translations
  963. $this->getTranslationsInformations();
  964. }
  965. /**
  966. * AdminController::postProcess() override
  967. * @see AdminController::postProcess()
  968. */
  969. public function postProcess()
  970. {
  971. $this->getInformations();
  972. /* PrestaShop demo mode */
  973. if (_PS_MODE_DEMO_)
  974. {
  975. $this->errors[] = Tools::displayError('This functionality has been disabled.');
  976. return;
  977. }
  978. /* PrestaShop demo mode */
  979. if (Tools::isSubmit('submitCopyLang'))
  980. {
  981. if ($this->tabAccess['add'] === '1')
  982. $this->submitCopyLang();
  983. else
  984. $this->errors[] = Tools::displayError('You do not have permission to add here.');
  985. }
  986. else if (Tools::isSubmit('submitExport'))
  987. {
  988. if ($this->tabAccess['add'] === '1')
  989. $this->submitExportLang();
  990. else
  991. $this->errors[] = Tools::displayError('You do not have permission to add here.');
  992. }
  993. else if (Tools::isSubmit('submitImport'))
  994. {
  995. if ($this->tabAccess['add'] === '1')
  996. $this->submitImportLang();
  997. else
  998. $this->errors[] = Tools::displayError('You do not have permission to add here.');
  999. }
  1000. else if (Tools::isSubmit('submitAddLanguage'))
  1001. {
  1002. if ($this->tabAccess['add'] === '1')
  1003. $this->submitAddLang();
  1004. else
  1005. $this->errors[] = Tools::displayError('You do not have permission to add here.');
  1006. }
  1007. else if (Tools::isSubmit('submitTranslationsFront'))
  1008. {
  1009. if ($this->tabAccess['edit'] === '1')
  1010. $this->writeTranslationFile();
  1011. else
  1012. $this->errors[] = Tools::displayError('You do not have permission to edit here.');
  1013. }
  1014. else if (Tools::isSubmit('submitTranslationsPdf'))
  1015. {
  1016. if ($this->tabAccess['edit'] === '1')
  1017. // Only the PrestaShop team should write the translations into the _PS_TRANSLATIONS_DIR_
  1018. if (($this->theme_selected == self::DEFAULT_THEME_NAME) && _PS_MODE_DEV_)
  1019. $this->writeTranslationFile();
  1020. else
  1021. $this->writeTranslationFile(true);
  1022. else
  1023. $this->errors[] = Tools::displayError('You do not have permission to edit here.');
  1024. }
  1025. else if (Tools::isSubmit('submitTranslationsBack'))
  1026. {
  1027. if ($this->tabAccess['edit'] === '1')
  1028. $this->writeTranslationFile();
  1029. else
  1030. $this->errors[] = Tools::displayError('You do not have permission to edit here.');
  1031. }
  1032. else if (Tools::isSubmit('submitTranslationsErrors'))
  1033. {
  1034. if ($this->tabAccess['edit'] === '1')
  1035. $this->writeTranslationFile();
  1036. else
  1037. $this->errors[] = Tools::displayError('You do not have permission to edit here.');
  1038. }
  1039. else if (Tools::isSubmit('submitTranslationsFields'))
  1040. {
  1041. if ($this->tabAccess['edit'] === '1')
  1042. $this->writeTranslationFile();
  1043. else
  1044. $this->errors[] = Tools::displayError('You do not have permission to edit here.');
  1045. }
  1046. else if (Tools::isSubmit('submitTranslationsMails') || Tools::isSubmit('submitTranslationsMailsAndStay'))
  1047. {
  1048. if ($this->tabAccess['edit'] === '1')
  1049. $this->submitTranslationsMails();
  1050. else
  1051. $this->errors[] = Tools::displayError('You do not have permission to edit here.');
  1052. }
  1053. else if (Tools::isSubmit('submitTranslationsModules'))
  1054. {
  1055. if ($this->tabAccess['edit'] === '1')
  1056. {
  1057. // Get a good path for module directory
  1058. if ($this->theme_selected == self::DEFAULT_THEME_NAME)
  1059. $i18n_dir = $this->translations_informations[$this->type_selected]['dir'];
  1060. else
  1061. $i18n_dir = $this->translations_informations[$this->type_selected]['override']['dir'];
  1062. // Get list of modules
  1063. if ($modules = $this->getListModules())
  1064. {
  1065. // Get files of all modules
  1066. $arr_files = $this->getAllModuleFiles($modules, $i18n_dir, $this->lang_selected->iso_code, true);
  1067. // Find and write all translation modules files
  1068. foreach ($arr_files as $value)
  1069. $this->findAndWriteTranslationsIntoFile($value['file_name'], $value['files'], $value['theme'], $value['module'], $value['dir']);
  1070. // Redirect
  1071. if (Tools::getValue('submitTranslationsModulesAndStay'))
  1072. $this->redirect(true);
  1073. else
  1074. $this->redirect();
  1075. }
  1076. }
  1077. else
  1078. $this->errors[] = Tools::displayError('You do not have permission to edit here.');
  1079. }
  1080. }
  1081. /**
  1082. * This method redirect in the translation main page or in the translation page
  1083. *
  1084. * @param bool $save_and_stay : true if the user has clicked on the button "save and stay"
  1085. * @param bool $conf : id of confirmation message
  1086. */
  1087. protected function redirect($save_and_stay = false, $conf = false)
  1088. {
  1089. $conf = !$conf ? 4 : $conf;
  1090. $url_base = self::$currentIndex.'&token='.$this->token.'&conf='.$conf;
  1091. if ($save_and_stay)
  1092. Tools::redirectAdmin($url_base.'&lang='.$this->lang_selected->iso_code.'&type='.$this->type_selected.'&theme='.$this->theme_selected);
  1093. else
  1094. Tools::redirectAdmin($url_base);
  1095. }
  1096. protected function getMailPattern()
  1097. {
  1098. // Let the indentation like it.
  1099. return '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/1999/REC-html401-19991224/strict.dtd">
  1100. <html>
  1101. <head>
  1102. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  1103. <title>#title</title>
  1104. </head>
  1105. <body>
  1106. #content
  1107. </body>
  1108. </html>';
  1109. }
  1110. /**
  1111. * This method is used to wright translation for mails.
  1112. * This wrights subject translation files
  1113. * (in root/mails/lang_choosen/lang.php or root/_PS_THEMES_DIR_/mails/lang_choosen/lang.php)
  1114. * and mails files.
  1115. */
  1116. protected function submitTranslationsMails()
  1117. {
  1118. $arr_mail_content = array();
  1119. $arr_mail_path = array();
  1120. if (Tools::getValue('core_mail'))
  1121. {
  1122. $arr_mail_content['core_mail'] = Tools::getValue('core_mail');
  1123. // Get path of directory for find a good path of translation file
  1124. if ($this->theme_selected != self::DEFAULT_THEME_NAME)
  1125. $arr_mail_path['core_mail'] = $this->translations_informations[$this->type_selected]['override']['dir'];
  1126. else
  1127. $arr_mail_path['core_mail'] = $this->translations_informations[$this->type_selected]['dir'];
  1128. }
  1129. if (Tools::getValue('module_mail'))
  1130. {
  1131. $arr_mail_content['module_mail'] = Tools::getValue('module_mail');
  1132. // Get path of directory for find a good path of translation file
  1133. if ($this->theme_selected != self::DEFAULT_THEME_NAME)
  1134. $arr_mail_path['module_mail'] = $this->translations_informations['modules']['override']['dir'].'{module}/mails/'.$this->lang_selected->iso_code.'/';
  1135. else
  1136. $arr_mail_path['module_mail'] = $this->translations_informations['modules']['dir'].'{module}/mails/'.$this->lang_selected->iso_code.'/';
  1137. }
  1138. // Save each mail content
  1139. foreach ($arr_mail_content as $group_name => $all_content)
  1140. {
  1141. foreach ($all_content as $type_content => $mails)
  1142. {
  1143. foreach ($mails as $mail_name => $content)
  1144. {
  1145. $module_name = false;
  1146. $module_name_pipe_pos = stripos($mail_name, '|');
  1147. if ($module_name_pipe_pos)
  1148. {
  1149. $module_name = substr($mail_name, 0, $module_name_pipe_pos);
  1150. if (!Validate::isModuleName($module_name))
  1151. throw new PrestaShopException(sprinf(Tools::displayError('Invalid module name "%s"'), $module_name));
  1152. $mail_name = substr($mail_name, $module_name_pipe_pos + 1);
  1153. if (!Validate::isTplName($mail_name))
  1154. throw new PrestaShopException(sprintf(Tools::displayError('Invalid mail name "%s"'), $mail_name));
  1155. }
  1156. if ($type_content == 'html')
  1157. {
  1158. $content = Tools::htmlentitiesUTF8($content);
  1159. $content = htmlspecialchars_decode($content);
  1160. // replace correct end of line
  1161. $content = str_replace("\r\n", PHP_EOL, $content);
  1162. $title = '';
  1163. if (Tools::getValue('title_'.$group_name.'_'.$mail_name))
  1164. $title = Tools::getValue('title_'.$group_name.'_'.$mail_name);
  1165. $string_mail = $this->getMailPattern();
  1166. $content = str_replace(array('#title', '#content'), array($title, $content), $string_mail);
  1167. // Magic Quotes shall... not.. PASS!
  1168. if (_PS_MAGIC_QUOTES_GPC_)
  1169. $content = stripslashes($content);
  1170. }
  1171. if (Validate::isCleanHTML($content))
  1172. {
  1173. $path = $arr_mail_path[$group_name];
  1174. if ($module_name)
  1175. $path = str_replace('{module}', $module_name, $path);
  1176. file_put_contents($path.$mail_name.'.'.$type_content, $content);
  1177. }
  1178. else
  1179. throw new PrestaShopException(Tools::displayError('HTML e-mail templates cannot contain JavaScript code.'));
  1180. }
  1181. }
  1182. }
  1183. // Update subjects
  1184. $array_subjects = array();
  1185. if (($subjects = Tools::getValue('subject')) && is_array($subjects))
  1186. {
  1187. $array_subjects['core_and_modules'] = array('translations'=>array(), 'path'=>$arr_mail_path['core_mail'].'lang.php');
  1188. foreach ($subjects as $subject_translation)
  1189. $array_subjects['core_and_modules']['translations'] = array_merge($array_subjects['core_and_modules']['translations'], $subject_translation);
  1190. }
  1191. if (!empty($array_subjects))
  1192. foreach ($array_subjects as $infos)
  1193. $this->writeSubjectTranslationFile($infos['translations'], $infos['path']);
  1194. if (Tools::isSubmit('submitTranslationsMailsAndStay'))
  1195. $this->redirect(true);
  1196. else
  1197. $this->redirect();
  1198. }
  1199. /**
  1200. * Include file $dir/$file and return the var $var declared in it.
  1201. * This create the file if not exists
  1202. *
  1203. * return array : translations
  1204. */
  1205. public function fileExists()
  1206. {
  1207. $var = $this->translations_informations[$this->type_selected]['var'];
  1208. $dir = $this->translations_informations[$this->type_selected]['dir'];
  1209. $file = $this->translations_informations[$this->type_selected]['file'];
  1210. $$var = array();
  1211. if (!Tools::file_exists_cache($dir))
  1212. if (!mkdir($dir, 0700))
  1213. throw new PrestaShopException('Directory '.$dir.' cannot be created.');
  1214. if (!Tools::file_exists_cache($dir.DIRECTORY_SEPARATOR.$file))
  1215. if (!file_put_contents($dir.'/'.$file, "<?php\n\nglobal \$".$var.";\n\$".$var." = array();\n\n?>"))
  1216. throw new PrestaShopException('File "'.$file.'" doesn\'t exists and cannot be created in '.$dir);
  1217. if (!is_writable($dir.DIRECTORY_SEPARATOR.$file))
  1218. $this->displayWarning(Tools::displayError('This file must be writable:').' '.$dir.'/'.$file);
  1219. include($dir.DIRECTORY_SEPARATOR.$file);
  1220. return $$var;
  1221. }
  1222. public function displayToggleButton($closed = false)
  1223. {
  1224. $str_output = '
  1225. <script type="text/javascript">';
  1226. if (Tools::getValue('type') == 'mails')
  1227. $str_output .= '$(document).ready(function(){
  1228. openCloseAllDiv(\''.$this->type_selected.'_div\', this.value == openAll); toggleElemValue(this.id, openAll, closeAll);
  1229. });';
  1230. $str_output .= '
  1231. var openAll = \''.html_entity_decode($this->l('Expand all fieldsets'), ENT_NOQUOTES, 'UTF-8').'\';
  1232. var closeAll = \''.html_entity_decode($this->l('Close all fieldsets'), ENT_NOQUOTES, 'UTF-8').'\';
  1233. </script>
  1234. <input type="button" class="button" id="buttonall" onclick="openCloseAllDiv(\''.$this->type_selected.'_div\', this.value == openAll); toggleElemValue(this.id, openAll, closeAll);" />
  1235. <script type="text/javascript">toggleElemValue(\'buttonall\', '.($closed ? 'openAll' : 'closeAll').', '.($closed ? 'closeAll' : 'openAll').');</script>';
  1236. return $str_output;
  1237. }
  1238. protected function displaySubmitButtons($name)
  1239. {
  1240. return '
  1241. <input type="submit" name="submitTranslations'.ucfirst($name).'" value="'.$this->l('Update translations').'" class="button" />
  1242. <input type="submit" name="submitTranslations'.ucfirst($name).'AndStay" value="'.$this->l('Update and stay').'" class="button" />';
  1243. }
  1244. /**
  1245. * Init js variables for translation with google
  1246. *
  1247. * @return array of variables to assign to the smarty template
  1248. */
  1249. public function initAutoTranslate()
  1250. {
  1251. $this->addJS('http://www.google.com/jsapi');
  1252. $this->addJS(_PS_JS_DIR_.'gg-translate.js');
  1253. $this->addJS(_PS_JS_DIR_.'admin-translations.js');
  1254. $language_code = Tools::htmlentitiesUTF8(Language::getLanguageCodeByIso(Tools::getValue('lang')));
  1255. return array('language_code' => $language_code,
  1256. 'not_available' => addslashes(html_entity_decode($this->l('this language is not available in Google Translate\'s API'), ENT_QUOTES, 'utf-8')),
  1257. 'tooltip_title' => addslashes(html_entity_decode($th

Large files files are truncated, but you can click here to view the full file