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:
107
discord_bot.php
107
discord_bot.php
@@ -104,8 +104,10 @@ try {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extraer y preservar emojis, stickers y elementos de Discord
|
||||||
|
$processedContent = preserveDiscordElements($originalContent);
|
||||||
$translator = new Translate(LIBRETRANSLATE_URL);
|
$translator = new Translate(LIBRETRANSLATE_URL);
|
||||||
$sourceLang = $translator->detectLanguage($originalContent) ?? 'es';
|
$sourceLang = $translator->detectLanguage($processedContent['text']) ?? 'es';
|
||||||
|
|
||||||
if ($sourceLang === $targetLang) {
|
if ($sourceLang === $targetLang) {
|
||||||
$interaction->respondWithMessage(
|
$interaction->respondWithMessage(
|
||||||
@@ -115,7 +117,10 @@ try {
|
|||||||
return;
|
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
|
// Obtener bandera
|
||||||
$stmt = $pdo->prepare("SELECT flag_emoji FROM supported_languages WHERE language_code = ? AND is_active = 1");
|
$stmt = $pdo->prepare("SELECT flag_emoji FROM supported_languages WHERE language_code = ? AND is_active = 1");
|
||||||
@@ -125,7 +130,7 @@ try {
|
|||||||
$flag = $flag !== '' ? $flag : '🏳️';
|
$flag = $flag !== '' ? $flag : '🏳️';
|
||||||
|
|
||||||
// Responder efímeramente con la traducción
|
// 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(
|
$interaction->respondWithMessage(
|
||||||
MessageBuilder::new()->setContent($response),
|
MessageBuilder::new()->setContent($response),
|
||||||
true // Efímero - solo visible para el usuario
|
true // Efímero - solo visible para el usuario
|
||||||
@@ -154,8 +159,10 @@ try {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Extraer y preservar emojis, stickers y elementos de Discord
|
||||||
|
$processedContent = preserveDiscordElements($originalContent);
|
||||||
$translator = new Translate(LIBRETRANSLATE_URL);
|
$translator = new Translate(LIBRETRANSLATE_URL);
|
||||||
$sourceLang = $translator->detectLanguage($originalContent) ?? 'es';
|
$sourceLang = $translator->detectLanguage($processedContent['text']) ?? 'es';
|
||||||
|
|
||||||
if ($sourceLang === $targetLang) {
|
if ($sourceLang === $targetLang) {
|
||||||
$interaction->respondWithMessage(
|
$interaction->respondWithMessage(
|
||||||
@@ -165,7 +172,10 @@ try {
|
|||||||
return;
|
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
|
// Obtener bandera
|
||||||
$stmt = $pdo->prepare("SELECT flag_emoji FROM supported_languages WHERE language_code = ? AND is_active = 1");
|
$stmt = $pdo->prepare("SELECT flag_emoji FROM supported_languages WHERE language_code = ? AND is_active = 1");
|
||||||
@@ -175,7 +185,7 @@ try {
|
|||||||
$flag = $flag !== '' ? $flag : '🏳️';
|
$flag = $flag !== '' ? $flag : '🏳️';
|
||||||
|
|
||||||
// Responder efímeramente con la traducción
|
// 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(
|
$interaction->respondWithMessage(
|
||||||
MessageBuilder::new()->setContent($response),
|
MessageBuilder::new()->setContent($response),
|
||||||
true // Efímero - solo visible para el usuario
|
true // Efímero - solo visible para el usuario
|
||||||
@@ -550,8 +560,39 @@ function handleDiscordTranslation(Message $message, PDO $pdo, Logger $logger)
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
$text = $message->content;
|
$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);
|
$translator = new Translate(LIBRETRANSLATE_URL);
|
||||||
$detectedLang = $translator->detectLanguage(strip_tags($text)) ?? 'es';
|
$detectedLang = $translator->detectLanguage(strip_tags($fullText)) ?? 'es';
|
||||||
|
|
||||||
// Obtener idiomas activos disponibles
|
// Obtener idiomas activos disponibles
|
||||||
$langStmt = $pdo->query("SELECT language_code, language_name, flag_emoji FROM supported_languages WHERE is_active = 1");
|
$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
|
// Enviar mensaje con botones efímeros
|
||||||
$builder = MessageBuilder::new()
|
$builder = MessageBuilder::new()
|
||||||
->setContent("🌍 **Selecciona idioma para traducir:**")
|
// ->setContent("🌍 **Selecciona idioma para traducir:**")
|
||||||
->setComponents($components);
|
->setComponents($components);
|
||||||
|
|
||||||
$message->reply($builder, true); // true = ephemeral (solo visible para el usuario)
|
$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()]);
|
$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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user