Files
lastwar/admin/languages.php

466 lines
22 KiB
PHP
Executable File

<?php
require_once __DIR__ . '/../includes/db.php';
require_once __DIR__ . '/../includes/session_check.php';
require_once __DIR__ . '/../includes/activity_logger.php';
require_once __DIR__ . '/../includes/env_loader.php';
require_once __DIR__ . '/../src/Translate.php';
requireAdmin();
$pageTitle = 'Gestión de Idiomas';
$languages = [];
try {
$pdo = getDbConnection();
$stmt = $pdo->query("SELECT * FROM supported_languages ORDER BY language_name");
$languages = $stmt->fetchAll();
} catch (Exception $e) {
$error = $e->getMessage();
}
$syncMessage = '';
$syncError = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
$action = $_POST['action'];
if ($action === 'toggle_status') {
$id = (int) $_POST['id'];
$stmt = $pdo->prepare("UPDATE supported_languages SET is_active = NOT is_active WHERE id = ?");
$stmt->execute([$id]);
logActivity(getCurrentUserId(), 'toggle_language', "Idioma ID: $id");
header('Location: languages.php');
exit;
} elseif ($action === 'update_flag') {
$id = (int) $_POST['id'];
$flag = $_POST['flag_emoji'];
$stmt = $pdo->prepare("UPDATE supported_languages SET flag_emoji = ? WHERE id = ?");
$stmt->execute([$flag, $id]);
header('Location: languages.php');
exit;
} elseif ($action === 'add') {
$code = $_POST['language_code'];
$name = $_POST['language_name'];
$flag = $_POST['flag_emoji'];
$stmt = $pdo->prepare("INSERT INTO supported_languages (language_code, language_name, flag_emoji, is_active) VALUES (?, ?, ?, FALSE)");
$stmt->execute([$code, $name, $flag]);
logActivity(getCurrentUserId(), 'add_language', "Idioma agregado: $name");
header('Location: languages.php');
exit;
} elseif ($action === 'sync_libretranslate') {
try {
$translator = new src\Translate();
$ltLanguages = $translator->getSupportedLanguages();
if (empty($ltLanguages)) {
$syncError = "No se pudieron obtener los idiomas de LibreTranslate. Verifica que el servicio esté corriendo en: " . ($_ENV['LIBRETRANSLATE_URL'] ?? 'http://localhost:5000');
} else {
$added = 0;
foreach ($ltLanguages as $ltLang) {
$code = $ltLang['code'];
$name = $ltLang['name'];
$stmt = $pdo->prepare("SELECT id FROM supported_languages WHERE language_code = ?");
$stmt->execute([$code]);
if (!$stmt->fetch()) {
$flag = getFlagForLanguage($code);
$stmt = $pdo->prepare("INSERT INTO supported_languages (language_code, language_name, flag_emoji, is_active) VALUES (?, ?, ?, FALSE)");
$stmt->execute([$code, $name, $flag]);
$added++;
}
}
$syncMessage = "Se sincronizaron $added idiomas desde LibreTranslate";
logActivity(getCurrentUserId(), 'sync_languages', "Sincronizados $added idiomas desde LibreTranslate");
}
} catch (Exception $e) {
$syncError = "Error al conectar con LibreTranslate: " . $e->getMessage() . ". Verifica que el servicio esté configurado correctamente en el archivo .env";
}
}
}
// Array completo de banderas con variantes regionales
$availableFlags = [
// Español - Variantes
['code' => 'es-MX', 'flag' => '🇲🇽', 'name' => 'Español (México)'],
['code' => 'es-ES', 'flag' => '🇪🇸', 'name' => 'Español (España)'],
['code' => 'es-AR', 'flag' => '🇦🇷', 'name' => 'Español (Argentina)'],
['code' => 'es-CO', 'flag' => '🇨🇴', 'name' => 'Español (Colombia)'],
['code' => 'es-CL', 'flag' => '🇨🇱', 'name' => 'Español (Chile)'],
['code' => 'es-PE', 'flag' => '🇵🇪', 'name' => 'Español (Perú)'],
['code' => 'es-VE', 'flag' => '🇻🇪', 'name' => 'Español (Venezuela)'],
// Inglés - Variantes
['code' => 'en-US', 'flag' => '🇺🇸', 'name' => 'English (USA)'],
['code' => 'en-GB', 'flag' => '🇬🇧', 'name' => 'English (UK)'],
['code' => 'en-CA', 'flag' => '🇨🇦', 'name' => 'English (Canada)'],
['code' => 'en-AU', 'flag' => '🇦🇺', 'name' => 'English (Australia)'],
// Portugués - Variantes
['code' => 'pt-BR', 'flag' => '🇧🇷', 'name' => 'Português (Brasil)'],
['code' => 'pt-PT', 'flag' => '🇵🇹', 'name' => 'Português (Portugal)'],
// Francés - Variantes
['code' => 'fr-FR', 'flag' => '🇫🇷', 'name' => 'Français (France)'],
['code' => 'fr-CA', 'flag' => '🇨🇦', 'name' => 'Français (Canada)'],
// Alemán
['code' => 'de', 'flag' => '🇩🇪', 'name' => 'Deutsch'],
// Italiano
['code' => 'it', 'flag' => '🇮🇹', 'name' => 'Italiano'],
// Ruso
['code' => 'ru', 'flag' => '🇷🇺', 'name' => 'Русский'],
// Chino - Variantes
['code' => 'zh-CN', 'flag' => '🇨🇳', 'name' => '中文 (简体)'],
['code' => 'zh-TW', 'flag' => '🇹🇼', 'name' => '中文 (繁體)'],
// Japonés
['code' => 'ja', 'flag' => '🇯🇵', 'name' => '日本語'],
// Coreano
['code' => 'ko', 'flag' => '🇰🇷', 'name' => '한국어'],
// Árabe
['code' => 'ar', 'flag' => '🇸🇦', 'name' => 'العربية'],
// Hindi
['code' => 'hi', 'flag' => '🇮🇳', 'name' => 'हिन्दी'],
// Holandés
['code' => 'nl', 'flag' => '🇳🇱', 'name' => 'Nederlands'],
// Polaco
['code' => 'pl', 'flag' => '🇵🇱', 'name' => 'Polski'],
// Turco
['code' => 'tr', 'flag' => '🇹🇷', 'name' => 'Türkçe'],
// Sueco
['code' => 'sv', 'flag' => '🇸🇪', 'name' => 'Svenska'],
// Danés
['code' => 'da', 'flag' => '🇩🇰', 'name' => 'Dansk'],
// Finés
['code' => 'fi', 'flag' => '🇫🇮', 'name' => 'Suomi'],
// Noruego
['code' => 'no', 'flag' => '🇳🇴', 'name' => 'Norsk'],
// Checo
['code' => 'cs', 'flag' => '🇨🇿', 'name' => 'Čeština'],
// Griego
['code' => 'el', 'flag' => '🇬🇷', 'name' => 'Ελληνικά'],
// Hebreo
['code' => 'he', 'flag' => '🇮🇱', 'name' => 'עברית'],
// Tailandés
['code' => 'th', 'flag' => '🇹🇭', 'name' => 'ไทย'],
// Vietnamita
['code' => 'vi', 'flag' => '🇻🇳', 'name' => 'Tiếng Việt'],
// Indonesio
['code' => 'id', 'flag' => '🇮🇩', 'name' => 'Bahasa Indonesia'],
// Malayo
['code' => 'ms', 'flag' => '🇲🇾', 'name' => 'Bahasa Melayu'],
// Ucraniano
['code' => 'uk', 'flag' => '🇺🇦', 'name' => 'Українська'],
// Catalán
['code' => 'ca', 'flag' => '🇪🇸', 'name' => 'Català'],
// Gallego
['code' => 'gl', 'flag' => '🇪🇸', 'name' => 'Galego'],
// Rumano
['code' => 'ro', 'flag' => '🇷🇴', 'name' => 'Română'],
// Húngaro
['code' => 'hu', 'flag' => '🇭🇺', 'name' => 'Magyar'],
// Búlgaro
['code' => 'bg', 'flag' => '🇧🇬', 'name' => 'Български'],
// Otros países importantes
['code' => 'other', 'flag' => '🇦🇹', 'name' => 'Austria'],
['code' => 'other', 'flag' => '🇧🇪', 'name' => 'Bélgica'],
['code' => 'other', 'flag' => '🇨🇭', 'name' => 'Suiza'],
['code' => 'other', 'flag' => '🇮🇪', 'name' => 'Irlanda'],
['code' => 'other', 'flag' => '🇳🇿', 'name' => 'Nueva Zelanda'],
['code' => 'other', 'flag' => '🇿🇦', 'name' => 'Sudáfrica'],
['code' => 'other', 'flag' => '🇪🇬', 'name' => 'Egipto'],
['code' => 'other', 'flag' => '🇮🇷', 'name' => 'Irán'],
['code' => 'other', 'flag' => '🇵🇰', 'name' => 'Pakistán'],
['code' => 'other', 'flag' => '🇧🇩', 'name' => 'Bangladesh'],
['code' => 'other', 'flag' => '🇵🇭', 'name' => 'Filipinas'],
['code' => 'other', 'flag' => '🇸🇬', 'name' => 'Singapur'],
['code' => 'other', 'flag' => '🇭🇰', 'name' => 'Hong Kong'],
['code' => 'other', 'flag' => '🇲🇴', 'name' => 'Macao'],
];
function getFlagForLanguage(string $code): string {
// Por defecto usar México para español
$flags = [
'en' => '🇺🇸', // USA para inglés general
'es' => '🇲🇽', // México para español (como pidió el usuario)
'pt' => '🇧🇷', // Brasil para portugués
'fr' => '🇫🇷', // Francia
'de' => '🇩🇪', // Alemania
'it' => '🇮🇹', // Italia
'ru' => '🇷🇺', // Rusia
'zh' => '🇨🇳', // China
'ja' => '🇯🇵', // Japón
'ko' => '🇰🇷', // Corea del Sur
'ar' => '🇸🇦', // Arabia Saudita
'hi' => '🇮🇳', // India
'nl' => '🇳🇱', // Países Bajos
'pl' => '🇵🇱', // Polonia
'tr' => '🇹🇷', // Turquía
'sv' => '🇸🇪', // Suecia
'da' => '🇩🇰', // Dinamarca
'fi' => '🇫🇮', // Finlandia
'no' => '🇳🇴', // Noruega
'cs' => '🇨🇿', // República Checa
'el' => '🇬🇷', // Grecia
'he' => '🇮🇱', // Israel
'th' => '🇹🇭', // Tailandia
'vi' => '🇻🇳', // Vietnam
'id' => '🇮🇩', // Indonesia
'ms' => '🇲🇾', // Malasia
'uk' => '🇺🇦', // Ucrania
'ca' => '🇪🇸', // España (Cataluña)
'gl' => '🇪🇸', // España (Galicia)
'ro' => '🇷🇴', // Rumania
'hu' => '🇭🇺', // Hungría
'bg' => '🇧🇬', // Bulgaria
];
return $flags[$code] ?? '🌐';
}
require_once __DIR__ . '/../templates/header.php';
?>
<div class="d-flex justify-content-between align-items-center mb-4">
<h2><i class="bi bi-translate"></i> Gestión de Idiomas</h2>
<div>
<form method="POST" class="d-inline">
<input type="hidden" name="action" value="sync_libretranslate">
<button type="submit" class="btn btn-outline-primary">
<i class="bi bi-cloud-download"></i> Sincronizar con LibreTranslate
</button>
</form>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#languageModal">
<i class="bi bi-plus-circle"></i> Nuevo Idioma
</button>
</div>
</div>
<?php if ($syncMessage): ?>
<div class="alert alert-success"><?= htmlspecialchars($syncMessage) ?></div>
<?php endif; ?>
<?php if ($syncError): ?>
<div class="alert alert-danger"><?= htmlspecialchars($syncError) ?></div>
<?php endif; ?>
<?php if (isset($error)): ?>
<div class="alert alert-danger"><?= htmlspecialchars($error) ?></div>
<?php endif; ?>
<div class="row">
<div class="col-md-12">
<div class="card border-0 shadow-sm">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Bandera</th>
<th>Código</th>
<th>Nombre</th>
<th>Estado</th>
<th>Acciones</th>
</tr>
</thead>
<tbody>
<?php foreach ($languages as $lang): ?>
<tr>
<td style="font-size: 1.5rem;"><?= htmlspecialchars($lang['flag_emoji']) ?></td>
<td><code><?= htmlspecialchars($lang['language_code']) ?></code></td>
<td><?= htmlspecialchars($lang['language_name']) ?></td>
<td>
<?php if ($lang['is_active']): ?>
<span class="badge bg-success">Activo</span>
<?php else: ?>
<span class="badge bg-secondary">Inactivo</span>
<?php endif; ?>
</td>
<td>
<form method="POST" class="d-inline">
<input type="hidden" name="action" value="toggle_status">
<input type="hidden" name="id" value="<?= $lang['id'] ?>">
<button type="submit" class="btn btn-sm btn-outline-<?= $lang['is_active'] ? 'warning' : 'success' ?>">
<i class="bi bi-<?= $lang['is_active'] ? 'pause' : 'play' ?>-fill"></i>
</button>
</form>
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#flagModal<?= $lang['id'] ?>">
<i class="bi bi-flag"></i> Cambiar
</button>
</td>
</tr>
<!-- Modal Selector de Banderas -->
<div class="modal fade" id="flagModal<?= $lang['id'] ?>" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form method="POST">
<input type="hidden" name="action" value="update_flag">
<input type="hidden" name="id" value="<?= $lang['id'] ?>">
<div class="modal-header">
<h5 class="modal-title">Seleccionar Bandera - <?= htmlspecialchars($lang['language_name']) ?></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Bandera actual</label>
<div class="display-4"><?= htmlspecialchars($lang['flag_emoji']) ?></div>
</div>
<div class="mb-3">
<label class="form-label">Seleccionar nueva bandera</label>
<div class="flag-selector" style="max-height: 400px; overflow-y: auto;">
<div class="row g-2">
<?php foreach ($availableFlags as $flag): ?>
<div class="col-6 col-md-4 col-lg-3">
<label class="d-block p-2 border rounded cursor-pointer text-center" style="cursor: pointer; <?= $flag['flag'] === $lang['flag_emoji'] ? 'background-color: #e3f2fd; border-color: #2196f3;' : '' ?>" onclick="selectFlag<?= $lang['id'] ?>('<?= $flag['flag'] ?>')">
<input type="radio" name="flag_emoji" value="<?= $flag['flag'] ?>" class="d-none" <?= $flag['flag'] === $lang['flag_emoji'] ? 'checked' : '' ?>>
<span style="font-size: 2rem;"><?= $flag['flag'] ?></span>
<div class="small text-muted mt-1"><?= htmlspecialchars($flag['name']) ?></div>
</label>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="mt-3">
<label class="form-label">O escribir emoji manualmente</label>
<input type="text" name="flag_emoji_custom" id="customFlag<?= $lang['id'] ?>" class="form-control" value="<?= htmlspecialchars($lang['flag_emoji']) ?>" maxlength="10" placeholder="🇲🇽">
<small class="text-muted">Puedes copiar y pegar cualquier emoji de bandera aquí</small>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
<button type="submit" class="btn btn-primary">Guardar</button>
</div>
</form>
</div>
</div>
</div>
<script>
function selectFlag<?= $lang['id'] ?>(flag) {
document.getElementById('customFlag<?= $lang['id'] ?>').value = flag;
}
</script>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<!-- Modal Nuevo Idioma -->
<div class="modal fade" id="languageModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<form method="POST">
<input type="hidden" name="action" value="add">
<div class="modal-header">
<h5 class="modal-title">Nuevo Idioma</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label class="form-label">Código de idioma (ej: ca, gl)</label>
<input type="text" name="language_code" class="form-control" required maxlength="10">
</div>
<div class="mb-3">
<label class="form-label">Nombre del idioma</label>
<input type="text" name="language_name" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Seleccionar bandera</label>
<div class="flag-selector-new" style="max-height: 300px; overflow-y: auto;">
<div class="row g-2">
<?php foreach ($availableFlags as $flag): ?>
<div class="col-4">
<label class="d-block p-2 border rounded cursor-pointer text-center" style="cursor: pointer;" onclick="selectNewFlag('<?= $flag['flag'] ?>')">
<input type="radio" name="flag_emoji" value="<?= $flag['flag'] ?>" class="d-none">
<span style="font-size: 1.5rem;"><?= $flag['flag'] ?></span>
<div class="small text-muted" style="font-size: 0.75rem;"><?= htmlspecialchars($flag['name']) ?></div>
</label>
</div>
<?php endforeach; ?>
</div>
</div>
</div>
<div class="mt-3">
<label class="form-label">O escribir emoji manualmente</label>
<input type="text" id="newFlagInput" name="flag_emoji" class="form-control" maxlength="10" placeholder="🇲🇽">
</div>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary">Agregar</button>
</div>
</form>
</div>
</div>
</div>
<script>
function selectNewFlag(flag) {
document.getElementById('newFlagInput').value = flag;
// Marcar visualmente la selección
document.querySelectorAll('.flag-selector-new label').forEach(function(label) {
label.style.backgroundColor = '';
label.style.borderColor = '';
});
event.currentTarget.style.backgroundColor = '#e3f2fd';
event.currentTarget.style.borderColor = '#2196f3';
}
// Estilo hover para las banderas
document.querySelectorAll('.flag-selector label, .flag-selector-new label').forEach(function(label) {
label.addEventListener('mouseenter', function() {
if (!this.querySelector('input:checked')) {
this.style.backgroundColor = '#f5f5f5';
}
});
label.addEventListener('mouseleave', function() {
if (!this.querySelector('input:checked')) {
this.style.backgroundColor = '';
}
});
});
</script>
<?php require_once __DIR__ . '/../templates/footer.php'; ?>