Files
kupshop/bundles/KupShop/I18nBundle/Admin/languageCheck.php
2025-08-02 16:30:27 +02:00

492 lines
16 KiB
PHP

<?php
use KupShop\KupShopBundle\Config;
use KupShop\KupShopBundle\Context\LanguageContext;
use KupShop\KupShopBundle\Util\Compat\ServiceContainer;
use KupShop\KupShopBundle\Util\Contexts;
use KupShop\KupShopBundle\Util\Locale\TemplateTranslator;
use KupShop\KupShopBundle\Util\System\PathFinder;
use Query\Operator;
$main_class = 'languageCheck';
class LanguageCheck extends Frame
{
use DatabaseCommunication;
protected $template = 'window/languageCheck.tpl';
protected $languages = [];
/** @var PathFinder */
public $pathFinder;
public function __construct()
{
$this->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;
}
}