'lang', 'primary' => 'id_lang', 'fields' => [ 'name' => ['type' => self::TYPE_STRING, 'validate' => 'isGenericName', 'required' => true, 'size' => 32], 'iso_code' => ['type' => self::TYPE_STRING, 'validate' => 'isLanguageIsoCode', 'required' => true, 'size' => 2], 'locale' => ['type' => self::TYPE_STRING, 'validate' => 'isLocale', 'size' => 5], 'language_code' => ['type' => self::TYPE_STRING, 'validate' => 'isLanguageCode', 'size' => 5], 'active' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'is_rtl' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'date_format_lite' => ['type' => self::TYPE_STRING, 'validate' => 'isPhpDateFormat', 'required' => true, 'size' => 32], 'date_format_full' => ['type' => self::TYPE_STRING, 'validate' => 'isPhpDateFormat', 'required' => true, 'size' => 32], ], ]; /** @var array|null Languages cache */ protected static $_checkedLangs; protected static $_LANGUAGES; protected static $countActiveLanguages = []; protected $webserviceParameters = [ 'objectNodeName' => 'language', 'objectsNodeName' => 'languages', ]; /** * Konstruktor */ public function __construct($id = 1, $name = 'Deutsch', $iso_code = 'de', $locale = 'de_DE') { parent::__construct($id); $this->name = $name; $this->iso_code = $iso_code; $this->locale = $locale; } /** * Reset static cache */ public static function resetStaticCache() { parent::resetStaticCache(); static::$loaded_classes = []; static::resetCache(); } /** * Reset cache */ public static function resetCache() { static::$_checkedLangs = null; static::$_LANGUAGES = null; static::$countActiveLanguages = null; static::$_cache_language_installation = null; static::$_cache_language_installation_by_locale = null; static::$_cache_all_language_json = null; static::$_cache_all_languages_iso = null; Cache::clean('Language::*'); } /** * Load all languages details */ private static function loadAllLanguagesDetails(): array { if (null === static::$_cache_all_languages_iso) { $allLanguages = file_get_contents(_PS_ROOT_DIR_ . self::ALL_LANGUAGES_FILE); static::$_cache_all_languages_iso = json_decode($allLanguages, true); if (JSON_ERROR_NONE !== json_last_error()) { throw new RuntimeException( sprintf('The legacy to standard locales JSON could not be decoded %s', json_last_error_msg()) ); } } return static::$_cache_all_languages_iso; } /** * Get fields */ public function getFields() { $this->iso_code = strtolower($this->iso_code); if (empty($this->language_code)) { $this->language_code = $this->iso_code; } return parent::getFields(); } /** * 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'); } } return true; } /** * Add language */ public function add($autodate = true, $nullValues = false, $only_add = false) { if (!parent::add($autodate, $nullValues)) { return false; } if ($only_add) { return true; } $this->checkFiles(); return true; } /** * Update language */ public function update($nullValues = false) { if (!parent::update($nullValues)) { return false; } $this->checkFiles(); return true; } /** * Check files */ public function checkFiles() { return static::checkFilesWithIsoCode($this->iso_code); } /** * Check files with ISO code */ public static function checkFilesWithIsoCode($iso_code) { if (empty($iso_code)) { return false; } $lang_dir = _PS_TRANSLATIONS_DIR_ . $iso_code; $lang_file = _PS_TRANSLATIONS_DIR_ . $iso_code . '.php'; $flag_file = _PS_IMG_DIR_ . 'l/' . $iso_code . '.jpg'; return (is_dir($lang_dir) || is_file($lang_file)) && is_file($flag_file); } /** * Get files list */ public static function getFilesList($iso_from, $theme_from, $iso_to = false, $theme_to = false, $select = false, $check = false, $modules = false) { if (empty($iso_from)) { return false; } $copy = false; if ($iso_to && $theme_to) { $copy = true; } $lFilesFrom = []; $lFilesTo = []; // Get language files if (!$modules) { $lFilesFrom = glob(_PS_TRANSLATIONS_DIR_ . $iso_from . '/*.php'); if ($copy) { $lFilesTo = glob(_PS_TRANSLATIONS_DIR_ . $iso_to . '/*.php'); } } // Get modules files if ($modules) { $lFilesFrom = glob(_PS_MODULE_DIR_ . '*/' . $iso_from . '.php'); if ($copy) { $lFilesTo = glob(_PS_MODULE_DIR_ . '*/' . $iso_to . '.php'); } } // Get theme files if ($theme_from) { $lFilesFrom = array_merge($lFilesFrom, glob(_PS_ALL_THEMES_DIR_ . $theme_from . '/lang/' . $iso_from . '.php')); if ($copy) { $lFilesTo = array_merge($lFilesTo, glob(_PS_ALL_THEMES_DIR_ . $theme_to . '/lang/' . $iso_to . '.php')); } } $lFiles = []; foreach ($lFilesFrom as $file) { $file = basename($file); if ($select && strpos($file, $select) === false) { continue; } $lFiles[$file] = $file; } return $lFiles; } /** * Load update SQL */ public function loadUpdateSQL() { $sql = []; $sql_file = _PS_TRANSLATIONS_DIR_ . $this->iso_code . '/sql/' . _PS_VERSION_ . '.sql'; if (file_exists($sql_file)) { $sql = file_get_contents($sql_file); $sql = str_replace('PREFIX_', _DB_PREFIX_, $sql); $sql = preg_split("/;\s*[\r\n]+/", $sql); } return $sql; } /** * Delete language */ public function delete() { if (!parent::delete()) { return false; } // Delete translations files if (file_exists(_PS_TRANSLATIONS_DIR_ . $this->iso_code)) { Tools::deleteDirectory(_PS_TRANSLATIONS_DIR_ . $this->iso_code); } if (file_exists(_PS_MAIL_DIR_ . $this->iso_code)) { Tools::deleteDirectory(_PS_MAIL_DIR_ . $this->iso_code); } // Delete flag if (file_exists(_PS_IMG_DIR_ . 'l/' . $this->iso_code . '.jpg')) { unlink(_PS_IMG_DIR_ . 'l/' . $this->iso_code . '.jpg'); } return true; } /** * Delete selection */ public function deleteSelection(array $selection) { if (!is_array($selection)) { return false; } $result = true; foreach ($selection as $id) { $language = new Language($id); $result = $result && $language->delete(); } return $result; } /** * Get languages */ public static function getLanguages($active = true, $id_shop = false, $ids_only = false) { if (!static::$_LANGUAGES) { static::loadLanguages(); } $languages = static::$_LANGUAGES; if ($active) { $languages = array_filter($languages, function ($lang) { return $lang['active']; }); } if ($id_shop) { $languages = array_filter($languages, function ($lang) use ($id_shop) { return in_array($id_shop, $lang['shops']); }); } if ($ids_only) { $languages = array_keys($languages); } return $languages; } /** * Get IDs */ public static function getIDs($active = true, $id_shop = false) { return static::getLanguages($active, $id_shop, true); } /** * Get language */ public static function getLanguage($id_lang) { if (!static::$_LANGUAGES) { static::loadLanguages(); } return isset(static::$_LANGUAGES[$id_lang]) ? static::$_LANGUAGES[$id_lang] : false; } /** * Get ISO by ID */ public static function getIsoById($id_lang) { if (!Validate::isUnsignedId($id_lang)) { return false; } $key = 'language_getIsoById_' . $id_lang; if (!Cache::isStored($key)) { $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue( ' SELECT `iso_code` FROM `' . _DB_PREFIX_ . 'lang` WHERE `id_lang` = ' . (int) $id_lang ); Cache::store($key, $result); } return Cache::retrieve($key); } /** * Get locale by ID */ public static function getLocaleById(int $langId): ?string { if (!Validate::isUnsignedId($langId)) { return null; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue( ' SELECT `locale` FROM `' . _DB_PREFIX_ . 'lang` WHERE `id_lang` = ' . (int) $langId ); return $result ?: null; } /** * Get JSON language details */ public static function getJsonLanguageDetails($locale) { $allLanguages = static::loadAllLanguagesDetails(); return isset($allLanguages[$locale]) ? $allLanguages[$locale] : null; } /** * Get ID by ISO */ public static function getIdByIso($iso_code, $no_cache = false) { if (!Validate::isLanguageIsoCode($iso_code)) { return false; } if (!$no_cache && isset(static::$_checkedLangs[strtolower($iso_code)])) { return static::$_checkedLangs[strtolower($iso_code)]; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue( ' SELECT `id_lang` FROM `' . _DB_PREFIX_ . 'lang` WHERE `iso_code` = \'' . pSQL(strtolower($iso_code)) . '\'' ); static::$_checkedLangs[strtolower($iso_code)] = $result; return $result; } /** * Get ID by locale */ public static function getIdByLocale($locale, $noCache = false) { if (!$noCache && isset(static::$_cache_language_installation_by_locale[$locale])) { return static::$_cache_language_installation_by_locale[$locale]; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue( ' SELECT `id_lang` FROM `' . _DB_PREFIX_ . 'lang` WHERE `locale` = \'' . pSQL($locale) . '\'' ); static::$_cache_language_installation_by_locale[$locale] = $result; return $result; } /** * Get language details */ public static function getLangDetails($iso) { $iso = strtolower($iso); if (!Validate::isLanguageIsoCode($iso)) { return false; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow( ' SELECT * FROM `' . _DB_PREFIX_ . 'lang` WHERE `iso_code` = \'' . pSQL($iso) . '\'' ); return $result; } /** * Get locale by ISO */ public static function getLocaleByIso($isoCode) { if (!Validate::isLanguageIsoCode($isoCode)) { return false; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue( ' SELECT `locale` FROM `' . _DB_PREFIX_ . 'lang` WHERE `iso_code` = \'' . pSQL(strtolower($isoCode)) . '\'' ); return $result; } /** * Get ISO by locale */ public static function getIsoByLocale($locale) { if (!Validate::isLocale($locale)) { return false; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue( ' SELECT `iso_code` FROM `' . _DB_PREFIX_ . 'lang` WHERE `locale` = \'' . pSQL($locale) . '\'' ); return $result; } /** * Get language code by ISO */ public static function getLanguageCodeByIso($iso_code) { if (!Validate::isLanguageIsoCode($iso_code)) { return false; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue( ' SELECT `language_code` FROM `' . _DB_PREFIX_ . 'lang` WHERE `iso_code` = \'' . pSQL(strtolower($iso_code)) . '\'' ); return $result; } /** * Get language by IETF code */ public static function getLanguageByIETFCode($code) { if (!Validate::isLanguageCode($code)) { return false; } $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->getRow( ' SELECT * FROM `' . _DB_PREFIX_ . 'lang` WHERE `language_code` = \'' . pSQL($code) . '\'' ); return $result; } /** * Get ISO IDs */ public static function getIsoIds($active = true) { $languages = static::getLanguages($active); $iso_ids = []; foreach ($languages as $language) { $iso_ids[$language['iso_code']] = $language['id_lang']; } return $iso_ids; } /** * Copy language data */ public static function copyLanguageData($from, $to) { $res = true; $sql = 'SHOW TABLES LIKE \'' . _DB_PREFIX_ . '%_lang\''; $tables = Db::getInstance()->executeS($sql); foreach ($tables as $table) { $table = array_values($table); $table = $table[0]; $sql = 'SELECT * FROM `' . $table . '` WHERE `id_lang` = ' . (int) $from; $data = Db::getInstance()->executeS($sql); foreach ($data as $row) { $row['id_lang'] = $to; $res &= Db::getInstance()->insert($table, $row); } } return $res; } /** * Load languages */ public static function loadLanguages() { static::$_LANGUAGES = []; $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`) ORDER BY l.`name` ASC'; $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); foreach ($result as $row) { if (!isset(static::$_LANGUAGES[$row['id_lang']])) { static::$_LANGUAGES[$row['id_lang']] = $row; static::$_LANGUAGES[$row['id_lang']]['shops'] = []; } static::$_LANGUAGES[$row['id_lang']]['shops'][] = $row['id_shop']; } } /** * Load languages (legacy) */ public static function loadLanguagesLegacy() { static::$_LANGUAGES = []; $sql = 'SELECT * FROM `' . _DB_PREFIX_ . 'lang` ORDER BY `name` ASC'; $result = Db::getInstance(_PS_USE_SQL_SLAVE_)->executeS($sql); foreach ($result as $row) { static::$_LANGUAGES[$row['id_lang']] = $row; } } /** * Check and add language */ public static function checkAndAddLanguage($iso_code, $lang_pack = false, $only_add = false, $params_lang = null) { if (!Validate::isLanguageIsoCode($iso_code)) { return false; } $lang = new Language(); $lang->iso_code = strtolower($iso_code); $lang->active = true; if ($params_lang && is_array($params_lang)) { foreach ($params_lang as $key => $value) { if (property_exists($lang, $key)) { $lang->$key = $value; } } } if (!$lang->add()) { return false; } if ($lang_pack) { static::installLanguagePack($iso_code, $params_lang); } return $lang->id; } /** * Is installed */ public static function isInstalled($iso_code) { return static::getIdByIso($iso_code) ? true : false; } /** * Is installed by locale */ public static function isInstalledByLocale($locale) { return static::getIdByLocale($locale) ? true : false; } /** * Count active languages */ public static function countActiveLanguages($id_shop = null) { if (!$id_shop) { $id_shop = Context::getContext()->shop->id; } if (!isset(static::$countActiveLanguages[$id_shop])) { static::$countActiveLanguages[$id_shop] = Db::getInstance(_PS_USE_SQL_SLAVE_)->getValue( ' SELECT COUNT(DISTINCT l.`id_lang`) FROM `' . _DB_PREFIX_ . 'lang` l LEFT JOIN `' . _DB_PREFIX_ . 'lang_shop` ls ON (l.`id_lang` = ls.`id_lang`) WHERE l.`active` = 1 AND ls.`id_shop` = ' . (int) $id_shop ); } return static::$countActiveLanguages[$id_shop]; } /** * Download and install language pack */ public static function downloadAndInstallLanguagePack($iso, $version = _PS_VERSION_, $params = null, $install = true) { $errors = []; $res = static::downloadLanguagePack($iso, $version, $errors); if ($res && $install) { static::installLanguagePack($iso, $params, $errors); } return $res; } /** * Download language pack */ public static function downloadLanguagePack($iso, $version, &$errors = []) { $errors = []; $res = true; // Download language pack $url = str_replace(['%version%', '%locale%'], [$version, $iso], self::SF_LANGUAGE_PACK_URL); // Simulate download (in real implementation, this would download the file) $errors[] = 'Language pack download not implemented in this version'; return $res; } /** * Install language pack */ public static function installLanguagePack($iso, $params, &$errors = []) { $errors = []; // Simulate installation (in real implementation, this would install the pack) $errors[] = 'Language pack installation not implemented in this version'; return true; } /** * Is multi language activated */ public static function isMultiLanguageActivated($id_shop = null) { return static::countActiveLanguages($id_shop) > 1; } /** * Update modules translations */ public static function updateModulesTranslations(array $modules_list = []) { if (empty($modules_list)) { $modules_list = Module::getModulesDirOnDisk(); } foreach ($modules_list as $module) { static::updateModuleTranslations($module); } } /** * Update module translations */ public static function updateModuleTranslations($module) { // Simulate module translation update return true; } /** * Get RTL stylesheet processor */ public static function getRtlStylesheetProcessor() { return new RtlStylesheetProcessor(); } /** * Translation pack is in cache */ public static function translationPackIsInCache(string $locale, string $type = self::PACK_TYPE_SYMFONY): bool { $path = static::getPathToCachedTranslationPack($locale, $type); return file_exists($path); } /** * Get path to cached translation pack */ private static function getPathToCachedTranslationPack(string $locale, string $type = self::PACK_TYPE_SYMFONY): string { return static::TRANSLATION_PACK_CACHE_DIR . '/' . $locale . '_' . $type . '.zip'; } /** * Get locale */ public function getLocale(): string { return $this->locale; } /** * Get ID */ public function getId(): int { return (int) $this->id; } /** * Get name */ public function getName(): string { return $this->name; } /** * Get ISO code */ public function getIsoCode(): string { return $this->iso_code; } /** * Get language code */ public function getLanguageCode(): string { return $this->language_code; } /** * Is RTL */ public function isRTL(): bool { return (bool) $this->is_rtl; } /** * Get date format */ public function getDateFormat(): string { return $this->date_format_lite; } /** * Get date time format */ public function getDateTimeFormat(): string { return $this->date_format_full; } /** * Load languages (simple method) */ public static function loadLanguages() { return [ new Language(1, 'Deutsch', 'de', 'de_DE'), new Language(2, 'English', 'en', 'en_US'), new Language(3, 'Français', 'fr', 'fr_FR'), new Language(4, 'Español', 'es', 'es_ES'), ]; } }