Mejora traducción bot Discord: detección de imágenes/videos y preservación de emojis

- Evita mostrar botones de traducción en mensajes con solo imágenes/videos
- Detecta y traduce captions de imágenes/videos
- Preserva emojis, menciones y elementos de Discord durante traducción
- Soluciona problema de placeholders en emojis Unicode estándar
This commit is contained in:
2026-02-07 20:03:56 -06:00
parent d1ec6bed5c
commit 7af0e95e0b

View File

@@ -104,8 +104,10 @@ try {
return;
}
// Extraer y preservar emojis, stickers y elementos de Discord
$processedContent = preserveDiscordElements($originalContent);
$translator = new Translate(LIBRETRANSLATE_URL);
$sourceLang = $translator->detectLanguage($originalContent) ?? 'es';
$sourceLang = $translator->detectLanguage($processedContent['text']) ?? 'es';
if ($sourceLang === $targetLang) {
$interaction->respondWithMessage(
@@ -115,7 +117,10 @@ try {
return;
}
$translatedText = $translator->translateText($originalContent, $sourceLang, $targetLang);
$translatedText = $translator->translateText($processedContent['text'], $sourceLang, $targetLang);
// Restaurar emojis y elementos de Discord
$finalText = restoreDiscordElements($translatedText, $processedContent['placeholders']);
// Obtener bandera
$stmt = $pdo->prepare("SELECT flag_emoji FROM supported_languages WHERE language_code = ? AND is_active = 1");
@@ -125,7 +130,7 @@ try {
$flag = $flag !== '' ? $flag : '🏳️';
// Responder efímeramente con la traducción
$response = "{$flag} **Traducción ({$sourceLang}{$targetLang}):**\n\n" . $translatedText;
$response = "{$flag} **Traducción ({$sourceLang}{$targetLang}):**\n\n" . $finalText;
$interaction->respondWithMessage(
MessageBuilder::new()->setContent($response),
true // Efímero - solo visible para el usuario
@@ -154,8 +159,10 @@ try {
return;
}
// Extraer y preservar emojis, stickers y elementos de Discord
$processedContent = preserveDiscordElements($originalContent);
$translator = new Translate(LIBRETRANSLATE_URL);
$sourceLang = $translator->detectLanguage($originalContent) ?? 'es';
$sourceLang = $translator->detectLanguage($processedContent['text']) ?? 'es';
if ($sourceLang === $targetLang) {
$interaction->respondWithMessage(
@@ -165,7 +172,10 @@ try {
return;
}
$translatedText = $translator->translateText($originalContent, $sourceLang, $targetLang);
$translatedText = $translator->translateText($processedContent['text'], $sourceLang, $targetLang);
// Restaurar emojis y elementos de Discord
$finalText = restoreDiscordElements($translatedText, $processedContent['placeholders']);
// Obtener bandera
$stmt = $pdo->prepare("SELECT flag_emoji FROM supported_languages WHERE language_code = ? AND is_active = 1");
@@ -175,7 +185,7 @@ try {
$flag = $flag !== '' ? $flag : '🏳️';
// Responder efímeramente con la traducción
$response = "{$flag} **Traducción ({$sourceLang}{$targetLang}):**\n\n" . $translatedText;
$response = "{$flag} **Traducción ({$sourceLang}{$targetLang}):**\n\n" . $finalText;
$interaction->respondWithMessage(
MessageBuilder::new()->setContent($response),
true // Efímero - solo visible para el usuario
@@ -550,8 +560,39 @@ function handleDiscordTranslation(Message $message, PDO $pdo, Logger $logger)
{
try {
$text = $message->content;
$attachments = $message->attachments;
// Verificar si el mensaje tiene contenido de texto
$hasTextContent = !empty(trim($text));
// Verificar si hay texto en los attachments (captions de imágenes/videos)
$attachmentText = '';
if (!empty($attachments)) {
foreach ($attachments as $attachment) {
// Algunos attachments tienen propiedad 'description' o 'caption'
if (!empty($attachment->description)) {
$attachmentText .= $attachment->description . ' ';
}
if (!empty($attachment->caption)) {
$attachmentText .= $attachment->caption . ' ';
}
}
}
// Combinar texto principal con texto de attachments
$fullText = trim($text . ' ' . $attachmentText);
$hasAnyText = !empty($fullText);
// Verificar si el mensaje tiene solo imágenes/adjuntos sin texto
$hasOnlyAttachments = !$hasAnyText && !empty($attachments) && count($attachments) > 0;
// Si el mensaje no tiene texto o tiene solo imágenes, no mostrar botones de traducción
if (!$hasAnyText || $hasOnlyAttachments) {
$logger->info("[TRADUCCIÓN] Mensaje #{$message->id} no tiene contenido de texto, omitiendo botones de traducción.");
return;
}
$translator = new Translate(LIBRETRANSLATE_URL);
$detectedLang = $translator->detectLanguage(strip_tags($text)) ?? 'es';
$detectedLang = $translator->detectLanguage(strip_tags($fullText)) ?? 'es';
// Obtener idiomas activos disponibles
$langStmt = $pdo->query("SELECT language_code, language_name, flag_emoji FROM supported_languages WHERE is_active = 1");
@@ -596,7 +637,7 @@ function handleDiscordTranslation(Message $message, PDO $pdo, Logger $logger)
// Enviar mensaje con botones efímeros
$builder = MessageBuilder::new()
->setContent("🌍 **Selecciona idioma para traducir:**")
// ->setContent("🌍 **Selecciona idioma para traducir:**")
->setComponents($components);
$message->reply($builder, true); // true = ephemeral (solo visible para el usuario)
@@ -607,3 +648,53 @@ function handleDiscordTranslation(Message $message, PDO $pdo, Logger $logger)
$logger->error("[Error Traducción Discord]", ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
}
}
/**
* Función para preservar emojis, stickers y elementos de Discord durante la traducción
*/
function preserveDiscordElements($text) {
$placeholders = [];
$processedText = $text;
// Patrones para detectar elementos de Discord (excluyendo emojis Unicode)
$patterns = [
// Emojis personalizados de Discord <:name:id>
'/<a?:([a-zA-Z0-9_]+):(\d+)>/',
// Menciones de usuarios <@id> y <@!id>
'/<@!?(\d+)>/',
// Menciones de canales <#id>
'/<#(\d+)>/',
// Menciones de roles <@&id>
'/<@&(\d+)>/',
// Stickers y GIFs animados (pueden venir como URLs especiales)
'/https?:\/\/(?:media|cdn)\.discordapp\.(?:com|net)\/(stickers|attachments)\/\S+/i'
];
$index = 0;
foreach ($patterns as $pattern) {
$processedText = preg_replace_callback($pattern, function($matches) use (&$placeholders, &$index) {
$placeholder = "DISCORD_ELEMENT_{$index}";
$placeholders[$placeholder] = $matches[0];
$index++;
return $placeholder;
}, $processedText);
}
return [
'text' => $processedText,
'placeholders' => $placeholders
];
}
/**
* Función para restaurar emojis, stickers y elementos de Discord después de la traducción
*/
function restoreDiscordElements($translatedText, $placeholders) {
$restoredText = $translatedText;
foreach ($placeholders as $placeholder => $originalElement) {
$restoredText = str_replace($placeholder, $originalElement, $restoredText);
}
return $restoredText;
}