import { NextRequest, NextResponse } from 'next/server'; import prisma from '@/lib/prisma'; import { cookies } from 'next/headers'; import jwt from 'jsonwebtoken'; import { Prisma } from '@prisma/client'; const LIBRETRANSLATE_URL = process.env.LIBRETRANSLATE_URL || 'https://libretranslate.stackbyte.cloud'; const SUPPORTED_LOCALES = ['en', 'es']; // Autenticação async function authenticate() { const cookieStore = await cookies(); const token = cookieStore.get('auth_token')?.value; if (!token) return null; try { const decoded = jwt.verify(token, process.env.JWT_SECRET!) as { userId: string }; const user = await prisma.user.findUnique({ where: { id: decoded.userId }, select: { id: true, email: true, name: true } }); return user; } catch { return null; } } // Traduzir um texto async function translateText(text: string, targetLang: string): Promise { 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) { return cached.translatedText; } try { console.log(`[i18n] Traduzindo: "${text.substring(0, 30)}..." para ${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(`[i18n] Erro ao traduzir para ${targetLang}:`, error); } return text; } // Traduzir objeto recursivamente async function translateContent(content: unknown, targetLang: string): Promise { 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: Record = {}; for (const [key, value] of Object.entries(content)) { // Não traduzir campos técnicos if (['icon', 'image', 'img', 'url', 'href', 'id', 'slug', 'src', 'link'].includes(key)) { result[key] = value; } else { result[key] = await translateContent(value, targetLang); } } return result; } return content; } // POST /api/admin/translate-pages - Traduzir todas as páginas para EN e ES export async function POST(request: NextRequest) { try { const user = await authenticate(); if (!user) { return NextResponse.json({ error: 'Não autorizado' }, { status: 401 }); } const body = await request.json().catch(() => ({})); const slugFilter = body.slug; // Opcional: traduzir só uma página específica // Buscar todas as páginas em português const ptPages = await prisma.pageContent.findMany({ where: slugFilter ? { slug: slugFilter, locale: 'pt' } : { locale: 'pt' } }); if (ptPages.length === 0) { return NextResponse.json({ error: 'Nenhuma página encontrada para traduzir' }, { status: 404 }); } const results: { slug: string; locale: string; status: string }[] = []; for (const page of ptPages) { for (const targetLocale of SUPPORTED_LOCALES) { try { console.log(`[i18n] Traduzindo página "${page.slug}" para ${targetLocale}...`); const translatedContent = await translateContent(page.content, targetLocale) as Prisma.InputJsonValue; await prisma.pageContent.upsert({ where: { slug_locale: { slug: page.slug, locale: targetLocale } }, update: { content: translatedContent }, create: { slug: page.slug, locale: targetLocale, content: translatedContent } }); results.push({ slug: page.slug, locale: targetLocale, status: 'success' }); console.log(`[i18n] ✓ Página "${page.slug}" traduzida para ${targetLocale}`); } catch (error) { console.error(`[i18n] ✗ Erro ao traduzir "${page.slug}" para ${targetLocale}:`, error); results.push({ slug: page.slug, locale: targetLocale, status: 'error' }); } } } return NextResponse.json({ success: true, message: `Tradução concluída para ${ptPages.length} página(s)`, results }); } catch (error) { console.error('Erro ao traduzir páginas:', error); return NextResponse.json({ error: 'Erro ao traduzir páginas' }, { status: 500 }); } } // GET /api/admin/translate-pages - Status das traduções export async function GET() { try { const pages = await prisma.pageContent.findMany({ select: { slug: true, locale: true, updatedAt: true }, orderBy: [{ slug: 'asc' }, { locale: 'asc' }] }); // Agrupar por slug const grouped: Record = {}; for (const page of pages) { if (!grouped[page.slug]) { grouped[page.slug] = {}; } grouped[page.slug][page.locale as 'pt' | 'en' | 'es'] = page.updatedAt; } return NextResponse.json({ pages: grouped }); } catch (error) { console.error('Erro ao buscar status:', error); return NextResponse.json({ error: 'Erro ao buscar status' }, { status: 500 }); } }