translationLocator->getTranslation(ProductsTranslation::class)->getColumns(); $translatableData = array_filter($product, fn ($k) => in_array($k, array_keys($translatableColumns)), ARRAY_FILTER_USE_KEY); // vsechno si prelozim do vychoziho jazyka - v tomhle jazuce totiz chci ukladat produkt do DB $result = $this->translate($translatableData, $config['source'], $this->getDefaultLanguageId()); // prerazim data produktu vychozim jazykem foreach ($result as $field => $value) { $product[$field] = $value; } // a ted jdu nagenerovat preklady (ulozi se mi to do prekladovy tabulky) foreach ($config['to'] as $toLanguage) { if ($toLanguage === $this->getDefaultLanguageId()) { continue; } // do vsech poli, kde chci spustit automaticky preklad, si ulozim AUTO_TRANSLATE hodnotu, kdy na konci aut. importu vsechny tyhle radky projdu a prelozim // automaticky preklad se provede az pozde pomoci `processAutoTranslate` metody $product['translations'][$toLanguage]['products'] = $toLanguage === $config['source'] ? $translatableData : array_map(fn ($x) => self::AUTO_TRANSLATE_KEY, $translatableData); } return $product; } /** * Fce ktera preklada nazev parametru a hodnotu parametru. * * Bohuzel to musi byt oddelene od `preprocessProductData`, protoze zalozeni parametru a jeho hodnoty se vola uz * behem parsovani dat, takze by mi to jinak zalozilo parametry a hodnoty v tom jazyce, ve kterym feed je. * * Tohle se zavola v ramci parsovani feedu a pripravi to data parametru. Provede se preklad parametru a hodnoty do vychoziho * jazyka a zaroven se nageneruji zaznamy do prekladove tabulky. */ public function preprocessParameterData(array $config, string $parameterName, string $parameterValue, array &$product): array { // provedu preklad parametru a hodnoty do vychoziho jazyka $result = $this->translate(['name' => $parameterName, 'value' => $parameterValue], $config['source'], $this->getDefaultLanguageId()); foreach ($config['to'] as $toLanguage) { if ($toLanguage === $this->getDefaultLanguageId()) { continue; } // generuju zaznamy pro prekladove tabulky parametru // pokud jeste neexistuje definice pro dany nazev parametru, tak si ji vytvorim at pak muzu pridavat jen hodnoty if (!isset($product['translations'][$toLanguage]['parameters'][$result['name']])) { $product['translations'][$toLanguage]['parameters'][$result['name']] = [ 'name' => $toLanguage === $config['source'] ? $parameterName : self::AUTO_TRANSLATE_KEY, 'values' => [], ]; } // pokud jeste neexistuje dana hodnota, tak ji pridam do `values` s AUTO_TRANSLATE, kdy preklad se provede az pozdeji pomoci `processAutoTranslate` if (!isset($product['translations'][$toLanguage]['parameters'][$result['name']]['values'][$result['value']])) { $product['translations'][$toLanguage]['parameters'][$result['name']]['values'][$result['value']] = $toLanguage === $config['source'] ? $parameterValue : self::AUTO_TRANSLATE_KEY; } } // vracim parametr a hodnotu ve vychozim jazyce return [$result['name'], $result['value']]; } public function processAutoTranslate(): void { $this->processAutoTranslateForTranslation(ProductsTranslation::class); $this->processAutoTranslateForTranslation(ParametersTranslation::class); $this->processAutoTranslateForTranslation(ParametersListTranslation::class); } /** * Fce ktera automaticky prelozi zaznamy s `AUTO_TRANSLATE_KEY` v prekladove tabulce. */ protected function processAutoTranslateForTranslation(string $translationClass): void { $translation = $this->translationLocator->getTranslation($translationClass); // query builder pro nacteni prekladovych zaznamu $qb = sqlQueryBuilder() ->select('o.id, t.id_language') ->from($translation->getTableName(), 'o') ->join('o', $translation->getTranslationTableName(), 't', "o.id = t.{$translation->getForeignKeyColumn()}") ->groupBy('o.id, t.id_language'); $orX = []; // zaselectuju si vsechny prekladove sloupce foreach ($translation->getColumns() as $column => $_) { // potrebuju sloupec od originalniho objektu (ve vychozim jazyce) // a potrebuju sloupec z prekladu $qb->addSelect("o.{$column}, t.{$column} as 'translated/{$column}'"); // zaroven chci selectovat jen takove radky, ktere obsahuji `AUTO_TRANSLATE_KEY` $orX[] = Operator::equals(["t.{$column}" => self::AUTO_TRANSLATE_KEY]); } $qb->andWhere(Operator::orX($orX)); foreach ($qb->execute() as $item) { // z radku s datama si zafiltruju vsechny pole, ktere chci prekladat (maji hodnotu AUTO_TRANSLATE_KEY) // vznikne mi pole [['field' => null], ...] $translatableColumns = Mapping::mapKeys(array_filter($item, fn ($x) => $x === self::AUTO_TRANSLATE_KEY), fn ($k, $v) => [explode('/', $k)[1], null]); // ted uz chci provest preklad $translated = $this->translate( // tady jeste z $item vezmu vsechny original pole podle prekladatelnych poli v $translatableColumns array_filter($item, fn ($k) => in_array($k, array_keys($translatableColumns)), ARRAY_FILTER_USE_KEY), $this->getDefaultLanguageId(), $item['id_language'] ); // ulozim preklad a mam hotovo $translation->saveSingleObject($item['id_language'], $item['id'], $translated); } } /** * Fce pro provedeni prekladu hodnot. * * Generuje si i lokalni cache, aby se pro stejnou hodnotu nemusel volat preklad pres API vicekrat. */ private function translate(array $data, string $source, string $language): array { $translated = []; $langKey = "{$source}-{$language}"; foreach ($data as $key => $value) { // prazdnou hodnotu nedava smysl prekladat a nejak s ni pracovat if (empty($value)) { $translated[$key] = null; continue; } // pokud je zdrojovy jazyk stejny jako jazyk do ktereho chci prekladat, tak nic neprekladam if ($source === $language) { $translated[$key] = $value; continue; } // pokud mam preklad uz v lokalni cache, tak ho pouziju if (!empty($this->translationsCache[$langKey][$value])) { $translated[$key] = $this->translationsCache[$langKey][$value]; continue; } // ciselnou hodnotu nema smysl prekladat if (is_numeric($value)) { $this->translationsCache[$langKey][$value] = $value; } else { // zavolam preklad hodnoty a ulozim si ho do lokalni cache abych stejnou hodnotu neprekladal v jednom behu aut. importu vicekrat $this->translationsCache[$langKey][$value] = $this->translationEngine->getTranslation($value, $source, $language)['translatedText'] ?? $value; } // do $translated ulozim prelozenou hodnotu $translated[$key] = $this->translationsCache[$langKey][$value]; } return $translated; } private function getDefaultLanguageId(): string { return Contexts::get(LanguageContext::class)->getDefaultId(); } }