6 private static array $warnings = array();
7 private static array $logged = array();
9 public static function provider(): string {
10 $provider = strtolower(trim((string)
dbx()->get_config(
'dbxContent',
'lng_translate_provider',
'copy')));
11 if ($provider ===
'' || $provider ===
'undef') {
18 self::$warnings = array();
19 self::$logged = array();
23 return self::$warnings;
26 public static function translate(
string $text,
string $from,
string $to,
string $context =
'content'): string {
28 if ($text ===
'' || $from === $to) {
32 $provider = self::provider();
39 return self::translateCustom($text, $from, $to, $context);
41 return self::translateDeepL($text, $from, $to, $context);
43 return self::translateOpenAi($text, $from, $to, $context);
45 self::addWarning($provider,
'Unbekannter Provider, Text wird kopiert.', $context, $to);
50 private static function addWarning(
string $provider,
string $message,
string $context =
'',
string $lng =
''): void {
51 $provider = strtolower(trim($provider));
52 $message = trim($message);
53 if ($message ===
'') {
57 $key = $provider .
'|' . $message;
58 if (isset(self::$logged[$key])) {
61 self::$logged[$key] = 1;
62 self::$warnings[] = array(
63 'provider' => $provider,
64 'message' => $message,
65 'context' => $context,
69 if (function_exists(
'dbx') && is_object(
dbx())) {
72 'dbxContentTranslate',
73 $lng !==
'' ? $lng : $context,
80 private static function translateCustom(
string $text,
string $from,
string $to,
string $context): string {
81 $file =
dbx()->os_path(
dbx()->get_base_dir() .
'dbx/modules/dbxContent/translate.php');
82 if (!is_file($file)) {
83 self::addWarning(
'custom',
'translate.php fehlt, Text wird kopiert.', $context, $to);
90 self::addWarning(
'custom',
'Custom-Translate lieferte kein Ergebnis.', $context, $to);
96 private static function translateDeepL(
string $text,
string $from,
string $to,
string $context): string {
97 $key = trim((string)
dbx()->get_config(
'dbxContent',
'lng_translate_api_key',
''));
99 self::addWarning(
'deepl',
'API-Key fehlt (lng_translate_api_key), Text wird kopiert.', $context, $to);
103 $url = trim((
string)
dbx()->get_config(
'dbxContent',
'lng_translate_api_url',
''));
105 $url =
'https://api-free.deepl.com/v2/translate';
108 $payload = http_build_query(array(
111 'source_lang' => strtoupper($from),
112 'target_lang' => strtoupper($to),
115 $response = self::httpPost($url, $payload, array(
'Content-Type: application/x-www-form-urlencoded'),
false,
'deepl', $context, $to);
121 self::addWarning(
'deepl',
$response[
'message'], $context, $to);
125 $trans =
$response[
'translations'][0][
'text'] ??
'';
126 if (!is_string($trans) || trim($trans) ===
'') {
127 self::addWarning(
'deepl',
'DeepL-Antwort ohne Text, Original wird verwendet.', $context, $to);
133 private static function translateOpenAi(
string $text,
string $from,
string $to,
string $context): string {
134 $key = trim((string)
dbx()->get_config(
'dbxContent',
'lng_translate_api_key',
''));
136 self::addWarning(
'openai',
'API-Key fehlt (lng_translate_api_key), Text wird kopiert.', $context, $to);
140 $url = trim((
string)
dbx()->get_config(
'dbxContent',
'lng_translate_api_url',
''));
142 $url =
'https://api.openai.com/v1/chat/completions';
145 $model = trim((
string)
dbx()->get_config(
'dbxContent',
'lng_translate_model',
'gpt-4o-mini'));
147 $model =
'gpt-4o-mini';
150 $prompt =
'Translate the following ' . $context .
' from ' . $from .
' to ' . $to
151 .
'. Preserve HTML tags and [modul=...][/modul] markers exactly. Return only the translation.';
153 $body = json_encode(array(
156 array(
'role' =>
'system',
'content' => $prompt),
157 array(
'role' =>
'user',
'content' => $text),
159 'temperature' => 0.2,
160 ), JSON_UNESCAPED_UNICODE);
162 $response = self::httpPost($url, $body, array(
163 'Content-Type: application/json',
164 'Authorization: Bearer ' . $key,
165 ),
true,
'openai', $context, $to);
171 if (isset(
$response[
'error'][
'message']) && is_string(
$response[
'error'][
'message'])) {
172 self::addWarning(
'openai',
$response[
'error'][
'message'], $context, $to);
176 $trans =
$response[
'choices'][0][
'message'][
'content'] ??
'';
177 if (!is_string($trans) || trim($trans) ===
'') {
178 self::addWarning(
'openai',
'OpenAI-Antwort ohne Text, Original wird verwendet.', $context, $to);
184 private static function httpPost(
string $url,
string $body, array $headers,
bool $json =
false,
string $provider =
'',
string $context =
'',
string $lng =
'') {
185 if (!function_exists(
'curl_init')) {
186 self::addWarning($provider !==
'' ? $provider :
'translate',
'curl nicht verfuegbar, Text wird kopiert.', $context, $lng);
190 $ch = curl_init($url);
191 curl_setopt($ch, CURLOPT_RETURNTRANSFER,
true);
192 curl_setopt($ch, CURLOPT_POST,
true);
193 curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
194 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
195 curl_setopt($ch, CURLOPT_TIMEOUT, 30);
197 $raw = curl_exec($ch);
198 $errno = curl_errno($ch);
199 $error = curl_error($ch);
200 $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
204 self::addWarning($provider !==
'' ? $provider :
'translate',
'HTTP-Fehler: ' . $error, $context, $lng);
208 self::addWarning($provider !==
'' ? $provider :
'translate',
'HTTP ' . $code .
' von API', $context, $lng);
210 if (!is_string($raw) || $raw ===
'') {
211 self::addWarning($provider !==
'' ? $provider :
'translate',
'Leere API-Antwort', $context, $lng);
215 $decoded = json_decode($raw,
true);
216 if (!is_array($decoded)) {
217 self::addWarning($provider !==
'' ? $provider :
'translate',
'Ungueltige JSON-Antwort', $context, $lng);
static translate(string $text, string $from, string $to, string $context='content')
if(! $db->connect_db_server($server)) $result