Integrar LibreTranslate para traducao automatica

This commit is contained in:
Erik
2025-11-26 21:15:17 -03:00
parent 0bde8d4a56
commit 6044a437f8
5 changed files with 357 additions and 0 deletions

View File

@@ -0,0 +1,134 @@
'use client';
import { useEffect, useState, ElementType, ComponentPropsWithoutRef } from 'react';
import { useTranslate } from '@/hooks/useTranslate';
interface TranslatedTextProps {
text: string;
as?: 'span' | 'p' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'div' | 'li';
className?: string;
}
/**
* Componente que traduz texto automaticamente via LibreTranslate
* quando o idioma não é português
*/
export function TranslatedText({ text, as = 'span', className }: TranslatedTextProps) {
const { translate, language } = useTranslate();
const [translatedText, setTranslatedText] = useState(text);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
if (language === 'PT') {
setTranslatedText(text);
return;
}
let cancelled = false;
setIsLoading(true);
translate(text).then((result) => {
if (!cancelled) {
setTranslatedText(result);
setIsLoading(false);
}
});
return () => {
cancelled = true;
};
}, [text, language, translate]);
const Tag = as;
return (
<Tag className={className} data-translating={isLoading}>
{translatedText}
</Tag>
);
}
/**
* Hook para traduzir objetos de conteúdo do banco de dados
*/
export function useTranslatedContent<T extends Record<string, unknown>>(content: T): {
translatedContent: T;
isTranslating: boolean
} {
const { translateBatch, language } = useTranslate();
const [translatedContent, setTranslatedContent] = useState<T>(content);
const [isTranslating, setIsTranslating] = useState(false);
useEffect(() => {
if (language === 'PT') {
setTranslatedContent(content);
return;
}
let cancelled = false;
const translateContent = async () => {
setIsTranslating(true);
// Extrair todos os textos do objeto
const texts: string[] = [];
const paths: string[] = [];
const extractTexts = (obj: unknown, path: string = '') => {
if (typeof obj === 'string' && obj.length > 0) {
texts.push(obj);
paths.push(path);
} else if (Array.isArray(obj)) {
obj.forEach((item, index) => extractTexts(item, `${path}[${index}]`));
} else if (obj && typeof obj === 'object') {
Object.entries(obj).forEach(([key, value]) => {
extractTexts(value, path ? `${path}.${key}` : key);
});
}
};
extractTexts(content);
if (texts.length === 0) {
setIsTranslating(false);
return;
}
try {
const translations = await translateBatch(texts);
if (cancelled) return;
// Reconstruir objeto com traduções
const newContent = JSON.parse(JSON.stringify(content));
paths.forEach((path, index) => {
const parts = path.replace(/\[(\d+)\]/g, '.$1').split('.');
let current: Record<string, unknown> = newContent;
for (let i = 0; i < parts.length - 1; i++) {
current = current[parts[i]] as Record<string, unknown>;
}
current[parts[parts.length - 1]] = translations[index];
});
setTranslatedContent(newContent);
} catch (error) {
console.error('Translation error:', error);
} finally {
if (!cancelled) {
setIsTranslating(false);
}
}
};
translateContent();
return () => {
cancelled = true;
};
}, [content, language, translateBatch]);
return { translatedContent, isTranslating };
}