'.$language.': '.$text; return $responseData; } $deepl = (\Settings::getDefault()->use_deepl ?? 'N'); getLogger()->notice('TranslationEngine:translate', ['char_count' => mb_strlen($text), 'from' => $sourceLanguage, 'to' => $language, 'deepl' => $deepl]); if ($deepl == 'Y') { return $this->getTranslationWithDeepL($text, $sourceLanguage, $language, $html); } return $this->getTranslationWithGoogle($text, $sourceLanguage, $language); } public function getTranslationMulti(array $textMulti, string $sourceLanguage, string $language): array { foreach ($textMulti as $key => $text) { if (empty($text)) { continue; } $translation = $this->getTranslation($text, $sourceLanguage, $language); if (empty($translation['error'])) { $textMulti[$key] = $translation['translatedText']; } else { unset($textMulti[$key]); } } return $textMulti; } private function getTranslationWithGoogle(string $text, string $sourceLanguage, string $language): array { // Google Translate nezná de-AT nebo de-CH, zná jen de-DE // potřebuju to teda, aby se použila němčina - jinak to nefunguje vubec $langAlias = [ 'at' => 'de', 'ch' => 'de', ]; foreach ([&$sourceLanguage, &$language] as &$lang) { if (isset($langAlias[$lang])) { $lang = $langAlias[$lang]; } } $baseUrl = 'https://www.googleapis.com/language/translate/v2?key='.self::$googleApiKey; // .'&q='.rawurlencode($text).'&source='.$sourceLanguage.'&target='.$language $textChunks = $this->splitTextIntoChunks($text); $translatedChunks = []; foreach ($textChunks as $chunk) { $url = $baseUrl.'&q='.rawurlencode($chunk).'&source='.$sourceLanguage.'&target='.$language; $handle = curl_init($url); curl_setopt($handle, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($handle); $responseData = json_decode($response ?: '{}', true); if (isset($responseData['error']) || curl_error($handle)) { curl_close($handle); return [ 'error' => curl_error($handle) ?: ($responseData['error'] ?? 'Unknown error'), 'translatedText' => '', ]; } $translatedChunks[] = html_entity_decode($responseData['data']['translations'][0]['translatedText'] ?? '', ENT_QUOTES); curl_close($handle); } // Combine all translated chunks into a single result $translatedText = implode(' ', $translatedChunks); // Replace malformed sequences $translatedText = str_replace( ['> , ', '> .'], ['>, ', '>.'], $translatedText ); return [ 'error' => '', 'translatedText' => $translatedText, ]; } private function getTranslationWithDeepL(string $text, string $sourceLanguage, string $language, bool $html = false): array { $responseData = ['translatedText' => '']; try { $translator = new Translator(self::$deepLAuthKey); $language = $this->deeplLanguageMapping($language); $sourceLanguage = $this->deeplLanguageMapping($sourceLanguage, true); $options = []; if ($html) { $options['tag_handling'] = 'html'; $options['non_splitting_tags'] = ['strong', 'em', 'b', 'i']; } $result = $translator->translateText($text, $sourceLanguage, $language, $options); if (!empty($result->text)) { $responseData['translatedText'] = $result->text; } } catch (DeepLException $exception) { $responseData['error'] = $exception->getMessage(); } return $responseData; } protected function deeplLanguageMapping(string $language, bool $source = false): string { switch ($language) { case 'en': // if source language is 'en' => keep it 'en' otherwise use 'en-US' return $source ? 'en' : 'en-US'; case 'at': return 'de'; } return $language; } protected function splitTextIntoChunks(string $text): array { $chunks = []; $currentChunk = ''; // Split text into words to preserve boundaries $words = preg_split('/(\s+)/u', $text, -1, PREG_SPLIT_DELIM_CAPTURE); foreach ($words as $word) { // Add word to the current chunk if it fits if (mb_strlen($currentChunk.$word) <= self::GOOGLE_CHUNK) { $currentChunk .= $word; } else { // Save the current chunk and start a new one $chunks[] = trim($currentChunk); $currentChunk = $word; } } // Add the remaining chunk if (!empty($currentChunk)) { $chunks[] = trim($currentChunk); } return $chunks; } }