Files
octto-engenharia/frontend/src/app/api/admin/translate-pages/route.ts

194 lines
5.9 KiB
TypeScript

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<string> {
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<unknown> {
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<string, unknown> = {};
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<string, { pt?: Date; en?: Date; es?: Date }> = {};
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 });
}
}