pathFinder = ServiceContainer::getService(PathFinder::class); $this->getLanguages(); } public const FORMAT_PO = 'po'; public const FORMAT_PHP = 'php'; protected $actualpofile = ''; public function selectType($type) { $language = $this->getActualLanguage(); $engineLangDir = $this->pathFinder->enginePath('web/lang/'); $shopLangDir = $this->pathFinder->shopPath('lang/'); $result = ['language' => $language, 'type' => $type]; if ($type == self::FORMAT_PO) { $this->actualpofile = ''; $engine_lang = $this->loadLanguageTranslationsPO($language, $engineLangDir); $shop_lang = $this->loadLanguageTranslationsPO($language, $shopLangDir); $merged_lang = array_replace_recursive($engine_lang, $shop_lang); $result += [ 'po_file' => $this->actualpofile, 'engine_lang' => $engine_lang, 'shop_lang' => $shop_lang, 'merged_lang' => $merged_lang, ]; } if ($type == self::FORMAT_PHP) { $main_lang['engine'] = $this->loadLanguageTranslationsPHP($engineLangDir, 'cs'); $main_lang['shop'] = $this->loadLanguageTranslationsPHP($shopLangDir, 'cs'); $main_lang['merged'] = array_replace_recursive($main_lang['engine'], $main_lang['shop']); if ($language == 'cs') { $foreign_lang = $main_lang; } else { $foreign_lang['engine'] = $this->loadLanguageTranslationsPHP($engineLangDir, $language); $foreign_lang['shop'] = $this->loadLanguageTranslationsPHP($shopLangDir, $language); $foreign_lang['merged'] = array_replace_recursive($foreign_lang['engine'], $foreign_lang['shop']); } $result += [ 'main_lang' => $main_lang, 'foreign_lang' => $foreign_lang, ]; } return $result; } public function getFrontendTranslations($selection, $language) { $sql_all = sqlQueryBuilder()->select('id, original, translation')->from('translations_frontend') ->where(Operator::equals(['type' => $selection, 'id_language' => $language])) ->orderBy('original'); return sqlFetchAll($sql_all, 'original'); } public function get_vars() { $data = parent::get_vars(); $results = []; $language = $this->getActualLanguage(); $results[$language][self::FORMAT_PO] = $this->loadDbPoTranslations($language, $data); $php_sql = $this->getFrontendTranslations(self::FORMAT_PHP, $language); if ($php_sql) { $file = $this->selectType(self::FORMAT_PHP); $mainTranslations = $file['main_lang']['merged']; $foreignTranslations = $file['foreign_lang']['merged']; foreach ($php_sql as $sql_translation) { $path = $sql_translation['original']; $actual = $this->findPathInArray(explode('/', $path), $mainTranslations); $translation = $this->findPathInArray(explode('/', $path), $foreignTranslations); $results[$file['language']]['php'][$path] = [ 'path' => $path, 'original' => $actual, 'translation' => $translation, 'sql' => $sql_translation, ]; } } $data['results'] = $results; return $data; } protected function findPathInArray($pathArray, $haystack) { if (empty($pathArray)) { return $haystack; } $key = array_shift($pathArray); if (array_key_exists($key, $haystack)) { return $this->findPathInArray($pathArray, $haystack[$key]); } return false; } public function loadDbPoTranslations($language, array &$data): array { $results = []; $po_sql = $this->getFrontendTranslations(self::FORMAT_PO, $language); if ($po_sql) { $file = $this->selectType(self::FORMAT_PO); $data['po_file'] = $file['po_file']; foreach ($po_sql as $sql_translation) { $original = $sql_translation['original']; if ($translation = $file['merged_lang'][$original] ?? false) { $plural = $translation['plural']; $plurals = []; foreach ($translation['pluralTranslations'] as $id => $pluralTranslation) { $plurals[$id] = [ 'original' => $plural, 'translation' => $pluralTranslation, 'sql' => $po_sql[$plural.'_plural'.$id] ?? null, ]; } $results[$original] = [ 'original' => $original, 'translation' => $translation['translation'], 'sql' => $sql_translation, 'plural' => $plural, 'pluralTranslations' => $plurals, ]; } } } return $results; } public function storeDbPoFile($language, $data): void { $translations = new \Gettext\Translations(); $translations->setLanguage($this->getLanguageLocale($language)); foreach ($data ?? [] as $key => $row) { $translation = $translations->insert('', $key); $translation->setTranslation($row['translation']); $translation->setPlural($row['plural'] ?? ''); $translation->setPluralTranslations($row['plurals'] ?? []); } $fileName = $this->pathFinder->tmpPath($language.'_db.po'); Gettext\Generators\Po::toFile($translations, $fileName); } protected function translationFrontendExists($original, $languageId, $type = false) { $qb = sqlQueryBuilder()->select('*')->from('translations_frontend') ->where(Operator::equals(['original' => $original, 'id_language' => $languageId])) ->setMaxResults(1); if ($type) { $qb->andWhere(Operator::equals(['type' => $type])); } return $qb->execute()->fetch(); } protected function getLanguageLocale(string $lang): string { return sqlQueryBuilder()->select('locale')->from('languages')->where(Operator::equals(['id' => $lang]))->execute()->fetchOne() ?: $lang; } /** * @return array */ protected function loadLanguageTranslationsPHP($dir, $language) { // Tady nactu vsecnhy preklady z lang.{lang}.php a vsechny soubory z adresare {lang} $main_file = $dir."lang.{$language}.php"; if (file_exists("{$dir}{$language}/")) { foreach (new DirectoryIterator($dir."{$language}/") as $fileinfo) { if ($fileinfo->isDot()) { continue; } $subfile = $dir."{$language}/".$fileinfo->getFilename(); require_once $subfile; } } if (file_exists($main_file)) { require $main_file; } return $txt_str ?? []; } protected function loadLanguageTranslationsPO(string $language, ?string $dir = null) { $txt_str = []; if (!($translations = $this->getPOTranslations($language, $dir))) { return []; } /** @var \Gettext\Translation $translation */ foreach ($translations as $index => $translation) { if ($translation->isDisabled()) { continue; } $txt_str[$translation->getOriginal()] = [ 'original' => $translation->getOriginal(), 'translation' => $translation->getTranslation(), 'plural' => $translation->getPlural(), 'pluralTranslations' => $translation->getPluralTranslations(), 'references' => $translation->getReferences(), 'object' => $translation, ]; } return $txt_str; } protected function sectionNotFound($section, $original) { $status = 'ERROR'; $podstatus = 'SECTIONNOTFOUND'; $results = []; foreach ($original as $key => $item) { if (is_array($item)) { $results += $this->sectionNotFound($section.'/'.$key, $item); } else { $results[$section.'/'.$key] = [ 'cesta' => $section.'/'.$key, 'original' => $item, 'translation' => "SEKCE {$section} NENALEZENA", 'status' => $status, 'podstatus' => $podstatus, ]; } } return $results; } protected function mainLangSectionNotFound($section, $translation) { $status = 'WARNING'; $podstatus = ''; $results = []; foreach ($translation as $key => $item) { if (is_array($item)) { $results += $this->mainLangSectionNotFound($section.'/'.$key, $item); } else { $original = str_replace('{NENALEZENO}/', '', $section); $results[$section.'/'.$key] = [ 'cesta' => $section.'/'.$key, 'original' => "SEKCE {$original} NENALEZENA", 'translation' => $item, 'status' => $status, 'podstatus' => $podstatus, ]; } } return $results; } protected function translationNotFound($section, $original) { $status = 'ERROR'; $podstatus = ''; $results = []; $results[$section] = [ 'cesta' => $section, 'original' => $original, 'translation' => 'NENALEZEN', 'status' => $status, 'podstatus' => $podstatus, ]; return $results; } protected function savePlurals($translation) { $plurals = $translation['plurals'] ?? []; $plurals = array_filter($plurals, 'strlen'); $type = $translation['type'] ?? self::FORMAT_PO; $actualLanguage = $this->getActualLanguage(); foreach ($plurals as $plural_id => $plural) { $original = $translation['plural'].'_plural'.$plural_id; $this->translationsInsertOnDuplicateUpdate($this->getActualLanguage(), $type, $original, $plural); } if (empty($plurals)) { $qb = sqlQueryBuilder()->delete('translations_frontend') ->where(Operator::equals(['id_language' => $actualLanguage, 'type' => $type])) ->andWhere(Operator::like(['original' => $translation['plural'].'_plural%'])); $qb->execute(); } } protected function translationsInsertOnDuplicateUpdate($id_language, $type, $original, $translation) { $idArray = ['original' => $original, 'type' => strtoupper($type), 'id_language' => $id_language]; if ($this->translationFrontendExists($original, $id_language, $type)) { $this->updateSQL('translations_frontend', ['translation' => $translation], $idArray); } else { $this->insertSQL('translations_frontend', $idArray + ['translation' => $translation]); } } protected function handleSend() { $data_array = $_POST; $this->saveTranslations($data_array); $this->returnOK('Překlady byly úspěšně odeslány.'); } protected function handleReload() { $data_array = $_POST; $this->saveTranslations($data_array); $this->generateDbPoFile($data_array); $this->returnOK('Překlady byly úspěšně uloženy a aktualizovány.'); } public function doReloadPoFile($lang) { $data = []; $data_array = $this->loadDbPoTranslations($lang, $data); foreach ($data_array as $key => &$translation) { if (isset($translation['sql']['translation'])) { $translation['translation'] = $translation['sql']['translation']; $translation['plurals'] = array_map(function ($plural) { return $plural['sql']['translation'] ?? ''; }, $translation['pluralTranslations']); } else { unset($translation[$key]); } } $this->storeDbPoFile($lang, $data_array); } protected function saveTranslations($data) { $language = $this->getActualLanguage(); foreach ($data['translation'][$language] as $key => $row) { $this->updateSQL('translations_frontend', ['translation' => $row['translation']], ['id' => $row['id']]); if (!empty($row['plural'])) { $this->savePlurals($row); } } } protected function generateDbPoFile($data) { $language = $this->getActualLanguage(); $this->storeDbPoFile($language, $data['translation'][$language]); $this->init_smarty(); $this->smarty->clearCompiledTemplate(); } public function getLanguages() { if (!empty($this->languages)) { return $this->languages; } return $this->languages = array_keys(Contexts::get(LanguageContext::class)->getAll()); } public function getActualSelection() { $selection = getVal('selection'); if (!empty($selection) && in_array($selection, [self::FORMAT_PO, self::FORMAT_PHP])) { return $selection; } return self::FORMAT_PO; } public function getActualLanguage() { $language = getVal('language'); if (!empty($language) && in_array($language, $this->getLanguages())) { return $language; } return $this->getLanguages()[0]; } public function getPOTranslations(string $language, ?string $dir = null): ?Gettext\Translations { $cfg = Config::get(); $templates = $cfg['Path']['smarty_tpl']['theme']; // load all or only from specific folder if (!$dir) { $files = [ $this->pathFinder->shopPath("lang/{$language}.po"), $this->pathFinder->shopPath("lang/{$language}.{$templates}.po"), $this->pathFinder->engineWebPath("lang/{$language}.{$templates}.po"), $this->pathFinder->engineWebPath("lang/{$language}.po"), ]; } else { $files = [ $dir."{$language}.po", $dir."{$language}.{$templates}.po", ]; } $translations = null; foreach ($files as $file) { $this->getTemplateTranslator()->mergeTranslations($translations, $file); } return $translations; } public function getActualPOFile($dir, $language) { $file = $dir."{$language}.po"; if (file_exists($file)) { return $file; } else { global $cfg; $templates = $cfg['Path']['smarty_tpl']['theme']; $file = $dir."{$language}.{$templates}.po"; if (file_exists($file)) { return $file; } else { return null; } } } protected function getTemplateTranslator(): TemplateTranslator { static $templateTranslator; if (!$templateTranslator) { $templateTranslator = ServiceContainer::getService(TemplateTranslator::class); } return $templateTranslator; } }