492 lines
16 KiB
PHP
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;
|
|
}
|
|
}
|