Traduccion parte de la piscina
This commit is contained in:
parent
dc8bc854f9
commit
56cba7f7ab
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
@ -128,7 +128,6 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|||
|
||||
if (user?.name) {
|
||||
document.getElementById("nombreUsuarioHeader").textContent = user.name;
|
||||
document.getElementById("nombreUsuarioDropdown").textContent = "Coach " + user.name;
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("❌ Error al obtener datos del usuario:", err);
|
||||
|
|
|
@ -1,4 +1,52 @@
|
|||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const userId = sessionStorage.getItem("userId");
|
||||
if (!userId) {
|
||||
alert("Sesión expirada, inicia sesión de nuevo.");
|
||||
window.location.href = "index.html";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/users/${userId}`);
|
||||
const user = await res.json();
|
||||
|
||||
if (user?.name) {
|
||||
document.getElementById("nombreUsuarioHeader").textContent = user.name;
|
||||
}
|
||||
|
||||
let lang = 'es'; // valor por defecto
|
||||
|
||||
// 1. Determinar idioma
|
||||
if (sessionStorage.getItem('langJustChanged') === 'true') {
|
||||
lang = sessionStorage.getItem('lang') || user.language || 'es';
|
||||
} else if (sessionStorage.getItem('lang')) {
|
||||
lang = sessionStorage.getItem('lang');
|
||||
} else if (user.language) {
|
||||
lang = user.language;
|
||||
sessionStorage.setItem('lang', lang);
|
||||
}
|
||||
|
||||
window.tLang = lang;
|
||||
localStorage.setItem('lang', lang); // opcional si usas localStorage
|
||||
|
||||
// 🌀 Recarga solo una vez con delay para evitar parpadeo inmediato
|
||||
if (!sessionStorage.getItem('langLoadedOnce')) {
|
||||
sessionStorage.setItem('langLoadedOnce', 'true');
|
||||
setTimeout(() => location.reload(), 100); //
|
||||
return;
|
||||
}
|
||||
|
||||
// ✅ Aplicar traducciones después de confirmar idioma
|
||||
const selector = document.getElementById("langSelector");
|
||||
if (selector) selector.value = lang;
|
||||
|
||||
aplicarTraducciones();
|
||||
actualizarTextosDinamicos();
|
||||
|
||||
} catch (err) {
|
||||
console.error("❌ Error al obtener datos del usuario:", err);
|
||||
}
|
||||
|
||||
const rutinaId = new URLSearchParams(window.location.search).get('routineId');
|
||||
if (!rutinaId) return alert('No se proporcionó ID de rutina.');
|
||||
|
||||
|
@ -38,21 +86,24 @@ atletas.forEach(a => {
|
|||
});
|
||||
|
||||
|
||||
let figuraActual = null; // 🔁 Guardar la figura seleccionada
|
||||
|
||||
select.addEventListener('change', () => {
|
||||
const datos = JSON.parse(select.value || '{}');
|
||||
select.dataset.id = datos.id; // << GUARDAS el ObjectId real
|
||||
select.dataset.id = datos.id;
|
||||
|
||||
const idInput = document.getElementById('idPersonalizado');
|
||||
if (datos.idPers) {
|
||||
document.getElementById('idPersonalizado').value = datos.idPers;
|
||||
document.getElementById('idPersonalizado').disabled = true;
|
||||
idInput.value = datos.idPers;
|
||||
idInput.disabled = true;
|
||||
} else {
|
||||
document.getElementById('idPersonalizado').value = '';
|
||||
document.getElementById('idPersonalizado').disabled = false;
|
||||
idInput.value = '';
|
||||
idInput.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
let figurasFINA = [];
|
||||
try {
|
||||
let figurasFINA = [];
|
||||
try {
|
||||
const res = await fetch('/catalog/figurasFINA.json');
|
||||
figurasFINA = await res.json();
|
||||
|
||||
|
@ -67,18 +118,20 @@ select.addEventListener('change', () => {
|
|||
matches.forEach(figura => {
|
||||
const item = document.createElement('button');
|
||||
item.type = 'button';
|
||||
item.className = 'list-group-item list-group-item-action';
|
||||
item.textContent = figura.nombre;
|
||||
item.onclick = () => {
|
||||
inputFigura.value = figura.nombre;
|
||||
inputFigura.title = `${figura.descripcion} (${figura.categoria})`;
|
||||
sugerenciasBox.innerHTML = '';
|
||||
figuraActual = figura; // guardamos figura activa
|
||||
mostrarPreview(figura);
|
||||
|
||||
const codigoInput = document.getElementById("codigoElemento");
|
||||
if (codigoInput && figura.codigoElemento) {
|
||||
codigoInput.value = figura.codigoElemento;
|
||||
}
|
||||
};
|
||||
};
|
||||
sugerenciasBox.appendChild(item);
|
||||
});
|
||||
});
|
||||
|
@ -88,18 +141,39 @@ select.addEventListener('change', () => {
|
|||
});
|
||||
|
||||
function mostrarPreview(figura) {
|
||||
const nombreTrad = window.figurasTraducidas?.[figura.nombre]?.[window.tLang] || figura.nombre;
|
||||
const descripcionTrad = window.descripcionesTraducidas?.[figura.descripcion]?.[window.tLang] || figura.descripcion;
|
||||
|
||||
// Traducción visual adicional debajo del input
|
||||
const nombreTraducidoVisual = document.getElementById("nombreFiguraTraducido");
|
||||
if (nombreTraducidoVisual) {
|
||||
nombreTraducidoVisual.textContent = nombreTrad;
|
||||
}
|
||||
|
||||
document.getElementById('previewFigura').innerHTML = `
|
||||
<img src="catalog/figuras/${figura.imagen}" alt="${figura.nombre}" class="img-fluid rounded border" style="max-height:150px;" />
|
||||
<p class="mt-2">${figura.descripcion} <span class="badge bg-info">${figura.categoria}</span></p>
|
||||
<img src="catalog/figuras/${figura.imagen}" alt="${nombreTrad}" class="img-fluid rounded border" style="max-height:150px;" />
|
||||
<p class="mt-2"><strong>${nombreTrad}</strong><br>${descripcionTrad} <span class="badge bg-info">${figura.categoria}</span></p>
|
||||
`;
|
||||
|
||||
const codigoInput = document.getElementById("codigoElemento");
|
||||
if (codigoInput && figura.codigoElemento) {
|
||||
codigoInput.value = figura.codigoElemento;
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('❌ No se pudo cargar el catálogo FINA:', err);
|
||||
|
||||
// Esto es clave: vuelve a mostrar la figura al cambiar idioma
|
||||
document.getElementById('langSelector').addEventListener('change', () => {
|
||||
window.tLang = sessionStorage.getItem('lang') || user.language || 'es';
|
||||
|
||||
if (figuraActual) {
|
||||
mostrarPreview(figuraActual); // 🔁 refresca con idioma nuevo
|
||||
}
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.warn('❌ No se pudo cargar el catálogo FINA:', err);
|
||||
}
|
||||
|
||||
const tipoPiscinaSelect = document.getElementById('tipoPiscina');
|
||||
|
||||
const medidasPiscina = {
|
||||
|
@ -652,9 +726,9 @@ formaciones.forEach((f, i) => {
|
|||
inputFigura.title = '';
|
||||
|
||||
btnEditarFormacion.className = 'btn btn-warning btn-sm d-inline-flex align-items-center gap-2';
|
||||
btnEditarFormacion.innerHTML = '🟡 En edición activa';
|
||||
btnEditarFormacion.innerHTML = t('editor.edicionActiva');
|
||||
|
||||
btnGuardarFormacion.textContent = 'Actualizar Formación';
|
||||
btnGuardarFormacion.textContent = t('editor.actualizar');
|
||||
btnGuardarFormacion.classList.remove('btn-primary');
|
||||
btnGuardarFormacion.classList.add('btn-warning');
|
||||
} else {
|
||||
|
@ -764,3 +838,31 @@ wave.on('audioprocess', (currentTime) => {
|
|||
});
|
||||
|
||||
});
|
||||
|
||||
document.getElementById('langSelector').addEventListener('change', async (e) => {
|
||||
const selectedLang = e.target.value;
|
||||
sessionStorage.setItem('lang', selectedLang);
|
||||
window.tLang = selectedLang;
|
||||
|
||||
const userId = sessionStorage.getItem("userId");
|
||||
if (userId) {
|
||||
await fetch(`/api/users/${userId}`, {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ language: selectedLang })
|
||||
});
|
||||
}
|
||||
|
||||
// 🟡 Recargar solo 1 vez
|
||||
sessionStorage.setItem('langJustChanged', 'true');
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
function logout() {
|
||||
sessionStorage.clear();
|
||||
localStorage.removeItem('lang'); // ✅ Limpia persistencia de idioma
|
||||
alert("Sesión cerrada");
|
||||
window.location.href = "../index.html";
|
||||
}
|
||||
|
||||
window.logout = logout;
|
|
@ -0,0 +1,355 @@
|
|||
const traducciones = {
|
||||
es: {
|
||||
editor: {
|
||||
titulo: "Editor de Formación",
|
||||
tipo: "Tipo",
|
||||
modalidad: "Modalidad",
|
||||
agregar: "Agregar Atleta",
|
||||
seleccionarAtleta: "Seleccionar atleta",
|
||||
rol: "Rol",
|
||||
rolSeleccionar: "Seleccionar rol",
|
||||
volador: "Volador",
|
||||
pilar: "Pilar",
|
||||
otro: "Otro",
|
||||
idPers: "ID personalizado",
|
||||
idEj: "Ej: A, 1, V2",
|
||||
figura: "Figura técnica",
|
||||
figuraEj: "Ej: Barracuda, Flamingo...",
|
||||
tipoElemento: "Tipo de elemento",
|
||||
codigoElemento: "Código del elemento",
|
||||
codigoEj: "Ej: TRE 1A, H4...",
|
||||
hibrido: "Híbrido",
|
||||
transicion: "Transición",
|
||||
btnAgregar: "Añadir Atleta",
|
||||
editar: "Editar formación",
|
||||
eliminar: "Eliminar Formación",
|
||||
guardar: "Guardar Formación",
|
||||
linea: "Línea de Tiempo",
|
||||
piscina: "Piscina",
|
||||
tipoPiscina: "Tipo de piscina",
|
||||
olimpica: "Olímpica (50m x 25m)",
|
||||
semiolimpica: "Semiolímpica (25m x 12.5m)",
|
||||
fosa: "Fosa/Poza (20m x 20m)",
|
||||
duracion: "Duración (segundos)",
|
||||
duracionEj: "Ej: 5",
|
||||
nombre: "Nombre",
|
||||
nombreEj: "Nombre de la formación",
|
||||
notas: "Notas tácticas",
|
||||
notasEj: "Instrucciones, marcajes, etc.",
|
||||
datos: "Datos de Formación",
|
||||
play: "▶ Reproducir",
|
||||
pause: "⏸︎ Pausar",
|
||||
actualizar: "Actualizar Formación",
|
||||
sinFigura: "Sin figura",
|
||||
direccion: "Añadir Dirección",
|
||||
eliminarDir: "Eliminar Dirección",
|
||||
edicionActiva: "🟡 En edición activa",
|
||||
alertaFaltanDatos: "Faltan datos del atleta",
|
||||
alertaMaxAtletas: "Modalidad \"{MOD}\" permite un máximo de {MAX} atletas.",
|
||||
alertaClickPiscina: "Haz clic en la piscina para colocarlo",
|
||||
alertaNombreFaltante: "Agrega nombre de formación y al menos un atleta",
|
||||
alertaSeleccionaFormacion: "Selecciona una formación desde la línea de tiempo primero.",
|
||||
confirmEliminar: {
|
||||
titulo: "¿Eliminar formación?",
|
||||
texto: "Esta acción no se puede deshacer",
|
||||
confirmar: "Sí, eliminar",
|
||||
cancelar: "Cancelar",
|
||||
eliminado: "La formación ha sido eliminada.",
|
||||
error: "No se pudo eliminar la formación."
|
||||
}
|
||||
},
|
||||
nav: {
|
||||
init: "Inicializar Rutina",
|
||||
equip: "Equipos Disponibles"
|
||||
},
|
||||
logout: "Salir"
|
||||
},
|
||||
en: {
|
||||
editor: {
|
||||
titulo: "Formation Editor",
|
||||
tipo: "Type",
|
||||
modalidad: "Modality",
|
||||
agregar: "Add Athlete",
|
||||
seleccionarAtleta: "Select athlete",
|
||||
rol: "Role",
|
||||
rolSeleccionar: "Select role",
|
||||
volador: "Flyer",
|
||||
pilar: "Base",
|
||||
otro: "Other",
|
||||
idPers: "Custom ID",
|
||||
idEj: "E.g.: A, 1, V2",
|
||||
figura: "Technical figure",
|
||||
figuraEj: "E.g.: Barracuda, Flamingo...",
|
||||
tipoElemento: "Element type",
|
||||
codigoElemento: "Element code",
|
||||
codigoEj: "E.g.: TRE 1A, H4...",
|
||||
hibrido: "Hybrid",
|
||||
transicion: "Transition",
|
||||
btnAgregar: "Add Athlete",
|
||||
editar: "Edit formation",
|
||||
eliminar: "Delete Formation",
|
||||
guardar: "Save Formation",
|
||||
linea: "Timeline",
|
||||
piscina: "Pool",
|
||||
tipoPiscina: "Pool type",
|
||||
olimpica: "Olympic (50m x 25m)",
|
||||
semiolimpica: "Semi-Olympic (25m x 12.5m)",
|
||||
fosa: "Pit (20m x 20m)",
|
||||
duracion: "Duration (seconds)",
|
||||
duracionEj: "E.g.: 5",
|
||||
nombre: "Name",
|
||||
nombreEj: "Formation name",
|
||||
notas: "Tactical notes",
|
||||
notasEj: "Instructions, markings, etc.",
|
||||
datos: "Formation Data",
|
||||
play: "▶ Play",
|
||||
pause: "⏸︎ Pause",
|
||||
actualizar: "Update Formation",
|
||||
sinFigura: "No figure",
|
||||
direccion: "Add Direction",
|
||||
eliminarDir: "Remove Direction",
|
||||
edicionActiva: "🟡 Editing active",
|
||||
alertaFaltanDatos: "Missing athlete data",
|
||||
alertaMaxAtletas: "Modality \"{MOD}\" allows a maximum of {MAX} athletes.",
|
||||
alertaClickPiscina: "Click on the pool to place the athlete",
|
||||
alertaNombreFaltante: "Add formation name and at least one athlete",
|
||||
alertaSeleccionaFormacion: "Select a formation from the timeline first.",
|
||||
confirmEliminar: {
|
||||
titulo: "Delete formation?",
|
||||
texto: "This action cannot be undone",
|
||||
confirmar: "Yes, delete",
|
||||
cancelar: "Cancel",
|
||||
eliminado: "Formation has been deleted.",
|
||||
error: "Failed to delete formation."
|
||||
}
|
||||
},
|
||||
nav: {
|
||||
init: "Initialize Routine",
|
||||
equip: "Available Teams"
|
||||
},
|
||||
logout: "Logout"
|
||||
},
|
||||
fr: {
|
||||
editor: {
|
||||
titulo: "Éditeur de Formation",
|
||||
tipo: "Type",
|
||||
modalidad: "Modalité",
|
||||
agregar: "Ajouter un Athlète",
|
||||
seleccionarAtleta: "Sélectionner un athlète",
|
||||
rol: "Rôle",
|
||||
rolSeleccionar: "Sélectionner un rôle",
|
||||
volador: "Voltigeur",
|
||||
pilar: "Pilier",
|
||||
otro: "Autre",
|
||||
idPers: "ID personnalisé",
|
||||
idEj: "Ex. : A, 1, V2",
|
||||
figura: "Figure technique",
|
||||
figuraEj: "Ex. : Barracuda, Flamant...",
|
||||
tipoElemento: "Type d'élément",
|
||||
codigoElemento: "Code de l'élément",
|
||||
codigoEj: "Ex. : TRE 1A, H4...",
|
||||
hibrido: "Hybride",
|
||||
transicion: "Transition",
|
||||
btnAgregar: "Ajouter un Athlète",
|
||||
editar: "Modifier la formation",
|
||||
eliminar: "Supprimer la Formation",
|
||||
guardar: "Enregistrer la Formation",
|
||||
linea: "Chronologie",
|
||||
piscina: "Piscine",
|
||||
tipoPiscina: "Type de piscine",
|
||||
olimpica: "Olympique (50m x 25m)",
|
||||
semiolimpica: "Semi-olympique (25m x 12,5m)",
|
||||
fosa: "Fosse (20m x 20m)",
|
||||
duracion: "Durée (secondes)",
|
||||
duracionEj: "Ex. : 5",
|
||||
nombre: "Nom",
|
||||
nombreEj: "Nom de la formation",
|
||||
notas: "Notes tactiques",
|
||||
notasEj: "Instructions, repères, etc.",
|
||||
datos: "Données de la Formation",
|
||||
play: "▶ Lire",
|
||||
pause: "⏸︎ Pause",
|
||||
actualizar: "Mettre à jour la Formation",
|
||||
sinFigura: "Pas de figure",
|
||||
direccion: "Ajouter une Direction",
|
||||
eliminarDir: "Supprimer la Direction",
|
||||
edicionActiva: "🟡 Édition active",
|
||||
alertaFaltanDatos: "Données de l'athlète manquantes",
|
||||
alertaMaxAtletas: "La modalité \"{MOD}\" permet un maximum de {MAX} athlètes.",
|
||||
alertaClickPiscina: "Cliquez sur la piscine pour placer l'athlète",
|
||||
alertaNombreFaltante: "Ajoutez un nom de formation et au moins un athlète",
|
||||
alertaSeleccionaFormacion: "Sélectionnez d'abord une formation depuis la chronologie.",
|
||||
confirmEliminar: {
|
||||
titulo: "Supprimer la formation ?",
|
||||
texto: "Cette action est irréversible",
|
||||
confirmer: "Oui, supprimer",
|
||||
cancelar: "Annuler",
|
||||
eliminado: "La formation a été supprimée.",
|
||||
error: "Échec de la suppression de la formation."
|
||||
}
|
||||
},
|
||||
nav: {
|
||||
init: "Démarrer la routine",
|
||||
equip: "Équipes disponibles"
|
||||
},
|
||||
logout: "Se déconnecter"
|
||||
}
|
||||
};
|
||||
|
||||
window.figurasTraducidas = {
|
||||
"Pez Volador con Giro": {
|
||||
en: "Flying Fish with Twist",
|
||||
fr: "Poisson Volant avec Torsion"
|
||||
},
|
||||
"Pez Volador": {
|
||||
en: "Flying Fish",
|
||||
fr: "Poisson Volant"
|
||||
},
|
||||
"Rodilla Flexionada con Giro Completo": {
|
||||
en: "Bent Knee with Full Twist",
|
||||
fr: "Genou Fléchi avec Rotation Complète"
|
||||
},
|
||||
"Rodilla Flexionada con Medio Giro": {
|
||||
en: "Bent Knee with Half Twist",
|
||||
fr: "Genou Fléchi avec Demi-Tour"
|
||||
},
|
||||
"Fouetté con Giro 720°": {
|
||||
en: "Fouetté with 720° Turn",
|
||||
fr: "Fouetté avec Rotation de 720°"
|
||||
},
|
||||
"Fouetté con Giro 360°": {
|
||||
en: "Fouetté with 360° Turn",
|
||||
fr: "Fouetté avec Rotation de 360°"
|
||||
},
|
||||
"Mariposa": {
|
||||
en: "Butterfly",
|
||||
fr: "Papillon"
|
||||
},
|
||||
"Split con Giro 180°": {
|
||||
en: "Split with 180° Turn",
|
||||
fr: "Grand Écart avec Rotation de 180°"
|
||||
},
|
||||
"Split a Rodilla Flexionada": {
|
||||
en: "Split to Bent Knee",
|
||||
fr: "Grand Écart vers Genou Fléchi"
|
||||
}
|
||||
};
|
||||
|
||||
window.descripcionesTraducidas = {
|
||||
"Impulso a vertical desde pike, transición a cola de pez aérea, regreso a vertical y giro de 180°.": {
|
||||
en: "Thrust to vertical from pike, transition to aerial fish tail, return to vertical and 180° twist.",
|
||||
fr: "Poussée en vertical depuis pike, transition vers queue de poisson aérienne, retour en vertical et torsion de 180°."
|
||||
},
|
||||
"Impulso a vertical desde pike, transición a cola de pez aérea, regreso a vertical y descenso.": {
|
||||
en: "Thrust to vertical from pike, transition to aerial fish tail, return to vertical and descent.",
|
||||
fr: "Poussée en vertical depuis pike, transition vers queue de poisson aérienne, retour en vertical et descente."
|
||||
},
|
||||
"Vertical con giro completo a rodilla flexionada, otro giro a vertical, apertura 180° a split y walkout.": {
|
||||
en: "Vertical with full twist to bent knee, another twist to vertical, 180° split and walkout.",
|
||||
fr: "Vertical avec rotation complète vers genou fléchi, nouvelle rotation vers vertical, ouverture à 180° en écart et sortie."
|
||||
},
|
||||
"Vertical con medio giro a rodilla flexionada, otro medio giro a vertical, split y walkout.": {
|
||||
en: "Vertical with half twist to bent knee, another half twist to vertical, split and walkout.",
|
||||
fr: "Vertical avec demi-tour vers genou fléchi, autre demi-tour vers vertical, écart et sortie."
|
||||
},
|
||||
"Desde cola de pez, dos giros Fouetté, paso a vertical y giro continuo de 720°.": {
|
||||
en: "From fish tail, two Fouetté turns, transition to vertical and continuous 720° turn.",
|
||||
fr: "Depuis queue de poisson, deux rotations Fouetté, passage en vertical et rotation continue de 720°."
|
||||
},
|
||||
"Desde cola de pez, dos giros Fouetté, paso a vertical y giro rápido de 360°.": {
|
||||
en: "From fish tail, two Fouetté turns, transition to vertical and quick 360° turn.",
|
||||
fr: "Depuis queue de poisson, deux rotations Fouetté, passage en vertical et rotation rapide de 360°."
|
||||
},
|
||||
"Secuencia dinámica con pike, cola de pez, split, giros, arco superficial y salida en layout.": {
|
||||
en: "Dynamic sequence with pike, fish tail, split, turns, surface arch and layout exit.",
|
||||
fr: "Séquence dynamique avec pike, queue de poisson, écart, rotations, arc en surface et sortie en layout."
|
||||
},
|
||||
"Impulso a vertical, split aéreo, giro 180° a rodilla flexionada y descenso vertical.": {
|
||||
en: "Thrust to vertical, aerial split, 180° turn to bent knee and vertical descent.",
|
||||
fr: "Poussée en vertical, grand écart aérien, rotation de 180° vers genou fléchi et descente verticale."
|
||||
},
|
||||
"Impulso a vertical, split aéreo, transición a rodilla flexionada y descenso vertical.": {
|
||||
en: "Thrust to vertical, aerial split, transition to bent knee and vertical descent.",
|
||||
fr: "Poussée en vertical, grand écart aérien, transition vers genou fléchi et descente verticale."
|
||||
}
|
||||
};
|
||||
|
||||
let lang = window.tLang || localStorage.getItem('lang') || 'es';
|
||||
window.tLang = lang;
|
||||
|
||||
const t = (key, replacements = {}) => {
|
||||
const keys = key.split('.');
|
||||
let value = keys.reduce((obj, k) => obj?.[k], traducciones[lang]) ?? key;
|
||||
|
||||
for (const [k, v] of Object.entries(replacements)) {
|
||||
value = value.replace(`{${k}}`, v);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
function aplicarTraducciones() {
|
||||
// Traduce elementos con data-i18n
|
||||
document.querySelectorAll('[data-i18n]').forEach(el => {
|
||||
const key = el.dataset.i18n;
|
||||
el.textContent = t(key);
|
||||
});
|
||||
|
||||
// Traduce placeholders
|
||||
document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
|
||||
const key = el.dataset.i18nPlaceholder;
|
||||
el.placeholder = t(key);
|
||||
});
|
||||
|
||||
// Traducción de <option> del select tipoElemento
|
||||
const tipoElementoSelect = document.getElementById('tipoElemento');
|
||||
if (tipoElementoSelect) {
|
||||
tipoElementoSelect.querySelectorAll('option').forEach(option => {
|
||||
const val = option.value.toLowerCase();
|
||||
const text = option.textContent.toLowerCase();
|
||||
|
||||
if (val === 'tre') {
|
||||
option.textContent = 'TRE'; // no traducir
|
||||
} else if (val === 'híbrido' || text.includes('hybrid') || val === 'hybride') {
|
||||
option.textContent = t('editor.hibrido') || 'Híbrido';
|
||||
} else if (val === 'transición' || text.includes('transition') || val === 'transition') {
|
||||
option.textContent = t('editor.transicion') || 'Transición';
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
aplicarTraducciones();
|
||||
actualizarTextosDinamicos();
|
||||
});
|
||||
|
||||
document.getElementById('langSelector').addEventListener('change', (e) => {
|
||||
const selectedLang = e.target.value;
|
||||
lang = selectedLang;
|
||||
window.tLang = selectedLang; // ✅ sincroniza con global
|
||||
localStorage.setItem('lang', selectedLang); // opcional, si quieres persistencia local
|
||||
aplicarTraducciones();
|
||||
actualizarTextosDinamicos();
|
||||
});
|
||||
|
||||
function actualizarTextosDinamicos() {
|
||||
document.getElementById("btnGuardarFormacion").textContent = `💾 ${t('editor.guardar')}`;
|
||||
document.getElementById("btnEditarFormacion").innerHTML = `✏ ${t('editor.editar')}`;
|
||||
document.getElementById("btnEliminarFormacion").innerHTML = `✏ ${t('editor.eliminar')}`;
|
||||
|
||||
if (btnEditarFormacion.classList.contains('btn-warning')) {
|
||||
btnEditarFormacion.innerHTML = t('editor.edicionActiva'); // refresca si está en modo edición
|
||||
}
|
||||
}
|
||||
|
||||
// Expone variables globales para otros scripts
|
||||
window.traducciones = traducciones;
|
||||
window.figurasTraducidas = figurasTraducidas;
|
||||
window.descripcionesTraducidas = descripcionesTraducidas;
|
||||
window.tLang = lang;
|
||||
|
||||
window.aplicarTraducciones = aplicarTraducciones;
|
||||
window.actualizarTextosDinamicos = actualizarTextosDinamicos;
|
||||
|
||||
|
|
@ -66,47 +66,48 @@
|
|||
|
||||
<main class="container-xl px-4 my-4">
|
||||
<section class="mb-4">
|
||||
<h2 id="tituloRutina" class="fw-bold fs-2 mb-2">Editor de Formación</h2>
|
||||
<h2 id="tituloRutina" class="fw-bold fs-2 mb-2" data-i18n="editor.titulo">Editor de Formación</h2>
|
||||
<div class="d-flex flex-wrap gap-3 small text-muted">
|
||||
<div><strong>Tipo:</strong> <span id="tipoRutina">Cargando...</span></div>
|
||||
<div><strong>Modalidad:</strong> <span id="modalidadRutina">Cargando...</span></div>
|
||||
<div><strong data-i18n="editor.tipo">Tipo:</strong> <span id="tipoRutina">Cargando...</span></div>
|
||||
<div><strong data-i18n="editor.modalidad">Modalidad:</strong> <span id="modalidadRutina">Cargando...</span></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="row gx-4 gy-4">
|
||||
<div class="col-lg-4">
|
||||
<div class="card p-4 h-100 d-flex flex-column">
|
||||
<h5 class="fw-semibold mb-3 text-primary">Agregar Atleta</h5>
|
||||
<h5 class="fw-semibold mb-3 text-primary" data-i18n="editor.agregar">Agregar Atleta</h5>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="selectAtleta" class="form-label">Seleccionar atleta</label>
|
||||
<label for="selectAtleta" class="form-label" data-i18n="editor.seleccionarAtleta">Seleccionar atleta</label>
|
||||
<select id="selectAtleta" class="form-select"></select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="rolAtleta" class="form-label">Rol</label>
|
||||
<label for="rolAtleta" class="form-label" data-i18n="editor.rol">Rol</label>
|
||||
<select id="rolAtleta" class="form-select">
|
||||
<option value="">Seleccionar rol</option>
|
||||
<option value="volador">Volador</option>
|
||||
<option value="pilar">Pilar</option>
|
||||
<option value="otro">Otro</option>
|
||||
<option value="" data-i18n="editor.rolSeleccionar">Seleccionar rol</option>
|
||||
<option value="volador" data-i18n="editor.volador">Volador</option>
|
||||
<option value="pilar" data-i18n="editor.pilar">Pilar</option>
|
||||
<option value="otro" data-i18n="editor.otro">Otro</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="idPersonalizado" class="form-label">ID personalizado</label>
|
||||
<input type="text" id="idPersonalizado" class="form-control" placeholder="Ej: A, 1, V2" readonly>
|
||||
<label for="idPersonalizado" class="form-label" data-i18n="editor.idPers">ID personalizado</label>
|
||||
<input type="text" id="idPersonalizado" class="form-control" placeholder="Ej: A, 1, V2" data-i18n-placeholder="editor.idEj" readonly>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="figura" class="form-label">Figura técnica</label>
|
||||
<input type="text" id="figura" class="form-control" placeholder="Ej: Barracuda, Flamingo..." autocomplete="off">
|
||||
<label for="figura" class="form-label" data-i18n="editor.figura">Figura técnica</label>
|
||||
<input type="text" id="figura" class="form-control" placeholder="Ej: Barracuda, Flamingo..." data-i18n-placeholder="editor.figuraEj" autocomplete="off">
|
||||
<small id="nombreFiguraTraducido" class="form-text text-muted"></small>
|
||||
<div id="sugerenciasFigura" class="list-group position-relative"></div>
|
||||
<div id="previewFigura" class="text-center mt-3 mb-3"></div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="tipoElemento" class="form-label">Tipo de elemento</label>
|
||||
<label for="tipoElemento" class="form-label" data-i18n="editor.tipoElemento">Tipo de elemento</label>
|
||||
<select id="tipoElemento" class="form-select">
|
||||
<option value="TRE">TRE</option>
|
||||
<option value="híbrido">Híbrido</option>
|
||||
|
@ -115,23 +116,23 @@
|
|||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="codigoElemento" class="form-label">Código del elemento</label>
|
||||
<input type="text" id="codigoElemento" class="form-control" placeholder="Ej: TRE 1A, H4...">
|
||||
<label for="codigoElemento" class="form-label" data-i18n="editor.codigoElemento">Código del elemento</label>
|
||||
<input type="text" id="codigoElemento" class="form-control" placeholder="Ej: TRE 1A, H4..." data-i18n-placeholder="editor.codigoEj">
|
||||
</div>
|
||||
|
||||
<button id="btnAgregarAtleta" class="btn btn-primary mt-auto">Añadir Atleta</button>
|
||||
<button id="btnAgregarAtleta" class="btn btn-primary mt-auto" data-i18n="editor.btnAgregar">Añadir Atleta</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-8 d-flex flex-column gap-3">
|
||||
<div class="card p-4">
|
||||
<h5 class="fw-semibold mb-3 text-primary">Piscina</h5>
|
||||
<h5 class="fw-semibold mb-3 text-primary" data-i18n="editor.piscina">Piscina</h5>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="tipoPiscina" class="form-label">Tipo de piscina</label>
|
||||
<label for="tipoPiscina" class="form-label" data-i18n="editor.tipoPiscina">Tipo de piscina</label>
|
||||
<select id="tipoPiscina" class="form-select form-select-sm w-100" style="max-width: 280px;">
|
||||
<option value="olimpica">Olímpica (50m x 25m)</option>
|
||||
<option value="semiolimpica">Semiolímpica (25m x 12.5m)</option>
|
||||
<option value="fosa">Fosa/Poza (20m x 20m)</option>
|
||||
<option value="olimpica" data-i18n="editor.olimpica">Olímpica (50m x 25m)</option>
|
||||
<option value="semiolimpica" data-i18n="editor.semiolimpica">Semiolímpica (25m x 12.5m)</option>
|
||||
<option value="fosa" data-i18n="editor.fosa">Fosa/Poza (20m x 20m)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
@ -144,14 +145,14 @@
|
|||
<button id="btnEliminarFormacion" class="btn btn-outline-danger btn-sm">🗑 Eliminar Formación</button>
|
||||
</div>
|
||||
|
||||
<label class="form-label fw-semibold">Línea de Tiempo</label>
|
||||
<label class="form-label fw-semibold" data-i18n="editor.linea">Línea de Tiempo</label>
|
||||
<div id="lineaTiempo" class="timeline-placeholder d-flex flex-wrap gap-2 mb-3"></div>
|
||||
|
||||
<!-- Reproductor abajo -->
|
||||
<div class="mb-3">
|
||||
<div id="waveform" style="height: 80px;"></div>
|
||||
<div class="text-end mt-2">
|
||||
<button id="playPauseBtn" class="btn btn-outline-primary btn-sm">▶ Reproducir</button>
|
||||
<button id="playPauseBtn" class="btn btn-outline-primary btn-sm" data-i18n="editor.play">▶ Reproducir</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -159,26 +160,26 @@
|
|||
|
||||
|
||||
<div class="card p-4 mt-4">
|
||||
<h5 class="fw-semibold mb-3 text-primary">Datos de Formación</h5>
|
||||
<h5 class="fw-semibold mb-3 text-primary" data-i18n="editor.datos">Datos de Formación</h5>
|
||||
<div class="row gy-3">
|
||||
<div class="col-md-4">
|
||||
<label for="nombreFormacion" class="form-label">Nombre</label>
|
||||
<input type="text" id="nombreFormacion" class="form-control" placeholder="Nombre de la formación">
|
||||
<label for="nombreFormacion" class="form-label" data-i18n="editor.nombre">Nombre</label>
|
||||
<input type="text" id="nombreFormacion" class="form-control" placeholder="Nombre de la formación" data-i18n-placeholder="editor.nombreEj">
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="duracionFormacion" class="form-label">Duración (segundos)</label>
|
||||
<input type="number" id="duracionFormacion" class="form-control" min="1" placeholder="Ej: 5">
|
||||
<label for="duracionFormacion" class="form-label" data-i18n="editor.duracion">Duración (segundos)</label>
|
||||
<input type="number" id="duracionFormacion" class="form-control" min="1" placeholder="Ej: 5" data-i18n-placeholder="editor.duracionEj">
|
||||
</div>
|
||||
|
||||
<div class="col-md-4">
|
||||
<label for="notasFormacion" class="form-label">Notas tácticas</label>
|
||||
<textarea id="notasFormacion" class="form-control" rows="1" placeholder="Instrucciones, marcajes, etc."></textarea>
|
||||
<label for="notasFormacion" class="form-label" data-i18n="editor.notas">Notas tácticas</label>
|
||||
<textarea id="notasFormacion" class="form-control" rows="1" placeholder="Instrucciones, marcajes, etc." data-i18n-placeholder="editor.notasEj"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-end mt-4">
|
||||
<button id="btnGuardarFormacion" class="btn btn-primary">Guardar Formación</button>
|
||||
<button id="btnGuardarFormacion" class="btn btn-primary" data-i18n="editor.guardar">Guardar Formación</button>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
@ -186,6 +187,8 @@
|
|||
<audio id="audioPlayer" class="d-none" controls></audio>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
|
||||
<script src="js/piscina.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="js/traduccionPiscina.js"></script>
|
||||
<script type="module" src="js/piscina.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Loading…
Reference in New Issue