- Cambiar de deferReply() a respondWithMessage() para garantizar respuesta en <3s - Responder inmediatamente con mensaje de carga - Actualizar respuesta con traducción completa - Agregar caché de traducciones para evitar llamadas repetidas a LibreTranslate - Caché guardar en archivos temporales con validez de 30 días Soluciona: 'Interacción fallida' en traducción al inglés y otros idiomas
205 lines
5.9 KiB
PHP
Executable File
205 lines
5.9 KiB
PHP
Executable File
<?php
|
|
|
|
namespace src;
|
|
|
|
class Translate
|
|
{
|
|
private string $url;
|
|
private array $supportedLanguages = [];
|
|
|
|
public function __construct()
|
|
{
|
|
$this->url = $_ENV['LIBRETRANSLATE_URL'] ?? getenv('LIBRETRANSLATE_URL') ?? 'http://localhost:5000';
|
|
}
|
|
|
|
public function detectLanguage(string $text): ?string
|
|
{
|
|
try {
|
|
$response = $this->request('/detect', ['q' => $text]);
|
|
|
|
if (!empty($response)) {
|
|
return $response[0]['language'] ?? null;
|
|
}
|
|
} catch (\Exception $e) {
|
|
error_log("Language detection error: " . $e->getMessage());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public function translate(string $text, string $sourceLang, string $targetLang): ?string
|
|
{
|
|
if ($sourceLang === $targetLang) {
|
|
return $text;
|
|
}
|
|
|
|
try {
|
|
// Primero intentar obtener del caché
|
|
$cacheKey = $this->generateCacheKey($text, $sourceLang, $targetLang);
|
|
$cached = $this->getFromCache($cacheKey);
|
|
|
|
if ($cached !== null) {
|
|
error_log("Translation cache hit for: $sourceLang -> $targetLang");
|
|
return $cached;
|
|
}
|
|
|
|
$lines = explode("\n", $text);
|
|
$translatedLines = [];
|
|
|
|
foreach ($lines as $line) {
|
|
if (trim($line) === '') {
|
|
$translatedLines[] = '';
|
|
continue;
|
|
}
|
|
|
|
$response = $this->request('/translate', [
|
|
'q' => trim($line),
|
|
'source' => $sourceLang,
|
|
'target' => $targetLang,
|
|
'format' => 'text'
|
|
]);
|
|
|
|
$translatedLines[] = $response['translatedText'] ?? trim($line);
|
|
}
|
|
|
|
$result = implode("\n", $translatedLines);
|
|
|
|
// Guardar en caché
|
|
$this->saveToCache($cacheKey, $result);
|
|
|
|
return $result;
|
|
} catch (\Exception $e) {
|
|
error_log("Translation error: " . $e->getMessage());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public function translateToMultiple(string $text, string $sourceLang, array $targetLangs): array
|
|
{
|
|
$results = [];
|
|
|
|
foreach ($targetLangs as $lang) {
|
|
$results[$lang] = $this->translate($text, $sourceLang, $lang);
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
public function getSupportedLanguages(): array
|
|
{
|
|
if (!empty($this->supportedLanguages)) {
|
|
return $this->supportedLanguages;
|
|
}
|
|
|
|
try {
|
|
$response = $this->request('/languages');
|
|
$this->supportedLanguages = $response;
|
|
return $response;
|
|
} catch (\Exception $e) {
|
|
error_log("Get languages error: " . $e->getMessage());
|
|
return [];
|
|
}
|
|
}
|
|
|
|
public function isLanguageSupported(string $langCode): bool
|
|
{
|
|
$languages = $this->getSupportedLanguages();
|
|
|
|
foreach ($languages as $lang) {
|
|
if ($lang['code'] === $langCode) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private function request(string $endpoint, array $data = []): array
|
|
{
|
|
$url = $this->url . $endpoint;
|
|
|
|
$ch = curl_init($url);
|
|
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
|
|
|
if (!empty($data)) {
|
|
curl_setopt($ch, CURLOPT_POST, true);
|
|
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
|
|
curl_setopt($ch, CURLOPT_HTTPHEADER, [
|
|
'Content-Type: application/x-www-form-urlencoded'
|
|
]);
|
|
}
|
|
|
|
$response = curl_exec($ch);
|
|
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
|
curl_close($ch);
|
|
|
|
if ($httpCode >= 400) {
|
|
throw new \Exception("LibreTranslate API Error: HTTP $httpCode");
|
|
}
|
|
|
|
$result = json_decode($response, true);
|
|
|
|
if ($result === null) {
|
|
throw new \Exception("Invalid JSON response from LibreTranslate");
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Genera una clave única para el caché de traducciones
|
|
*/
|
|
private function generateCacheKey(string $text, string $sourceLang, string $targetLang): string
|
|
{
|
|
return md5($text . $sourceLang . $targetLang);
|
|
}
|
|
|
|
/**
|
|
* Obtiene una traducción del caché
|
|
*/
|
|
private function getFromCache(string $cacheKey): ?string
|
|
{
|
|
try {
|
|
$cacheDir = sys_get_temp_dir() . '/discord_translation_cache';
|
|
if (!is_dir($cacheDir)) {
|
|
mkdir($cacheDir, 0755, true);
|
|
}
|
|
|
|
$cacheFile = $cacheDir . '/' . $cacheKey . '.txt';
|
|
|
|
if (file_exists($cacheFile)) {
|
|
// Verificar que el caché no sea muy antiguo (máximo 30 días)
|
|
$fileAge = time() - filemtime($cacheFile);
|
|
if ($fileAge < (30 * 24 * 60 * 60)) {
|
|
$content = file_get_contents($cacheFile);
|
|
if ($content !== false) {
|
|
return $content;
|
|
}
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
error_log("Cache retrieval error: " . $e->getMessage());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Guarda una traducción en caché
|
|
*/
|
|
private function saveToCache(string $cacheKey, string $translation): void
|
|
{
|
|
try {
|
|
$cacheDir = sys_get_temp_dir() . '/discord_translation_cache';
|
|
if (!is_dir($cacheDir)) {
|
|
mkdir($cacheDir, 0755, true);
|
|
}
|
|
|
|
$cacheFile = $cacheDir . '/' . $cacheKey . '.txt';
|
|
file_put_contents($cacheFile, $translation, LOCK_EX);
|
|
} catch (\Exception $e) {
|
|
error_log("Cache save error: " . $e->getMessage());
|
|
}
|
|
}
|
|
}
|