* @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 */ /** * @since 1.5.0 */ class TranslateCore { /** * Get a translation for an admin controller * * @param $string * @param string $class * @param bool $addslashes * @param bool $htmlentities * @return string */ public static function getAdminTranslation($string, $class = 'AdminTab', $addslashes = false, $htmlentities = true, $sprintf = null) { static $modules_tabs = null; // @todo remove global keyword in translations files and use static global $_LANGADM; if ($modules_tabs === null) $modules_tabs = Tab::getModuleTabList(); if ($_LANGADM == null) { $iso = Context::getContext()->language->iso_code; if (empty($iso)) $iso = Language::getIsoById((int)(Configuration::get('PS_LANG_DEFAULT'))); if (file_exists(_PS_TRANSLATIONS_DIR_.$iso.'/admin.php')) include_once(_PS_TRANSLATIONS_DIR_.$iso.'/admin.php'); } if (isset($modules_tabs[strtolower($class)])) { $class_name_controller = $class.'controller'; // if the class is extended by a module, use modules/[module_name]/xx.php lang file if (class_exists($class_name_controller) && Module::getModuleNameFromClass($class_name_controller)) { $string = str_replace('\'', '\\\'', $string); return Translate::getModuleTranslation(Module::$classInModule[$class_name_controller], $string, $class_name_controller); } } $key = md5(str_replace('\'', '\\\'', $string)); if (isset($_LANGADM[$class.$key])) $str = $_LANGADM[$class.$key]; else $str = Translate::getGenericAdminTranslation($string, $key, $_LANGADM); if ($htmlentities) $str = htmlspecialchars($str, ENT_QUOTES, 'utf-8'); $str = str_replace('"', '"', $str); if ($sprintf !== null) $str = Translate::checkAndReplaceArgs($str, $sprintf); return ($addslashes ? addslashes($str) : stripslashes($str)); } /** * Return the translation for a string if it exists for the base AdminController or for helpers * * @static * @param $string string to translate * @param null $key md5 key if already calculated (optional) * @param $lang_array global array of admin translations * @return string translation */ public static function getGenericAdminTranslation($string, $key = null, &$lang_array) { if (is_null($key)) $key = md5(str_replace('\'', '\\\'', $string)); if (isset($lang_array['AdminController'.$key])) $str = $lang_array['AdminController'.$key]; else if (isset($lang_array['Helper'.$key])) $str = $lang_array['Helper'.$key]; else if (isset($lang_array['AdminTab'.$key])) $str = $lang_array['AdminTab'.$key]; else // note in 1.5, some translations has moved from AdminXX to helper/*.tpl $str = $string; return $str; } /** * Get a translation for a module * * @param string|Module $module * @param string $string * @param string $source * @return string */ public static function getModuleTranslation($module, $string, $source, $sprintf = null, $js = false) { global $_MODULES, $_MODULE, $_LANGADM; static $lang_cache = array(); // $_MODULES is a cache of translations for all module. // $translations_merged is a cache of wether a specific module's translations have already been added to $_MODULES static $translations_merged = array(); $name = $module instanceof Module ? $module->name : $module; if (!isset($translations_merged[$name]) && isset(Context::getContext()->language)) { $filesByPriority = array( // Translations in theme _PS_THEME_DIR_.'modules/'.$name.'/translations/'.Context::getContext()->language->iso_code.'.php', _PS_THEME_DIR_.'modules/'.$name.'/'.Context::getContext()->language->iso_code.'.php', // PrestaShop 1.5 translations _PS_MODULE_DIR_.$name.'/translations/'.Context::getContext()->language->iso_code.'.php', // PrestaShop 1.4 translations _PS_MODULE_DIR_.$name.'/'.Context::getContext()->language->iso_code.'.php' ); foreach ($filesByPriority as $file) if (Tools::file_exists_cache($file)) { include_once($file); $_MODULES = !empty($_MODULES) ? $_MODULES + $_MODULE : $_MODULE; //we use "+" instead of array_merge() because array merge erase existing values. $translations_merged[$name] = true; } } $key = md5(str_replace('\'', '\\\'', $string)); $cache_key = $name.'|'.$string.'|'.$source.'|'.(int)$js; if (!isset($lang_cache[$cache_key])) { if ($_MODULES == null) { if ($sprintf !== null) $string = Translate::checkAndReplaceArgs($string, $sprintf); return str_replace('"', '"', $string); } $current_key = strtolower('<{'.$name.'}'._THEME_NAME_.'>'.$source).'_'.$key; $default_key = strtolower('<{'.$name.'}prestashop>'.$source).'_'.$key; if (isset($_MODULES[$current_key])) $ret = stripslashes($_MODULES[$current_key]); elseif (isset($_MODULES[$default_key])) $ret = stripslashes($_MODULES[$default_key]); // if translation was not found in module, look for it in AdminController or Helpers elseif (!empty($_LANGADM)) $ret = Translate::getGenericAdminTranslation($string, $key, $_LANGADM); else $ret = stripslashes($string); if ($sprintf !== null) $ret = Translate::checkAndReplaceArgs($ret, $sprintf); if ($js) $ret = addslashes($ret); else $ret = htmlspecialchars($ret, ENT_COMPAT, 'UTF-8'); if ($sprintf === null) $lang_cache[$cache_key] = $ret; else return $ret; } return $lang_cache[$cache_key]; } /** * Get a translation for a PDF * * @param string $string * @return string */ public static function getPdfTranslation($string) { global $_LANGPDF; $iso = Context::getContext()->language->iso_code; if (!Validate::isLangIsoCode($iso)) Tools::displayError(sprintf('Invalid iso lang (%s)', Tools::safeOutput($iso))); $override_i18n_file = _PS_THEME_DIR_.'pdf/lang/'.$iso.'.php'; $i18n_file = _PS_TRANSLATIONS_DIR_.$iso.'/pdf.php'; if (file_exists($override_i18n_file)) $i18n_file = $override_i18n_file; if (!include($i18n_file)) Tools::displayError(sprintf('Cannot include PDF translation language file : %s', $i18n_file)); if (!isset($_LANGPDF) || !is_array($_LANGPDF)) return str_replace('"', '"', $string); $key = md5(str_replace('\'', '\\\'', $string)); $str = (array_key_exists('PDF'.$key, $_LANGPDF) ? $_LANGPDF['PDF'.$key] : $string); return $str; } /** * Check if string use a specif syntax for sprintf and replace arguments if use it * * @param $string * @param $args * @return string */ public static function checkAndReplaceArgs($string, $args) { if (preg_match_all('#(?:%%|%(?:[0-9]+\$)?[+-]?(?:[ 0]|\'.)?-?[0-9]*(?:\.[0-9]+)?[bcdeufFosxX])#', $string, $matches) && !is_null($args)) { if (!is_array($args)) $args = array($args); return vsprintf($string, $args); } return $string; } /** * Perform operations on translations after everything is escaped and before displaying it */ public static function smartyPostProcessTranslation($string, $params) { // If tags were explicitely provided, we want to use them *after* the translation string is escaped. if (!empty($params['tags'])) { foreach ($params['tags'] as $index => $tag) { // Make positions start at 1 so that it behaves similar to the %1$d etc. sprintf positional params $position = $index + 1; // extract tag name $match = array(); if (preg_match('/^\s*<\s*(\w+)/', $tag, $match)) { $opener = $tag; $closer = ''; $string = str_replace('['.$position.']', $opener, $string); $string = str_replace('[/'.$position.']', $closer, $string); $string = str_replace('['.$position.'/]', $opener.$closer, $string); } } } return $string; } }