* @copyright 2007-2014 PrestaShop SA * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) * International Registered Trademark & Property of PrestaShop SA */ class LanguageCore extends ObjectModel { public $id; /** @var string Name */ public $name; /** @var string 2-letter iso code */ public $iso_code; /** @var string 5-letter iso code */ public $language_code; /** @var string date format http://http://php.net/manual/en/function.date.php with the date only */ public $date_format_lite = 'Y-m-d'; /** @var string date format http://http://php.net/manual/en/function.date.php with hours and minutes */ public $date_format_full = 'Y-m-d H:i:s'; /** @var bool true if this language is right to left language */ public $is_rtl = false; /** @var boolean Status */ public $active = true; /** * @see ObjectModel::$definition */ public static $definition = array( 'table' => 'lang', 'primary' => 'id_lang', 'fields' => array( 'name' => array('type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 32), 'iso_code' => array('type' => self::TYPE_STRING, 'validate' => 'isLanguageIsoCode', 'required' => true, 'size' => 2), 'language_code' => array('type' => self::TYPE_STRING, 'validate' => 'isLanguageCode', 'size' => 5), 'active' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'is_rtl' => array('type' => self::TYPE_BOOL, 'validate' => 'isBool'), 'date_format_lite' => array('type' => self::TYPE_STRING, 'validate' => 'isPhpDateFormat', 'required' => true, 'size' => 32), 'date_format_full' => array('type' => self::TYPE_STRING, 'validate' => 'isPhpDateFormat', 'required' => true, 'size' => 32), ), ); /** @var array Languages cache */ protected static $_checkedLangs; protected static $_LANGUAGES; protected static $countActiveLanguages = array(); protected $webserviceParameters = array( 'objectNodeName' => 'language', 'objectsNodeName' => 'languages', ); protected $translationsFilesAndVars = array( 'fields' => '_FIELDS', 'errors' => '_ERRORS', 'admin' => '_LANGADM', 'pdf' => '_LANGPDF', 'tabs' => 'tabs', ); public function __construct($id = null, $id_lang = null) { parent::__construct($id); } /** * @see ObjectModel::getFields() * @return array */ public function getFields() { $this->iso_code = strtolower($this->iso_code); if (empty($this->language_code)) $this->language_code = $this->iso_code; return parent::getFields(); } /** * Generate translations files * */ protected function _generateFiles($newIso = null) { $iso_code = $newIso ? $newIso : $this->iso_code; if (!file_exists(_PS_TRANSLATIONS_DIR_.$iso_code)) { if (@mkdir(_PS_TRANSLATIONS_DIR_.$iso_code)) @chmod(_PS_TRANSLATIONS_DIR_.$iso_code, 0777); } foreach ($this->translationsFilesAndVars as $file => $var) { $path_file = _PS_TRANSLATIONS_DIR_.$iso_code.'/'.$file.'.php'; if (!file_exists($path_file)) if ($file != 'tabs') @file_put_contents($path_file, ''); else @file_put_contents($path_file, ''); @chmod($path_file, 0777); } } /** * Move translations files after editing language iso code */ public function moveToIso($newIso) { if ($newIso == $this->iso_code) return true; if (file_exists(_PS_TRANSLATIONS_DIR_.$this->iso_code)) rename(_PS_TRANSLATIONS_DIR_.$this->iso_code, _PS_TRANSLATIONS_DIR_.$newIso); if (file_exists(_PS_MAIL_DIR_.$this->iso_code)) rename(_PS_MAIL_DIR_.$this->iso_code, _PS_MAIL_DIR_.$newIso); $modulesList = Module::getModulesDirOnDisk(); foreach ($modulesList as $moduleDir) { if (file_exists(_PS_MODULE_DIR_.$moduleDir.'/mails/'.$this->iso_code)) rename(_PS_MODULE_DIR_.$moduleDir.'/mails/'.$this->iso_code, _PS_MODULE_DIR_.$moduleDir.'/mails/'.$newIso); if (file_exists(_PS_MODULE_DIR_.$moduleDir.'/'.$this->iso_code.'.php')) rename(_PS_MODULE_DIR_.$moduleDir.'/'.$this->iso_code.'.php', _PS_MODULE_DIR_.$moduleDir.'/'.$newIso.'.php'); } foreach (Theme::getThemes() as $theme) { $theme_dir = $theme->directory; if (file_exists(_PS_ALL_THEMES_DIR_.$theme_dir.'/lang/'.$this->iso_code.'.php')) rename(_PS_ALL_THEMES_DIR_.$theme_dir.'/lang/'.$this->iso_code.'.php', _PS_ALL_THEMES_DIR_.$theme_dir.'/lang/'.$newIso.'.php'); if (file_exists(_PS_ALL_THEMES_DIR_.$theme_dir.'/mails/'.$this->iso_code)) rename(_PS_ALL_THEMES_DIR_.$theme_dir.'/mails/'.$this->iso_code, _PS_ALL_THEMES_DIR_.$theme_dir.'/mails/'.$newIso); foreach ($modulesList as $module) if (file_exists(_PS_ALL_THEMES_DIR_.$theme_dir.'/modules/'.$module.'/'.$this->iso_code.'.php')) rename(_PS_ALL_THEMES_DIR_.$theme_dir.'/modules/'.$module.'/'.$this->iso_code.'.php', _PS_ALL_THEMES_DIR_.$theme_dir.'/modules/'.$module.'/'.$newIso.'.php'); } } /** * Return an array of theme * * @return array([theme dir] => array('name' => [theme name])) * @deprecated */ protected function _getThemesList() { Tools::displayAsDeprecated(); static $themes = array(); if (empty($themes)) { $installed_themes = Theme::getThemes(); foreach ($installed_themes as $theme) $themes[$theme->directory] = array('name' => $theme->name); } return $themes; } public function add($autodate = true, $nullValues = false, $only_add = false) { if (!parent::add($autodate, $nullValues)) return false; if ($only_add) return true; // create empty files if they not exists $this->_generateFiles(); // @todo Since a lot of modules are not in right format with their primary keys name, just get true ... $this->loadUpdateSQL(); return Tools::generateHtaccess(); } public function toggleStatus() { if (!parent::toggleStatus()) return false; return Tools::generateHtaccess(); } public function checkFiles() { return Language::checkFilesWithIsoCode($this->iso_code); } /** * This functions checks if every files exists for the language $iso_code. * Concerned files are those located in translations/$iso_code/ * and translations/mails/$iso_code . * * @param mixed $iso_code * @returntrue if all files exists */ public static function checkFilesWithIsoCode($iso_code) { if (isset(self::$_checkedLangs[$iso_code]) && self::$_checkedLangs[$iso_code]) return true; foreach (array_keys(Language::getFilesList($iso_code, _THEME_NAME_, false, false, false, true)) as $key) if (!file_exists($key)) return false; self::$_checkedLangs[$iso_code] = true; return true; } public static function getFilesList($iso_from, $theme_from, $iso_to = false, $theme_to = false, $select = false, $check = false, $modules = false) { if (empty($iso_from)) die(Tools::displayError()); $copy = ($iso_to && $theme_to) ? true : false; $lPath_from = _PS_TRANSLATIONS_DIR_.(string)$iso_from.'/'; $tPath_from = _PS_ROOT_DIR_.'/themes/'.(string)$theme_from.'/'; $pPath_from = _PS_ROOT_DIR_.'/themes/'.(string)$theme_from.'/pdf/'; $mPath_from = _PS_MAIL_DIR_.(string)$iso_from.'/'; if ($copy) { $lPath_to = _PS_TRANSLATIONS_DIR_.(string)$iso_to.'/'; $tPath_to = _PS_ROOT_DIR_.'/themes/'.(string)$theme_to.'/'; $pPath_to = _PS_ROOT_DIR_.'/themes/'.(string)$theme_to.'/pdf/'; $mPath_to = _PS_MAIL_DIR_.(string)$iso_to.'/'; } $lFiles = array('admin.php', 'errors.php', 'fields.php', 'pdf.php', 'tabs.php'); // Added natives mails files $mFiles = array( 'account.html', 'account.txt', 'backoffice_order.html', 'backoffice_order.txt', 'bankwire.html', 'bankwire.txt', 'cheque.html', 'cheque.txt', 'contact.html', 'contact.txt', 'contact_form.html', 'contact_form.txt', 'credit_slip.html', 'credit_slip.txt', 'download_product.html', 'download_product.txt', 'employee_password.html', 'employee_password.txt', 'forward_msg.html', 'forward_msg.txt', 'guest_to_customer.html', 'guest_to_customer.txt', 'in_transit.html', 'in_transit.txt', 'log_alert.html', 'log_alert.txt', 'newsletter.html', 'newsletter.txt', 'order_canceled.html', 'order_canceled.txt', 'order_conf.html', 'order_conf.txt', 'order_customer_comment.html', 'order_customer_comment.txt', 'order_merchant_comment.html', 'order_merchant_comment.txt', 'order_return_state.html', 'order_return_state.txt', 'outofstock.html', 'outofstock.txt', 'password.html', 'password.txt', 'password_query.html', 'password_query.txt', 'payment.html', 'payment.txt', 'payment_error.html', 'payment_error.txt', 'preparation.html', 'preparation.txt', 'refund.html', 'refund.txt', 'reply_msg.html', 'reply_msg.txt', 'shipped.html', 'shipped.txt', 'test.html', 'test.txt', 'voucher.html', 'voucher.txt', 'voucher_new.html', 'voucher_new.txt', 'order_changed.html', 'order_changed.txt' ); $number = -1; $files = array(); $files_tr = array(); $files_theme = array(); $files_mail = array(); $files_modules = array(); // When a copy is made from a theme in specific language // to an other theme for the same language, // it's avoid to copy Translations, Mails files // and modules files which are not override by theme. if (!$copy || $iso_from != $iso_to) { // Translations files if (!$check || ($check && (string)$iso_from != 'en')) foreach ($lFiles as $file) $files_tr[$lPath_from.$file] = ($copy ? $lPath_to.$file : ++$number); if ($select == 'tr') return $files_tr; $files = array_merge($files, $files_tr); // Mail files if (!$check || ($check && (string)$iso_from != 'en')) $files_mail[$mPath_from.'lang.php'] = ($copy ? $mPath_to.'lang.php' : ++$number); foreach ($mFiles as $file) $files_mail[$mPath_from.$file] = ($copy ? $mPath_to.$file : ++$number); if ($select == 'mail') return $files_mail; $files = array_merge($files, $files_mail); // Modules if ($modules) { $modList = Module::getModulesDirOnDisk(); foreach ($modList as $mod) { $modDir = _PS_MODULE_DIR_.$mod; // Lang file if (file_exists($modDir.'/translations/'.(string)$iso_from.'.php')) $files_modules[$modDir.'/translations/'.(string)$iso_from.'.php'] = ($copy ? $modDir.'/translations/'.(string)$iso_to.'.php' : ++$number); else if (file_exists($modDir.'/'.(string)$iso_from.'.php')) $files_modules[$modDir.'/'.(string)$iso_from.'.php'] = ($copy ? $modDir.'/'.(string)$iso_to.'.php' : ++$number); // Mails files $modMailDirFrom = $modDir.'/mails/'.(string)$iso_from; $modMailDirTo = $modDir.'/mails/'.(string)$iso_to; if (file_exists($modMailDirFrom)) { $dirFiles = scandir($modMailDirFrom); foreach ($dirFiles as $file) if (file_exists($modMailDirFrom.'/'.$file) && $file != '.' && $file != '..' && $file != '.svn') $files_modules[$modMailDirFrom.'/'.$file] = ($copy ? $modMailDirTo.'/'.$file : ++$number); } } if ($select == 'modules') return $files_modules; $files = array_merge($files, $files_modules); } } else if ($select == 'mail' || $select == 'tr') return $files; // Theme files if (!$check || ($check && (string)$iso_from != 'en')) { $files_theme[$tPath_from.'lang/'.(string)$iso_from.'.php'] = ($copy ? $tPath_to.'lang/'.(string)$iso_to.'.php' : ++$number); // Override for pdf files in the theme if (file_exists($pPath_from.'lang/'.(string)$iso_from.'.php')) $files_theme[$pPath_from.'lang/'.(string)$iso_from.'.php'] = ($copy ? $pPath_to.'lang/'.(string)$iso_to.'.php' : ++$number); $module_theme_files = (file_exists($tPath_from.'modules/') ? scandir($tPath_from.'modules/') : array()); foreach ($module_theme_files as $module) if ($module !== '.' && $module != '..' && $module !== '.svn' && file_exists($tPath_from.'modules/'.$module.'/translations/'.(string)$iso_from.'.php')) $files_theme[$tPath_from.'modules/'.$module.'/translations/'.(string)$iso_from.'.php'] = ($copy ? $tPath_to.'modules/'.$module.'/translations/'.(string)$iso_to.'.php' : ++$number); } if ($select == 'theme') return $files_theme; $files = array_merge($files, $files_theme); // Return return $files; } /** * loadUpdateSQL will create default lang values when you create a new lang, based on default id lang * * @return boolean true if succeed */ public function loadUpdateSQL() { $tables = Db::getInstance()->executeS('SHOW TABLES LIKE \''.str_replace('_', '\\_', _DB_PREFIX_).'%\_lang\' '); $langTables = array(); foreach ($tables as $table) foreach ($table as $t) if ($t != _DB_PREFIX_.'configuration_lang') $langTables[] = $t; $return = true; $shops = Shop::getShopsCollection(false); foreach ($shops as $shop) { $id_lang_default = Configuration::get('PS_LANG_DEFAULT', null, $shop->id_shop_group, $shop->id); foreach ($langTables as $name) { preg_match('#^'.preg_quote(_DB_PREFIX_).'(.+)_lang$#i', $name, $m); $identifier = 'id_'.$m[1]; $fields = ''; // We will check if the table contains a column "id_shop" // If yes, we will add "id_shop" as a WHERE condition in queries copying data from default language $shop_field_exists = $primary_key_exists = false; $columns = Db::getInstance()->executeS('SHOW COLUMNS FROM `'.$name.'`'); foreach ($columns as $column) { $fields .= $column['Field'].', '; if ($column['Field'] == 'id_shop') $shop_field_exists = true; if ($column['Field'] == $identifier) $primary_key_exists = true; } $fields = rtrim($fields, ', '); if (!$primary_key_exists) continue; $sql = 'INSERT IGNORE INTO `'.$name.'` ('.$fields.') (SELECT '; // For each column, copy data from default language reset($columns); foreach ($columns as $column) { if ($identifier != $column['Field'] && $column['Field'] != 'id_lang') { $sql .= '( SELECT `'.bqSQL($column['Field']).'` FROM `'.bqSQL($name).'` tl WHERE tl.`id_lang` = '.(int)$id_lang_default.' '.($shop_field_exists ? ' AND tl.`id_shop` = '.(int)$shop->id : '').' AND tl.`'.bqSQL($identifier).'` = `'.bqSQL(str_replace('_lang', '', $name)).'`.`'.bqSQL($identifier).'` ),'; } else $sql .= '`'.bqSQL($column['Field']).'`,'; } $sql = rtrim($sql, ', '); $sql .= ' FROM `'._DB_PREFIX_.'lang` CROSS JOIN `'.bqSQL(str_replace('_lang', '', $name)).'`)'; $return &= Db::getInstance()->execute($sql); } } return $return; } public static function recurseDeleteDir($dir) { if (!is_dir($dir)) return false; if ($handle = @opendir($dir)) { while (false !== ($file = readdir($handle))) if ($file != '.' && $file != '..') { if (is_dir($dir.'/'.$file)) Language::recurseDeleteDir($dir.'/'.$file); elseif (file_exists($dir.'/'.$file)) @unlink($dir.'/'.$file); } closedir($handle); } if (is_writable($dir)) rmdir($dir); } public function delete() { if (!$this->hasMultishopEntries() || Shop::getContext() == Shop::CONTEXT_ALL) { if (empty($this->iso_code)) $this->iso_code = Language::getIsoById($this->id); // Database translations deletion $result = Db::getInstance()->executeS('SHOW TABLES FROM `'._DB_NAME_.'`'); foreach ($result as $row) if (isset($row['Tables_in_'._DB_NAME_]) && !empty($row['Tables_in_'._DB_NAME_]) && preg_match('/'.preg_quote(_DB_PREFIX_).'_lang/', $row['Tables_in_'._DB_NAME_])) if (!Db::getInstance()->execute('DELETE FROM `'.$row['Tables_in_'._DB_NAME_].'` WHERE `id_lang` = '.(int)$this->id)) return false; // Delete tags Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'tag WHERE id_lang = '.(int)$this->id); // Delete search words Db::getInstance()->execute('DELETE FROM '._DB_PREFIX_.'search_word WHERE id_lang = '.(int)$this->id); // Files deletion foreach (Language::getFilesList($this->iso_code, _THEME_NAME_, false, false, false, true, true) as $key => $file) if (file_exists($key)) unlink($key); $modList = scandir(_PS_MODULE_DIR_); foreach ($modList as $mod) { Language::recurseDeleteDir(_PS_MODULE_DIR_.$mod.'/mails/'.$this->iso_code); $files = @scandir(_PS_MODULE_DIR_.$mod.'/mails/'); if (count($files) <= 2) Language::recurseDeleteDir(_PS_MODULE_DIR_.$mod.'/mails/'); if (file_exists(_PS_MODULE_DIR_.$mod.'/'.$this->iso_code.'.php')) { unlink(_PS_MODULE_DIR_.$mod.'/'.$this->iso_code.'.php'); $files = @scandir(_PS_MODULE_DIR_.$mod); if (count($files) <= 2) Language::recurseDeleteDir(_PS_MODULE_DIR_.$mod); } } if (file_exists(_PS_MAIL_DIR_.$this->iso_code)) Language::recurseDeleteDir(_PS_MAIL_DIR_.$this->iso_code); if (file_exists(_PS_TRANSLATIONS_DIR_.$this->iso_code)) Language::recurseDeleteDir(_PS_TRANSLATIONS_DIR_.$this->iso_code); $images = array( '.jpg', '-default-'.ImageType::getFormatedName('thickbox').'.jpg', '-default-'.ImageType::getFormatedName('home').'.jpg', '-default-'.ImageType::getFormatedName('large').'.jpg', '-default-'.ImageType::getFormatedName('medium').'.jpg', '-default-'.ImageType::getFormatedName('small').'.jpg' ); $images_directories = array(_PS_CAT_IMG_DIR_, _PS_MANU_IMG_DIR_, _PS_PROD_IMG_DIR_, _PS_SUPP_IMG_DIR_); foreach ($images_directories as $image_directory) foreach ($images as $image) { if (file_exists($image_directory.$this->iso_code.$image)) unlink($image_directory.$this->iso_code.$image); if (file_exists(_PS_ROOT_DIR_.'/img/l/'.$this->id.'.jpg')) unlink(_PS_ROOT_DIR_.'/img/l/'.$this->id.'.jpg'); } } if (!parent::delete()) return false; return Tools::generateHtaccess(); } public function deleteSelection($selection) { if (!is_array($selection)) die(Tools::displayError()); $result = true; foreach ($selection as $id) { $language = new Language($id); $result = $result && $language->delete(); } return $result; } /** * Return available languages * * @param boolean $active Select only active languages * @return array Languages */ public static function getLanguages($active = true, $id_shop = false) { if (!self::$_LANGUAGES) Language::loadLanguages(); $languages = array(); foreach (self::$_LANGUAGES as $language) { if ($active && !$language['active'] || ($id_shop && !isset($language['shops'][(int)$id_shop]))) continue; $languages[] = $language; } return $languages; } public static function getLanguage($id_lang) { if (!array_key_exists((int)$id_lang, self::$_LANGUAGES)) return false; return self::$_LANGUAGES[(int)($id_lang)]; } /** * Return iso code from id * * @param integer $id_lang Language ID * @return string Iso code */ public static function getIsoById($id_lang) { if (isset(self::$_LANGUAGES[(int)$id_lang]['iso_code'])) return self::$_LANGUAGES[(int)$id_lang]['iso_code']; return false; } /** * Return id from iso code * * @param string $iso_code Iso code * @return integer Language ID */ public static function getIdByIso($iso_code) { if (!Validate::isLanguageIsoCode($iso_code)) die(Tools::displayError('Fatal error: ISO code is not correct').' '.Tools::safeOutput($iso_code)); return Db::getInstance()->getValue('SELECT `id_lang` FROM `'._DB_PREFIX_.'lang` WHERE `iso_code` = \''.pSQL(strtolower($iso_code)).'\''); } public static function getLanguageCodeByIso($iso_code) { if (!Validate::isLanguageIsoCode($iso_code)) die(Tools::displayError('Fatal error: ISO code is not correct').' '.Tools::safeOutput($iso_code)); return Db::getInstance()->getValue('SELECT `language_code` FROM `'._DB_PREFIX_.'lang` WHERE `iso_code` = \''.pSQL(strtolower($iso_code)).'\''); } public static function getLanguageByIETFCode($code) { if (!Validate::isLanguageCode($code)) die(sprintf(Tools::displayError('Fatal error: IETF code %s is not correct'), Tools::safeOutput($code))); // $code is in the form of 'xx-YY' where xx is the language code // and 'YY' a country code identifying a variant of the language. $lang_country = explode('-', $code); // Get the language component of the code $lang = $lang_country[0]; // Find the id_lang of the language. // We look for anything with the correct language code // and sort on equality with the exact IETF code wanted. // That way using only one query we get either the exact wanted language // or a close match. $id_lang = Db::getInstance()->getValue( 'SELECT `id_lang`, IF(language_code = \''.pSQL($code).'\', 0, LENGTH(language_code)) as found FROM `'._DB_PREFIX_.'lang` WHERE LEFT(`language_code`,2) = \''.pSQL($lang).'\' ORDER BY found ASC' ); // Instantiate the Language object if we found it. if ($id_lang) return new Language($id_lang); else return false; } /** * Return array (id_lang, iso_code) * * @param string $iso_code Iso code * @return array Language (id_lang, iso_code) */ public static function getIsoIds($active = true) { return Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS('SELECT `id_lang`, `iso_code` FROM `'._DB_PREFIX_.'lang` '.($active ? 'WHERE active = 1' : '')); } public static function copyLanguageData($from, $to) { $result = Db::getInstance()->executeS('SHOW TABLES FROM `'._DB_NAME_.'`'); foreach ($result as $row) if (preg_match('/_lang/', $row['Tables_in_'._DB_NAME_]) && $row['Tables_in_'._DB_NAME_] != _DB_PREFIX_.'lang') { $result2 = Db::getInstance()->executeS('SELECT * FROM `'.$row['Tables_in_'._DB_NAME_].'` WHERE `id_lang` = '.(int)$from); if (!count($result2)) continue; Db::getInstance()->execute('DELETE FROM `'.$row['Tables_in_'._DB_NAME_].'` WHERE `id_lang` = '.(int)$to); $query = 'INSERT INTO `'.$row['Tables_in_'._DB_NAME_].'` VALUES '; foreach ($result2 as $row2) { $query .= '('; $row2['id_lang'] = $to; foreach ($row2 as $field) $query .= (!is_string($field) && $field == NULL) ? 'NULL,' : '\''.pSQL($field, true).'\','; $query = rtrim($query, ',').'),'; } $query = rtrim($query, ','); Db::getInstance()->execute($query); } return true; } /** * Load all languages in memory for caching */ public static function loadLanguages() { self::$_LANGUAGES = array(); $sql = 'SELECT l.*, ls.`id_shop` FROM `'._DB_PREFIX_.'lang` l LEFT JOIN `'._DB_PREFIX_.'lang_shop` ls ON (l.id_lang = ls.id_lang)'; $result = Db::getInstance()->executeS($sql); foreach ($result as $row) { if (!isset(self::$_LANGUAGES[(int)$row['id_lang']])) self::$_LANGUAGES[(int)$row['id_lang']] = $row; self::$_LANGUAGES[(int)$row['id_lang']]['shops'][(int)$row['id_shop']] = true; } } public function update($nullValues = false) { if (!parent::update($nullValues)) return false; return Tools::generateHtaccess(); } public static function checkAndAddLanguage($iso_code, $lang_pack = false, $only_add = false, $params_lang = null) { if (Language::getIdByIso($iso_code)) return true; // Initialize the language $lang = new Language(); $lang->iso_code = Tools::strtolower($iso_code); $lang->language_code = $iso_code; // Rewritten afterwards if the language code is available $lang->active = true; // If the language pack has not been provided, retrieve it from prestashop.com if (!$lang_pack) $lang_pack = Tools::jsonDecode(Tools::file_get_contents('http://www.prestashop.com/download/lang_packs/get_language_pack.php?version='._PS_VERSION_.'&iso_lang='.$iso_code)); // If a language pack has been found or provided, prefill the language object with the value if ($lang_pack) foreach (get_object_vars($lang_pack) as $key => $value) if ($key != 'iso_code' && isset(Language::$definition['fields'][$key])) $lang->$key = $value; // Use the values given in parameters to override the data retrieved automatically if ($params_lang !== null && is_array($params_lang)) foreach ($params_lang as $key => $value) if ($key != 'iso_code' && isset(Language::$definition['fields'][$key])) $lang->$key = $value; if (!$lang->validateFields() || !$lang->validateFieldsLang() || !$lang->add(true, false, $only_add)) return false; $flag = Tools::file_get_contents('http://www.prestashop.com/download/lang_packs/flags/jpeg/'.$iso_code.'.jpg'); if ($flag != null && !preg_match('//', $flag)) { $file = fopen(_PS_ROOT_DIR_.'/img/l/'.(int)$lang->id.'.jpg', 'w'); if ($file) { fwrite($file, $flag); fclose($file); } else Language::_copyNoneFlag((int)$lang->id); } else Language::_copyNoneFlag((int)$lang->id); $files_copy = array( '/en.jpg', '/en-default-'.ImageType::getFormatedName('thickbox').'.jpg', '/en-default-'.ImageType::getFormatedName('home').'.jpg', '/en-default-'.ImageType::getFormatedName('large').'.jpg', '/en-default-'.ImageType::getFormatedName('medium').'.jpg', '/en-default-'.ImageType::getFormatedName('small').'.jpg', '/en-default-'.ImageType::getFormatedName('scene').'.jpg' ); foreach (array(_PS_CAT_IMG_DIR_, _PS_MANU_IMG_DIR_, _PS_PROD_IMG_DIR_, _PS_SUPP_IMG_DIR_) as $to) foreach ($files_copy as $file) @copy(_PS_ROOT_DIR_.'/img/l'.$file, $to.str_replace('/en', '/'.$iso_code, $file)); return true; } protected static function _copyNoneFlag($id) { return copy(_PS_ROOT_DIR_.'/img/l/none.jpg', _PS_ROOT_DIR_.'/img/l/'.$id.'.jpg'); } protected static $_cache_language_installation = null; public static function isInstalled($iso_code) { if (self::$_cache_language_installation === null) { self::$_cache_language_installation = array(); $result = Db::getInstance()->executeS('SELECT `id_lang`, `iso_code` FROM `'._DB_PREFIX_.'lang`'); foreach ($result as $row) self::$_cache_language_installation[$row['iso_code']] = $row['id_lang']; } return (isset(self::$_cache_language_installation[$iso_code]) ? self::$_cache_language_installation[$iso_code] : false); } public static function countActiveLanguages($id_shop = null) { if (isset(Context::getContext()->shop) && is_object(Context::getContext()->shop) && $id_shop === null) $id_shop = (int)Context::getContext()->shop->id; if (!isset(self::$countActiveLanguages[$id_shop])) self::$countActiveLanguages[$id_shop] = Db::getInstance()->getValue(' SELECT COUNT(DISTINCT l.id_lang) FROM `'._DB_PREFIX_.'lang` l JOIN '._DB_PREFIX_.'lang_shop lang_shop ON (lang_shop.id_lang = l.id_lang AND lang_shop.id_shop = '.(int)$id_shop.') WHERE l.`active` = 1 '); return self::$countActiveLanguages[$id_shop]; } public static function downloadAndInstallLanguagePack($iso, $version = null, $params = null, $install = true) { if (!Validate::isLanguageIsoCode($iso)) return false; if ($version == null) $version = _PS_VERSION_; $lang_pack = false; $lang_pack_ok = false; $errors = array(); $file = _PS_TRANSLATIONS_DIR_.$iso.'.gzip'; if (!$lang_pack_link = Tools::file_get_contents('http://www.prestashop.com/download/lang_packs/get_language_pack.php?version='.$version.'&iso_lang='.Tools::strtolower($iso))) $errors[] = Tools::displayError('Archive cannot be downloaded from prestashop.com.'); elseif (!$lang_pack = Tools::jsonDecode($lang_pack_link)) $errors[] = Tools::displayError('Error occurred when language was checked according to your Prestashop version.'); elseif (empty($lang_pack->error) && ($content = Tools::file_get_contents('http://translations.prestashop.com/download/lang_packs/gzip/'.$lang_pack->version.'/'.Tools::strtolower($lang_pack->iso_code.'.gzip')))) if (!@file_put_contents($file, $content)) { if (is_writable(dirname($file))) { @unlink($file); @file_put_contents($file, $content); } elseif (!is_writable($file)) $errors[] = Tools::displayError('Server does not have permissions for writing.').' ('.$file.')'; } if (!file_exists($file)) $errors[] = Tools::displayError('No language pack is available for your version.'); elseif ($install) { require_once(_PS_TOOL_DIR_.'tar/Archive_Tar.php'); $gz = new Archive_Tar($file, true); $files_list = AdminTranslationsController::filterTranslationFiles(Language::getLanguagePackListContent($iso, $gz)); $files_paths = AdminTranslationsController::filesListToPaths($files_list); $i = 0; $tmp_array = array(); foreach($files_paths as $files_path) { $path = dirname($files_path); if (is_dir(_PS_TRANSLATIONS_DIR_.'../'.$path) && !is_writable(_PS_TRANSLATIONS_DIR_.'../'.$path) && !in_array($path, $tmp_array)) { $errors[] = (!$i++? Tools::displayError('The archive cannot be extracted.').' ' : '').Tools::displayError('The server does not have permissions for writing.').' '.sprintf(Tools::displayError('Please check rights for %s'), $path); $tmp_array[] = $path; } } if (defined('_PS_HOST_MODE_')) { $mails_files = array(); $other_files = array(); foreach ($files_list as $key => $data) if (substr($data['filename'], 0, 5) == 'mails') $mails_files[] = $data; else $other_files[] = $data; $files_list = $other_files; if (!$gz->extractList(AdminTranslationsController::filesListToPaths($mails_files), _PS_CORE_DIR_)) $errors[] = Tools::displayError('Cannot decompress the translation mail file for the following language:').' '.(string)$iso; } if (!$gz->extractList(AdminTranslationsController::filesListToPaths($files_list), _PS_TRANSLATIONS_DIR_.'../')) $errors[] = Tools::displayError('Cannot decompress the translation file for the following language:').' '.(string)$iso; // Clear smarty modules cache Tools::clearCache(); if (!Language::checkAndAddLanguage((string)$iso, $lang_pack, false, $params)) $errors[] = Tools::displayError('An error occurred while creating the language: ').(string)$iso; else { // Reset cache Language::loadLanguages(); AdminTranslationsController::checkAndAddMailsFiles($iso, $files_list); AdminTranslationsController::addNewTabs($iso, $files_list); } } return count($errors) ? $errors : true; } /** * Check if more on than one language is activated * * @since 1.5.0 * @return bool */ public static function isMultiLanguageActivated($id_shop = null) { return (Language::countActiveLanguages($id_shop) > 1); } public static function getLanguagePackListContent($iso, $tar) { $key = 'Language::getLanguagePackListContent_'.$iso; if (!Cache::isStored($key)) { if (!$tar instanceof Archive_Tar) return false; Cache::store($key, $tar->listContent()); } return Cache::retrieve($key); } public static function updateModulesTranslations(Array $modules_list) { require_once(_PS_TOOL_DIR_.'tar/Archive_Tar.php'); $languages = Language::getLanguages(false); foreach ($languages as $lang) { $gz = false; $files_listing = array(); foreach ($modules_list as $module_name) { $filegz = _PS_TRANSLATIONS_DIR_.$lang['iso_code'].'.gzip'; clearstatcache(); if (@filemtime($filegz) < (time() - (24 * 3600))) if (Language::downloadAndInstallLanguagePack($lang['iso_code'], null, null, false) !== true) break; $gz = new Archive_Tar($filegz, true); $files_list = Language::getLanguagePackListContent($lang['iso_code'], $gz); foreach ($files_list as $i => $file) if (strpos($file['filename'], 'modules/'.$module_name.'/') !== 0) unset($files_list[$i]); foreach ($files_list as $file) if (isset($file['filename']) && is_string($file['filename'])) $files_listing[] = $file['filename']; } if ($gz) $gz->extractList($files_listing, _PS_TRANSLATIONS_DIR_.'../', ''); } } }