'Norwegian Bokmål (nn is Nynorsk; this is bokmål). Legal and formal register. Preserve Norwegian legal terminology.', 'uk' => 'Ukrainian. Formal register suitable for legal documents. Use standard Ukrainian orthography.', 'pl' => 'Polish. Formal register suitable for legal documents.', ]; // ── Entry point ────────────────────────────────────────────────────────────── if (PHP_SAPI !== 'cli') { http_response_code(403); exit('CLI only'); } if ($argc < 2) { fwrite(STDERR, "Usage: php scripts/translate-pages.php translations/.php\n"); exit(1); } $filePath = realpath($argv[1]); if (!$filePath || !is_file($filePath)) { fwrite(STDERR, "File not found: {$argv[1]}\n"); exit(1); } echo "Loading: $filePath\n"; $allLangs = require $filePath; if (!is_array($allLangs) || !isset($allLangs['en'])) { fwrite(STDERR, "File must return an array with an 'en' key.\n"); exit(1); } $englishStrings = $allLangs['en']; echo 'English keys: ' . count($englishStrings) . "\n"; // ── Translate each target language ────────────────────────────────────────── foreach ($targetLangs as $langCode => $langDesc) { echo "\nTranslating → $langCode ($langDesc)...\n"; $translated = translateAll($englishStrings, $langCode, $langDesc, $endpoint, $deploy, $apiVer, $apiKey, $batchSize); $allLangs[$langCode] = $translated; echo " Done. Keys translated: " . count($translated) . "\n"; } // ── Write back ─────────────────────────────────────────────────────────────── $phpCode = " $batchKeys) { $batchNum = $i + 1; $total = count($batches); echo " Batch $batchNum/$total (" . count($batchKeys) . " keys)...\n"; $batchStrings = array_intersect_key($strings, array_flip($batchKeys)); $translated = callAzureOpenAI($batchStrings, $langCode, $langDesc, $endpoint, $deploy, $apiVer, $apiKey); $result = array_merge($result, $translated); } return $result; } function callAzureOpenAI( array $strings, string $langCode, string $langDesc, string $endpoint, string $deploy, string $apiVer, string $apiKey ): array { $systemPrompt = <<, , ,
etc.) - Preserve all bracketed tokens exactly: [FATHER], [PERSON], [SOCIAL WORKER], [ORG] etc. - Preserve all arrow characters (→, ←, →) and typographic symbols - Preserve placeholder values like "Ola Nordmann", "00:01:24" unchanged - Keep URLs, file extensions (.docx, .php), and technical terms (PDF, DOCX, GPT-4o, Whisper, pyannote) unchanged - Translate UI labels, descriptions, and body text naturally into {$langDesc} - Return ONLY a valid JSON object with the same keys as input — no commentary, no markdown fences PROMPT; $userContent = json_encode($strings, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); $payload = json_encode([ 'messages' => [ ['role' => 'system', 'content' => $systemPrompt], ['role' => 'user', 'content' => $userContent], ], 'temperature' => 0.2, 'response_format' => ['type' => 'json_object'], ]); $url = "{$endpoint}/openai/deployments/{$deploy}/chat/completions?api-version={$apiVer}"; $ch = curl_init($url); curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payload, CURLOPT_HTTPHEADER => [ 'Content-Type: application/json', "api-key: {$apiKey}", ], CURLOPT_TIMEOUT => 120, ]); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($response === false || $httpCode !== 200) { fwrite(STDERR, "API error HTTP $httpCode: $response\n"); exit(1); } $data = json_decode($response, true); $content = $data['choices'][0]['message']['content'] ?? ''; $translated = json_decode($content, true); if (!is_array($translated)) { fwrite(STDERR, "Failed to parse JSON from model response:\n$content\n"); exit(1); } return $translated; } function varExportShort(mixed $data, int $indent = 0): string { $pad = str_repeat(' ', $indent); $pad1 = str_repeat(' ', $indent + 1); if (!is_array($data)) { return var_export($data, true); } $isIndexed = array_keys($data) === range(0, count($data) - 1); $lines = []; foreach ($data as $key => $value) { $keyStr = $isIndexed ? '' : var_export($key, true) . ' => '; $lines[] = $pad1 . $keyStr . varExportShort($value, $indent + 1); } return "array (\n" . implode(",\n", $lines) . ",\n{$pad})"; }