// Script para traduzir todas as páginas PT para EN e ES // Executar: node prisma/translate-pages.mjs import { PrismaClient } from '@prisma/client'; const prisma = new PrismaClient(); const LIBRETRANSLATE_URL = process.env.LIBRETRANSLATE_URL || 'https://libretranslate.stackbyte.cloud'; const SUPPORTED_LOCALES = ['en', 'es']; // Traduzir um texto async function translateText(text, targetLang) { if (!text || text.trim() === '' || targetLang === 'pt') return text; // Verificar cache no banco primeiro const cached = await prisma.translation.findUnique({ where: { sourceText_sourceLang_targetLang: { sourceText: text, sourceLang: 'pt', targetLang: targetLang, }, }, }); if (cached) { console.log(` [cache] "${text.substring(0, 25)}..."`); return cached.translatedText; } try { console.log(` [traduzindo] "${text.substring(0, 25)}..." -> ${targetLang}`); const response = await fetch(`${LIBRETRANSLATE_URL}/translate`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ q: text, source: 'pt', target: targetLang, format: 'text' }), }); if (response.ok) { const data = await response.json(); const translatedText = data.translatedText || text; // Salvar no cache try { await prisma.translation.create({ data: { sourceText: text, sourceLang: 'pt', targetLang: targetLang, translatedText, }, }); } catch { // Ignorar se já existe } return translatedText; } } catch (error) { console.error(` [erro] ${error.message}`); } return text; } // Traduzir objeto recursivamente async function translateContent(content, targetLang) { if (typeof content === 'string') { return await translateText(content, targetLang); } if (Array.isArray(content)) { const results = []; for (const item of content) { results.push(await translateContent(item, targetLang)); } return results; } if (content && typeof content === 'object') { const result = {}; for (const [key, value] of Object.entries(content)) { // Não traduzir campos técnicos if (['icon', 'image', 'img', 'url', 'href', 'id', 'slug', 'src', 'link', 'linkText'].includes(key)) { result[key] = value; } else { result[key] = await translateContent(value, targetLang); } } return result; } return content; } async function main() { console.log('🌐 Iniciando tradução de páginas...\n'); console.log(`📡 LibreTranslate: ${LIBRETRANSLATE_URL}\n`); // Buscar todas as páginas em português const ptPages = await prisma.pageContent.findMany({ where: { locale: 'pt' } }); if (ptPages.length === 0) { console.log('❌ Nenhuma página encontrada em português'); return; } console.log(`📄 Encontradas ${ptPages.length} páginas em PT\n`); for (const page of ptPages) { console.log(`\n📝 Página: ${page.slug}`); console.log('─'.repeat(40)); for (const targetLocale of SUPPORTED_LOCALES) { console.log(`\n 🔄 Traduzindo para ${targetLocale.toUpperCase()}...`); try { const translatedContent = await translateContent(page.content, targetLocale); await prisma.pageContent.upsert({ where: { slug_locale: { slug: page.slug, locale: targetLocale } }, update: { content: translatedContent }, create: { slug: page.slug, locale: targetLocale, content: translatedContent } }); console.log(` ✅ ${page.slug} -> ${targetLocale.toUpperCase()} concluído!`); } catch (error) { console.error(` ❌ Erro: ${error.message}`); } } } console.log('\n' + '═'.repeat(40)); console.log('✨ Tradução concluída!'); console.log('═'.repeat(40)); } main() .catch((e) => { console.error('Erro:', e); process.exit(1); }) .finally(async () => { await prisma.$disconnect(); });