#!/usr/bin/env node import { promises as fs } from "node:fs"; import path from "node:path"; const ROOT = process.cwd(); const MESSAGES_DIR = path.join(ROOT, "src", "i18n", "messages"); const MESSAGE_OVERRIDES = { es: { "common.disabled": "Deshabilitado", "common.model": "Modelo", "common.account": "Cuenta", "common.time": "Hora", "common.columns": "Columnas", "common.newest": "Más reciente", "common.oldest": "Más antiguo", "common.yes": "Sí", "sidebar.combos": "Combos", "sidebar.docs": "Documentación", "sidebar.apiManager": "Gestor de API", "header.providerDescription": "Gestiona tus conexiones de proveedores de IA", "header.combos": "Combos", "header.comboDescription": "Combinaciones de modelos con fallback", "header.analytics": "Analíticas", "header.anthropicCompatible": "Compatible con Anthropic", "home.quickStartDesc": "Empieza en 4 pasos. Conecta proveedores, enruta modelos y monitorea todo.", "home.fullDocs": "Documentación completa", "home.step1Desc": "Ve a Endpoint -> Claves registradas. Genera una clave por entorno.", "home.step2Desc": "Agrega cuentas en Proveedores. Soporta OAuth, API Key y planes gratuitos.", "home.step3Title": "3. Configura tu cliente", "home.step3Desc": "Configura la URL base como {url} en tu IDE o cliente API.", "home.step4Desc": "Supervisa tokens, costos y errores en Registros y Analíticas.", "home.requestsShort": "{count} reqs", "auth.unifiedProxy": "Proxy de API de IA unificado", "auth.unifiedAiApiProxy": "Proxy de API de IA unificado", "auth.runOnboardingWizard": "Ejecuta el asistente de onboarding para configurar tu contraseña y conectar tu primer proveedor de IA.", "auth.stopServer": "Detén el servidor OmniRoute", "auth.copyUrlManual": "Copia la URL de la barra de direcciones y pégala en la aplicación.", "auth.methodManualDescription": "Elimina la contraseña de la base de datos y configura una nueva al iniciar:", "auth.setPasswordInYour": "Define una nueva contraseña en tu", "auth.restartServerWithNewPassword": "Reinicia el servidor; usará la nueva contraseña", }, fr: { "sidebar.docs": "Documentation", "header.providerDescription": "Gérez vos connexions aux fournisseurs d'IA", "header.comboDescription": "Combinaisons de modèles avec bascule de secours", "header.analytics": "Analytique", "header.anthropicCompatible": "Compatible Anthropic", "home.quickStartDesc": "Démarrez en 4 étapes. Connectez des fournisseurs, routez les modèles et surveillez tout.", "home.fullDocs": "Documentation complète", "home.step1Desc": "Allez dans Endpoint -> Clés enregistrées. Générez une clé par environnement.", "home.step2Title": "2. Connecter des fournisseurs", "home.step2Desc": "Ajoutez des comptes dans Providers. Prend en charge OAuth, API Key et paliers gratuits.", "home.step3Title": "3. Configurer votre client", "home.step3Desc": "Définissez l'URL de base sur {url} dans votre IDE ou client API.", "home.step4Desc": "Suivez les tokens, les coûts et les erreurs dans Journaux des requêtes et Analytique.", "home.requestsShort": "{count} reqs", "auth.runOnboardingWizard": "Exécutez l'assistant d'onboarding pour configurer votre mot de passe et connecter votre premier fournisseur d'IA.", "auth.copyUrlManual": "Copiez l'URL depuis la barre d'adresse et collez-la dans l'application.", "auth.newPasswordPlaceholder": "votre_nouveau_mot_de_passe", }, de: { "sidebar.dashboard": "Dashboard", "header.analytics": "Analysen", "header.anthropicCompatible": "Anthropic-kompatibel", "home.step1Desc": "Gehen Sie zu Endpoint -> Registrierte Schlüssel. Erstellen Sie einen Schlüssel pro Umgebung.", "home.step2Desc": "Fügen Sie Konten unter Providers hinzu. Unterstützt OAuth, API Key und kostenlose Stufen.", "home.step3Title": "3. Client konfigurieren", "home.step4Desc": "Verfolgen Sie Tokens, Kosten und Fehler in Anfrageprotokollen und Analysen.", "home.requestsShort": "{count} Anfr.", "auth.unifiedProxy": "Einheitlicher KI-API-Proxy", "auth.unifiedAiApiProxy": "Einheitlicher KI-API-Proxy", "auth.setPasswordInYour": "Legen Sie ein neues Passwort in Ihrer", "auth.newPasswordPlaceholder": "ihr_neues_passwort", "auth.copyUrlManual": "Kopieren Sie die URL aus der Adressleiste und fügen Sie sie in die Anwendung ein.", }, ja: { "common.disabled": "無効", "common.columns": "列", "common.newest": "新しい順", "common.oldest": "古い順", "header.providerDescription": "AI プロバイダー接続を管理します", "header.comboDescription": "フォールバック付きのモデルコンボ", "header.analytics": "アナリティクス", "header.settingsDescription": "設定を管理します", "header.anthropicCompatible": "Anthropic 互換", "home.quickStartDesc": "4 ステップでセットアップ完了。プロバイダー接続、モデルルーティング、監視まで一括で行えます。", "home.fullDocs": "完全版ドキュメント", "home.step1Desc": "Endpoint -> Registered Keys に移動し、環境ごとに 1 つのキーを作成します。", "home.step2Title": "2. プロバイダーを接続", "home.step2Desc": "Providers でアカウントを追加します。OAuth、API Key、無料枠に対応しています。", "home.step3Title": "3. クライアントを設定", "home.step3Desc": "IDE または API クライアントの Base URL を {url} に設定します。", "home.step4Desc": "リクエストログアナリティクス でトークン・コスト・エラーを追跡します。", "home.requestsShort": "{count} 件", "auth.runOnboardingWizard": "オンボーディングウィザードを実行して、パスワード設定と最初の AI プロバイダー接続を行います。", "auth.stopServer": "OmniRoute サーバーを停止", "auth.copyUrlManual": "アドレスバーの URL をコピーしてアプリケーションに貼り付けてください。", "auth.methodManualDescription": "データベースからパスワードを削除し、起動時に新しいパスワードを設定します:", "auth.setPasswordInYour": "次のファイルで新しいパスワードを設定してください", "auth.newPasswordPlaceholder": "あなたの新しいパスワード", "auth.restartServerWithNewPassword": "サーバーを再起動すると新しいパスワードが適用されます", }, ar: { "common.disabled": "غير مفعّل", "sidebar.providers": "المزوّدون", "sidebar.apiManager": "مدير API", "header.providers": "المزوّدون", "header.providerDescription": "إدارة اتصالات مزوّدي الذكاء الاصطناعي", "header.comboDescription": "مجموعات نماذج مع التبديل الاحتياطي", "header.anthropicCompatible": "متوافق مع Anthropic", "home.quickStartDesc": "ابدأ خلال 4 خطوات: وصّل المزوّدين، فعّل توجيه النماذج، وراقب كل شيء.", "home.fullDocs": "التوثيق الكامل", "home.step1Desc": "انتقل إلى Endpoint -> Registered Keys. أنشئ مفتاحًا واحدًا لكل بيئة.", "home.step2Desc": "أضف الحسابات في Providers. يدعم OAuth وAPI Key والخطط المجانية.", "home.step3Title": "3. اضبط عميلك", "home.step3Desc": "عيّن عنوان Base URL إلى {url} في IDE أو عميل API لديك.", "home.step4Desc": "تتبّع الرموز والتكلفة والأخطاء في سجلات الطلبات والتحليلات.", "home.requestsShort": "{count} طلب", "auth.unifiedProxy": "وكيل API موحّد للذكاء الاصطناعي", "auth.unifiedAiApiProxy": "وكيل API موحّد للذكاء الاصطناعي", "auth.copyUrlManual": "انسخ عنوان URL من شريط العنوان والصقه داخل التطبيق.", "auth.setPasswordInYour": "عيّن كلمة مرور جديدة في ملف", "auth.newPasswordPlaceholder": "كلمة_مرور_جديدة", "auth.restartServerWithNewPassword": "أعد تشغيل الخادم وسيتم استخدام كلمة المرور الجديدة", }, }; const README_PREFIX_OVERRIDES = { "README.es.md": "🌐 **Disponible en:**", "README.fr.md": "🌐 **Disponible en :**", "README.de.md": "🌐 **Verfügbar in:**", "README.ja.md": "🌐 **対応言語:**", "README.ar.md": "🌐 **متوفر باللغات:**", }; const README_NAV_OVERRIDES = { "README.ja.md": "[🌐 ウェブサイト](https://omniroute.online) • [🚀 クイックスタート](#-クイックスタート) • [💡 主な機能](#-主な機能) • [📖 ドキュメント](#-ドキュメント) • [💰 料金](#-価格の概要) • [💬 WhatsApp](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)", "README.ar.md": "[🌐 الموقع](https://omniroute.online) • [🚀 البداية السريعة](#-بداية-سريعة) • [💡 الميزات](#-الميزات-الرئيسية) • [📖 التوثيق](#-التوثيق) • [💰 الأسعار](#-لمحة-سريعة-عن-الأسعار) • [💬 WhatsApp](https://chat.whatsapp.com/JI7cDQ1GyaiDHhVBpLxf8b?mode=gi_t)", }; function setByPath(target, pathStr, value) { const tokens = pathStr.split("."); let current = target; for (let i = 0; i < tokens.length - 1; i += 1) { if (tokens[i] === "__proto__" || tokens[i] === "constructor" || tokens[i] === "prototype") continue; if (typeof current[tokens[i]] !== "object") current[tokens[i]] = {}; current = current[tokens[i]]; } const last = tokens[tokens.length - 1]; if (last !== "__proto__" && last !== "constructor" && last !== "prototype") { current[last] = value; } } async function applyMessageOverrides() { for (const [locale, overrides] of Object.entries(MESSAGE_OVERRIDES)) { const file = path.join(MESSAGES_DIR, `${locale}.json`); const data = JSON.parse(await fs.readFile(file, "utf8")); for (const [key, value] of Object.entries(overrides)) { setByPath(data, key, value); } await fs.writeFile(file, `${JSON.stringify(data, null, 2)}\n`, "utf8"); } } function replaceLineByPrefix(content, prefix, replacement) { const lines = content.split("\n"); const idx = lines.findIndex((line) => line.startsWith(prefix)); if (idx >= 0) { lines[idx] = replacement; } return lines.join("\n"); } function removeEnglishPortugueseAnchorLine(content) { const lines = content.split("\n"); const filtered = lines.filter( (line) => !line.includes( "**[English](#-omniroute--the-free-ai-gateway)** | **[Português (BR)](#-omniroute--gateway-de-ia-gratuito)**" ) ); return filtered.join("\n"); } function removeBrazilianAppendixSection(content) { const marker = "\n## 🇧🇷 OmniRoute"; const idx = content.indexOf(marker); if (idx === -1) { return content; } return content.slice(0, idx).trimEnd() + "\n"; } async function applyReadmeOverrides() { for (const [fileName, localizedPrefix] of Object.entries(README_PREFIX_OVERRIDES)) { const filePath = path.join(ROOT, fileName); let content = await fs.readFile(filePath, "utf8"); content = content.replace("🌐 **Available in:**", localizedPrefix); if (README_NAV_OVERRIDES[fileName]) { content = replaceLineByPrefix(content, "[🌐 Website]", README_NAV_OVERRIDES[fileName]); content = removeEnglishPortugueseAnchorLine(content); content = removeBrazilianAppendixSection(content); } await fs.writeFile(filePath, content, "utf8"); } } async function main() { await applyMessageOverrides(); await applyReadmeOverrides(); console.log("priority overrides applied"); } main().catch((error) => { console.error(error); process.exit(1); });