fix(costs): rework the cost panel UX wise and apply prettier on the shared package

This commit is contained in:
jubnl
2026-06-18 13:59:10 +02:00
parent ad6e1ddcc8
commit d5850041a7
584 changed files with 6915 additions and 10724 deletions
+49 -92
View File
@@ -2,23 +2,19 @@ import type { TranslationStrings } from '../types';
const admin: TranslationStrings = {
'admin.notifications.title': 'Notificaciones',
'admin.notifications.hint':
'Elija un canal de notificación. Solo uno puede estar activo a la vez.',
'admin.notifications.hint': 'Elija un canal de notificación. Solo uno puede estar activo a la vez.',
'admin.notifications.none': 'Desactivado',
'admin.notifications.email': 'Correo (SMTP)',
'admin.notifications.webhook': 'Webhook',
'admin.notifications.save': 'Guardar configuración de notificaciones',
'admin.notifications.saved': 'Configuración de notificaciones guardada',
'admin.notifications.testWebhook': 'Enviar webhook de prueba',
'admin.notifications.testWebhookSuccess':
'Webhook de prueba enviado correctamente',
'admin.notifications.testWebhookSuccess': 'Webhook de prueba enviado correctamente',
'admin.notifications.testWebhookFailed': 'Error al enviar webhook de prueba',
'admin.smtp.title': 'Correo y notificaciones',
'admin.smtp.hint':
'Configuración SMTP para el envío de notificaciones por correo.',
'admin.smtp.hint': 'Configuración SMTP para el envío de notificaciones por correo.',
'admin.smtp.testButton': 'Enviar correo de prueba',
'admin.webhook.hint':
'Enviar notificaciones a un webhook externo (Discord, Slack, etc.).',
'admin.webhook.hint': 'Enviar notificaciones a un webhook externo (Discord, Slack, etc.).',
'admin.smtp.testSuccess': 'Correo de prueba enviado correctamente',
'admin.smtp.testFailed': 'Error al enviar correo de prueba',
'admin.title': 'Administración',
@@ -42,8 +38,7 @@ const admin: TranslationStrings = {
'admin.editUser': 'Editar usuario',
'admin.newPassword': 'Nueva contraseña',
'admin.newPasswordHint': 'Déjalo vacío para mantener la contraseña actual',
'admin.deleteUser':
'¿Eliminar al usuario "{name}"? Todos sus viajes se borrarán permanentemente.',
'admin.deleteUser': '¿Eliminar al usuario "{name}"? Todos sus viajes se borrarán permanentemente.',
'admin.deleteUserTitle': 'Eliminar usuario',
'admin.newPasswordPlaceholder': 'Introduce una nueva contraseña…',
'admin.toast.loadError': 'No se pudieron cargar los datos de administración',
@@ -76,19 +71,16 @@ const admin: TranslationStrings = {
'admin.invite.deleteError': 'Error al eliminar el enlace',
'admin.tabs.settings': 'Ajustes',
'admin.allowRegistration': 'Permitir el registro',
'admin.allowRegistrationHint':
'Los nuevos usuarios pueden registrarse por sí mismos',
'admin.allowRegistrationHint': 'Los nuevos usuarios pueden registrarse por sí mismos',
'admin.authMethods': 'Authentication Methods',
'admin.passwordLogin': 'Password Login',
'admin.passwordLoginHint': 'Allow users to sign in with email and password',
'admin.passwordRegistration': 'Password Registration',
'admin.passwordRegistrationHint':
'Allow new users to register with email and password',
'admin.passwordRegistrationHint': 'Allow new users to register with email and password',
'admin.oidcLogin': 'SSO Login',
'admin.oidcLoginHint': 'Allow users to sign in with SSO',
'admin.oidcRegistration': 'SSO Auto-Provisioning',
'admin.oidcRegistrationHint':
'Automatically create accounts for new SSO users',
'admin.oidcRegistrationHint': 'Automatically create accounts for new SSO users',
'admin.envOverrideHint':
'Password login settings are controlled by the OIDC_ONLY environment variable and cannot be changed here.',
'admin.lockoutWarning': 'At least one login method must remain enabled',
@@ -96,17 +88,14 @@ const admin: TranslationStrings = {
'admin.requireMfaHint':
'Los usuarios sin 2FA deben completar la configuración en Ajustes antes de usar la aplicación.',
'admin.apiKeys': 'Claves API',
'admin.apiKeysHint':
'Opcional. Activa datos ampliados de lugares, como fotos y previsión del tiempo.',
'admin.apiKeysHint': 'Opcional. Activa datos ampliados de lugares, como fotos y previsión del tiempo.',
'admin.mapsKey': 'Clave API de Google Maps',
'admin.mapsKeyHint':
'Obligatoria para buscar lugares. Consíguela en console.cloud.google.com',
'admin.mapsKeyHint': 'Obligatoria para buscar lugares. Consíguela en console.cloud.google.com',
'admin.mapsKeyHintLong':
'Sin una clave API, la búsqueda de lugares usa OpenStreetMap. Con una clave de Google también se pueden cargar fotos, valoraciones y horarios de apertura. Consíguela en console.cloud.google.com.',
'admin.recommended': 'Recomendado',
'admin.weatherKey': 'Clave API de OpenWeatherMap',
'admin.weatherKeyHint':
'Para datos meteorológicos. Gratis en openweathermap.org',
'admin.weatherKeyHint': 'Para datos meteorológicos. Gratis en openweathermap.org',
'admin.validateKey': 'Probar',
'admin.keyValid': 'Conectado',
'admin.keyInvalid': 'No válida',
@@ -116,12 +105,10 @@ const admin: TranslationStrings = {
'Permite iniciar sesión mediante proveedores externos como Google, Apple, Authentik o Keycloak.',
'admin.oidcDisplayName': 'Nombre visible',
'admin.oidcIssuer': 'URL del emisor',
'admin.oidcIssuerHint':
'La URL Issuer de OpenID Connect del proveedor. Ej.: https://accounts.google.com',
'admin.oidcIssuerHint': 'La URL Issuer de OpenID Connect del proveedor. Ej.: https://accounts.google.com',
'admin.oidcSaved': 'Configuración OIDC guardada',
'admin.fileTypes': 'Tipos de archivo permitidos',
'admin.fileTypesHint':
'Configura qué tipos de archivo pueden subir los usuarios.',
'admin.fileTypesHint': 'Configura qué tipos de archivo pueden subir los usuarios.',
'admin.fileTypesFormat':
'Extensiones separadas por comas (p. ej. jpg,png,pdf,doc). Usa * para permitir todos los tipos.',
'admin.fileTypesSaved': 'Ajustes de tipos de archivo guardados',
@@ -135,18 +122,15 @@ const admin: TranslationStrings = {
'admin.placesDetails.subtitle':
'Obtiene información detallada del lugar (horarios, valoración, web) de la Google Places API. Desactiva para ahorrar cuota de API.',
'admin.bagTracking.title': 'Seguimiento de equipaje',
'admin.bagTracking.subtitle':
'Activar peso y asignación de equipaje para artículos de la lista',
'admin.bagTracking.subtitle': 'Activar peso y asignación de equipaje para artículos de la lista',
'admin.collab.chat.title': 'Chat',
'admin.collab.chat.subtitle':
'Mensajería en tiempo real para la colaboración',
'admin.collab.chat.subtitle': 'Mensajería en tiempo real para la colaboración',
'admin.collab.notes.title': 'Notas',
'admin.collab.notes.subtitle': 'Notas y documentos compartidos',
'admin.collab.polls.title': 'Encuestas',
'admin.collab.polls.subtitle': 'Encuestas y votaciones grupales',
'admin.collab.whatsnext.title': 'Qué sigue',
'admin.collab.whatsnext.subtitle':
'Sugerencias de actividades y próximos pasos',
'admin.collab.whatsnext.subtitle': 'Sugerencias de actividades y próximos pasos',
'admin.tabs.config': 'Personalización',
'admin.tabs.defaults': 'Valores predeterminados',
'admin.defaultSettings.title': 'Configuración predeterminada de usuarios',
@@ -157,11 +141,9 @@ const admin: TranslationStrings = {
'admin.defaultSettings.resetToBuiltIn': 'restaurar',
'admin.tabs.templates': 'Plantillas de equipaje',
'admin.packingTemplates.title': 'Plantillas de equipaje',
'admin.packingTemplates.subtitle':
'Crear listas de equipaje reutilizables para tus viajes',
'admin.packingTemplates.subtitle': 'Crear listas de equipaje reutilizables para tus viajes',
'admin.packingTemplates.create': 'Nueva plantilla',
'admin.packingTemplates.namePlaceholder':
'Nombre de la plantilla (ej. Vacaciones en la playa)',
'admin.packingTemplates.namePlaceholder': 'Nombre de la plantilla (ej. Vacaciones en la playa)',
'admin.packingTemplates.empty': 'No se han creado plantillas aún',
'admin.packingTemplates.items': 'artículos',
'admin.packingTemplates.categories': 'categorías',
@@ -177,10 +159,8 @@ const admin: TranslationStrings = {
'admin.packingTemplates.saveError': 'Error al guardar',
'admin.tabs.addons': 'Complementos',
'admin.addons.title': 'Complementos',
'admin.addons.subtitle':
'Activa o desactiva funciones para personalizar tu experiencia en TREK.',
'admin.addons.subtitleBefore':
'Activa o desactiva funciones para personalizar tu experiencia en ',
'admin.addons.subtitle': 'Activa o desactiva funciones para personalizar tu experiencia en TREK.',
'admin.addons.subtitleBefore': 'Activa o desactiva funciones para personalizar tu experiencia en ',
'admin.addons.subtitleAfter': '.',
'admin.addons.enabled': 'Activo',
'admin.addons.disabled': 'Desactivado',
@@ -188,10 +168,8 @@ const admin: TranslationStrings = {
'admin.addons.type.global': 'Global',
'admin.addons.type.integration': 'Integración',
'admin.addons.tripHint': 'Disponible como pestaña dentro de cada viaje',
'admin.addons.globalHint':
'Disponible como sección independiente en la navegación principal',
'admin.addons.integrationHint':
'Servicios backend e integraciones de API sin página dedicada',
'admin.addons.globalHint': 'Disponible como sección independiente en la navegación principal',
'admin.addons.integrationHint': 'Servicios backend e integraciones de API sin página dedicada',
'admin.addons.toast.updated': 'Complemento actualizado',
'admin.addons.toast.error': 'No se pudo actualizar el complemento',
'admin.addons.noAddons': 'No hay complementos disponibles',
@@ -202,16 +180,14 @@ const admin: TranslationStrings = {
'admin.weather.forecast': 'Pronóstico de 16 días',
'admin.weather.forecastDesc': 'Antes eran 5 días (OpenWeatherMap)',
'admin.weather.climate': 'Datos climáticos históricos',
'admin.weather.climateDesc':
'Promedios de los últimos 85 años para fechas posteriores al pronóstico de 16 días',
'admin.weather.climateDesc': 'Promedios de los últimos 85 años para fechas posteriores al pronóstico de 16 días',
'admin.weather.requests': '10.000 solicitudes / día',
'admin.weather.requestsDesc': 'Gratis, sin necesidad de clave API',
'admin.weather.locationHint':
'El tiempo se basa en el primer lugar con coordenadas de cada día. Si no hay ningún lugar asignado a un día, se usa como referencia cualquier lugar de la lista.',
'admin.tabs.mcpTokens': 'Acceso MCP',
'admin.mcpTokens.title': 'Acceso MCP',
'admin.mcpTokens.subtitle':
'Gestionar sesiones OAuth y tokens de API de todos los usuarios',
'admin.mcpTokens.subtitle': 'Gestionar sesiones OAuth y tokens de API de todos los usuarios',
'admin.mcpTokens.sectionTitle': 'Tokens de API',
'admin.mcpTokens.owner': 'Propietario',
'admin.mcpTokens.tokenName': 'Nombre del token',
@@ -262,8 +238,7 @@ const admin: TranslationStrings = {
'admin.github.error': 'No se pudieron cargar las versiones',
'admin.github.by': 'por',
'admin.update.available': 'Actualización disponible',
'admin.update.text':
'TREK {version} está disponible. Estás usando {current}.',
'admin.update.text': 'TREK {version} está disponible. Estás usando {current}.',
'admin.update.button': 'Ver en GitHub',
'admin.update.install': 'Instalar actualización',
'admin.update.confirmTitle': '¿Instalar actualización?',
@@ -271,44 +246,33 @@ const admin: TranslationStrings = {
'TREK se actualizará de {current} a {version}. Después, el servidor se reiniciará automáticamente.',
'admin.update.dataInfo':
'Todos tus datos (viajes, usuarios, claves API, subidas, Vacay, Atlas, presupuestos) se conservarán.',
'admin.update.warning':
'La app estará brevemente no disponible durante el reinicio.',
'admin.update.warning': 'La app estará brevemente no disponible durante el reinicio.',
'admin.update.confirm': 'Actualizar ahora',
'admin.update.installing': 'Actualizando…',
'admin.update.success':
'¡Actualización instalada! El servidor se está reiniciando…',
'admin.update.success': '¡Actualización instalada! El servidor se está reiniciando…',
'admin.update.failed': 'La actualización falló',
'admin.update.backupHint':
'Recomendamos crear una copia de seguridad antes de actualizar.',
'admin.update.backupHint': 'Recomendamos crear una copia de seguridad antes de actualizar.',
'admin.update.backupLink': 'Ir a Copia de seguridad',
'admin.update.howTo': 'Cómo actualizar',
'admin.update.dockerText':
'Tu instancia de TREK se ejecuta en Docker. Para actualizar a {version}, ejecuta los siguientes comandos en tu servidor:',
'admin.update.reloadHint': 'Recarga la página en unos segundos.',
'admin.addons.catalog.memories.name': 'Fotos (Immich)',
'admin.addons.catalog.memories.description':
'Comparte fotos de viaje a través de tu instancia de Immich',
'admin.addons.catalog.memories.description': 'Comparte fotos de viaje a través de tu instancia de Immich',
'admin.addons.catalog.mcp.name': 'MCP',
'admin.addons.catalog.mcp.description':
'Protocolo de contexto de modelo para integración con asistentes de IA',
'admin.addons.catalog.mcp.description': 'Protocolo de contexto de modelo para integración con asistentes de IA',
'admin.addons.catalog.packing.name': 'Listas',
'admin.addons.catalog.packing.description':
'Listas de equipaje y tareas pendientes para tus viajes',
'admin.addons.catalog.packing.description': 'Listas de equipaje y tareas pendientes para tus viajes',
'admin.addons.catalog.budget.name': 'Presupuesto',
'admin.addons.catalog.budget.description':
'Controla los gastos y planifica el presupuesto del viaje',
'admin.addons.catalog.budget.description': 'Controla los gastos y planifica el presupuesto del viaje',
'admin.addons.catalog.documents.name': 'Documentos',
'admin.addons.catalog.documents.description':
'Guarda y gestiona la documentación del viaje',
'admin.addons.catalog.documents.description': 'Guarda y gestiona la documentación del viaje',
'admin.addons.catalog.vacay.name': 'Vacaciones',
'admin.addons.catalog.vacay.description':
'Planificador personal de vacaciones con vista de calendario',
'admin.addons.catalog.vacay.description': 'Planificador personal de vacaciones con vista de calendario',
'admin.addons.catalog.atlas.name': 'Atlas',
'admin.addons.catalog.atlas.description':
'Mapa del mundo con los países visitados y estadísticas de viaje',
'admin.addons.catalog.atlas.description': 'Mapa del mundo con los países visitados y estadísticas de viaje',
'admin.addons.catalog.collab.name': 'Colaboración',
'admin.addons.catalog.collab.description':
'Notas, encuestas y chat en tiempo real para organizar el viaje',
'admin.addons.catalog.collab.description': 'Notas, encuestas y chat en tiempo real para organizar el viaje',
'admin.oidcOnlyMode': 'Desactivar autenticación por contraseña',
'admin.oidcOnlyModeHint':
'Si está activado, solo se permite el inicio de sesión con SSO. El inicio de sesión y registro con contraseña se bloquean.',
@@ -321,12 +285,9 @@ const admin: TranslationStrings = {
'admin.notifications.adminWebhookPanel.title': 'Webhook de admin',
'admin.notifications.adminWebhookPanel.hint':
'Este webhook se usa exclusivamente para notificaciones de admin (ej. alertas de versión). Es independiente de los webhooks de usuario y se activa automáticamente si hay una URL configurada.',
'admin.notifications.adminWebhookPanel.saved':
'URL del webhook de admin guardada',
'admin.notifications.adminWebhookPanel.testSuccess':
'Webhook de prueba enviado correctamente',
'admin.notifications.adminWebhookPanel.testFailed':
'Error al enviar el webhook de prueba',
'admin.notifications.adminWebhookPanel.saved': 'URL del webhook de admin guardada',
'admin.notifications.adminWebhookPanel.testSuccess': 'Webhook de prueba enviado correctamente',
'admin.notifications.adminWebhookPanel.testFailed': 'Error al enviar el webhook de prueba',
'admin.notifications.adminWebhookPanel.alwaysOnHint':
'El webhook de admin se activa automáticamente si hay una URL configurada',
'admin.notifications.ntfy': 'Ntfy',
@@ -345,15 +306,11 @@ const admin: TranslationStrings = {
'admin.notifications.adminNtfyPanel.topicLabel': 'Tema de admin',
'admin.notifications.adminNtfyPanel.topicPlaceholder': 'trek-admin-alerts',
'admin.notifications.adminNtfyPanel.tokenLabel': 'Token de acceso (opcional)',
'admin.notifications.adminNtfyPanel.tokenCleared':
'Token de acceso de admin eliminado',
'admin.notifications.adminNtfyPanel.saved':
'Configuración de Ntfy de admin guardada',
'admin.notifications.adminNtfyPanel.tokenCleared': 'Token de acceso de admin eliminado',
'admin.notifications.adminNtfyPanel.saved': 'Configuración de Ntfy de admin guardada',
'admin.notifications.adminNtfyPanel.test': 'Enviar Ntfy de prueba',
'admin.notifications.adminNtfyPanel.testSuccess':
'Ntfy de prueba enviado correctamente',
'admin.notifications.adminNtfyPanel.testFailed':
'Error al enviar el Ntfy de prueba',
'admin.notifications.adminNtfyPanel.testSuccess': 'Ntfy de prueba enviado correctamente',
'admin.notifications.adminNtfyPanel.testFailed': 'Error al enviar el Ntfy de prueba',
'admin.notifications.adminNtfyPanel.alwaysOnHint':
'El Ntfy de admin siempre se activa cuando hay un tema configurado',
'admin.notifications.adminNotificationsHint':
@@ -361,10 +318,8 @@ const admin: TranslationStrings = {
'admin.notifications.tripReminders.title': 'Recordatorios de viaje',
'admin.notifications.tripReminders.hint':
'Envía una notificación de recordatorio antes de que comience un viaje (requiere días de recordatorio configurados en el viaje).',
'admin.notifications.tripReminders.enabled':
'Recordatorios de viaje activados',
'admin.notifications.tripReminders.disabled':
'Recordatorios de viaje desactivados',
'admin.notifications.tripReminders.enabled': 'Recordatorios de viaje activados',
'admin.notifications.tripReminders.disabled': 'Recordatorios de viaje desactivados',
'admin.tabs.notifications': 'Notificaciones',
'admin.addons.catalog.journey.name': 'Travesía',
'admin.addons.catalog.journey.description':
@@ -389,11 +344,13 @@ const admin: TranslationStrings = {
'admin.passkey.resetConfirm': '¿Eliminar todas las passkeys de {name}?',
'admin.passkey.resetDone': 'Se eliminaron {count} passkey(s)',
'admin.defaultSettings.mapProvider': 'Motor de mapas',
'admin.defaultSettings.mapProviderHint': 'El mapa predeterminado para todos en esta instancia. Cada usuario puede cambiarlo en sus propios ajustes.',
'admin.defaultSettings.mapProviderHint':
'El mapa predeterminado para todos en esta instancia. Cada usuario puede cambiarlo en sus propios ajustes.',
'admin.defaultSettings.providerLeaflet': 'Estándar (gratis)',
'admin.defaultSettings.providerMapbox': 'Mapbox (3D)',
'admin.defaultSettings.mapboxToken': 'Token de Mapbox compartido',
'admin.defaultSettings.mapboxTokenHint': 'Se usa para cada usuario que no haya introducido su propio token, de modo que toda la instancia obtenga Mapbox sin compartir la clave individualmente. Se almacena cifrado.',
'admin.defaultSettings.mapboxTokenHint':
'Se usa para cada usuario que no haya introducido su propio token, de modo que toda la instancia obtenga Mapbox sin compartir la clave individualmente. Se almacena cifrado.',
'admin.defaultSettings.mapboxStyle': 'Estilo de mapa',
'admin.defaultSettings.mapboxStylePlaceholder': 'Elige un estilo…',
'admin.defaultSettings.mapbox3d': 'Edificios y terreno en 3D',
+2 -4
View File
@@ -9,8 +9,7 @@ const atlas: TranslationStrings = {
'atlas.visitedCountries': 'Países visitados',
'atlas.cities': 'Ciudades',
'atlas.noData': 'Aún no hay datos de viaje',
'atlas.noDataHint':
'Crea un viaje y añade lugares para ver tu mapa del mundo',
'atlas.noDataHint': 'Crea un viaje y añade lugares para ver tu mapa del mundo',
'atlas.lastTrip': 'Último viaje',
'atlas.nextTrip': 'Próximo viaje',
'atlas.daysLeft': 'días restantes',
@@ -45,8 +44,7 @@ const atlas: TranslationStrings = {
'atlas.unmark': 'Eliminar',
'atlas.confirmMark': '¿Marcar este país como visitado?',
'atlas.confirmUnmark': '¿Eliminar este país de tu lista de visitados?',
'atlas.confirmUnmarkRegion':
'¿Eliminar esta región de tu lista de visitados?',
'atlas.confirmUnmarkRegion': '¿Eliminar esta región de tu lista de visitados?',
'atlas.markVisited': 'Marcar como visitado',
'atlas.markVisitedHint': 'Añadir este país a tu lista de visitados',
'atlas.markRegionVisitedHint': 'Añadir esta región a tu lista de visitados',
+5 -10
View File
@@ -29,18 +29,15 @@ const backup: TranslationStrings = {
'backup.toast.settingsSaved': 'Ajustes de copia automática guardados',
'backup.toast.settingsError': 'No se pudieron guardar los ajustes',
'backup.auto.title': 'Copia automática',
'backup.auto.subtitle':
'Copia de seguridad automática según una programación',
'backup.auto.subtitle': 'Copia de seguridad automática según una programación',
'backup.auto.enable': 'Activar copia automática',
'backup.auto.enableHint':
'Se crearán copias automáticamente según la frecuencia elegida',
'backup.auto.enableHint': 'Se crearán copias automáticamente según la frecuencia elegida',
'backup.auto.interval': 'Intervalo',
'backup.auto.hour': 'Ejecutar a la hora',
'backup.auto.hourHint': 'Hora local del servidor (formato {format})',
'backup.auto.dayOfWeek': 'Día de la semana',
'backup.auto.dayOfMonth': 'Día del mes',
'backup.auto.dayOfMonthHint':
'Limitado a 128 para compatibilidad con todos los meses',
'backup.auto.dayOfMonthHint': 'Limitado a 128 para compatibilidad con todos los meses',
'backup.auto.scheduleSummary': 'Programación',
'backup.auto.summaryDaily': 'Todos los días a las {hour}:00',
'backup.auto.summaryWeekly': 'Cada {day} a las {hour}:00',
@@ -49,8 +46,7 @@ const backup: TranslationStrings = {
'backup.auto.envLockedHint':
'La copia automática está configurada mediante variables de entorno Docker. Para cambiar estos ajustes, actualiza tu docker-compose.yml y reinicia el contenedor.',
'backup.auto.copyEnv': 'Copiar variables de entorno Docker',
'backup.auto.envCopied':
'Variables de entorno Docker copiadas al portapapeles',
'backup.auto.envCopied': 'Variables de entorno Docker copiadas al portapapeles',
'backup.auto.keepLabel': 'Eliminar copias antiguas después de',
'backup.dow.sunday': 'Dom',
'backup.dow.monday': 'Lun',
@@ -72,8 +68,7 @@ const backup: TranslationStrings = {
'backup.restoreConfirmTitle': '¿Restaurar copia?',
'backup.restoreWarning':
'Todos los datos actuales (viajes, lugares, usuarios, subidas) serán reemplazados permanentemente por la copia. Esta acción no se puede deshacer.',
'backup.restoreTip':
'Consejo: crea una copia del estado actual antes de restaurar.',
'backup.restoreTip': 'Consejo: crea una copia del estado actual antes de restaurar.',
'backup.restoreConfirm': 'Sí, restaurar',
};
export default backup;
+82 -78
View File
@@ -4,8 +4,7 @@ const budget: TranslationStrings = {
'budget.title': 'Presupuesto',
'budget.exportCsv': 'Exportar CSV',
'budget.emptyTitle': 'Aún no se ha creado ningún presupuesto',
'budget.emptyText':
'Crea categorías y entradas para planificar el presupuesto de tu viaje',
'budget.emptyText': 'Crea categorías y entradas para planificar el presupuesto de tu viaje',
'budget.emptyPlaceholder': 'Introduce el nombre de la categoría...',
'budget.createCategory': 'Crear categoría',
'budget.category': 'Categoría',
@@ -26,10 +25,8 @@ const budget: TranslationStrings = {
'budget.totalBudget': 'Presupuesto total',
'budget.byCategory': 'Por categoría',
'budget.editTooltip': 'Haz clic para editar',
'budget.linkedToReservation':
'Vinculado a una reserva — edite el nombre allí',
'budget.confirm.deleteCategory':
'¿Seguro que quieres eliminar la categoría "{name}" con {count} entradas?',
'budget.linkedToReservation': 'Vinculado a una reserva — edite el nombre allí',
'budget.confirm.deleteCategory': '¿Seguro que quieres eliminar la categoría "{name}" con {count} entradas?',
'budget.deleteCategory': 'Eliminar categoría',
'budget.perPerson': 'Por persona',
'budget.paid': 'Pagado',
@@ -40,78 +37,85 @@ const budget: TranslationStrings = {
'Haz clic en el avatar de un miembro en una partida del presupuesto para marcarlo en verde — esto significa que ha pagado. La liquidación muestra quién debe cuánto a quién.',
'budget.netBalances': 'Saldos netos',
'budget.categoriesLabel': 'categorías',
"costs.you": "Tú",
"costs.youShort": "Tú",
"costs.youLower": "tú",
"costs.youOwe": "Debes",
"costs.youOweSub": "Deberías pagar a otros",
"costs.youreOwed": "Te deben",
"costs.youreOwedSub": "Otros deberían pagarte",
"costs.totalSpend": "Gasto total del viaje",
"costs.totalSpendSub": "Entre todos los viajeros",
"costs.to": "Para",
"costs.from": "De",
"costs.allSettled": "Estás al día con todo",
"costs.nothingOwed": "Nadie te debe nada",
"costs.yourShare": "Tu parte",
"costs.youPaid": "Pagaste",
"costs.expenses": "Gastos",
"costs.entries": "{count} entradas",
"costs.searchPlaceholder": "Buscar gastos…",
"costs.filter.all": "Todos",
"costs.filter.mine": "Pagados por mí",
"costs.filter.owed": "Me deben",
"costs.addExpense": "Añadir gasto",
"costs.editExpense": "Editar gasto",
"costs.noMatch": "Ningún gasto coincide con tu búsqueda.",
"costs.emptyText": "Aún no hay gastos. Añade el primero.",
"costs.spent": "{amount} gastados",
"costs.noDate": "Sin fecha",
"costs.noOnePaid": "Nadie ha pagado aún",
"costs.youLent": "prestaste {amount}",
"costs.youBorrowed": "tomaste prestado {amount}",
"costs.settleUp": "Saldar cuentas",
"costs.history": "Historial",
"costs.everyoneSquare": "Todos están en paz",
"costs.nothingOutstanding": "No hay pagos pendientes ahora mismo.",
"costs.pay": "paga",
"costs.pays": "paga",
"costs.settle": "Saldar",
"costs.balances": "Saldos",
"costs.byCategory": "Por categoría",
"costs.noCategories": "Aún no hay gastos.",
"costs.settleHistory": "Historial de pagos",
"costs.noSettlements": "Aún no hay pagos saldados.",
"costs.paymentsSettled": "{count} pagos saldados",
"costs.paid": "pagado",
"costs.undo": "Deshacer",
"costs.whatFor": "¿Para qué fue?",
"costs.namePlaceholder": "p. ej. Cena, souvenirs, gasolina…",
"costs.totalAmount": "Importe total",
"costs.currency": "Moneda",
"costs.day": "Día",
"costs.rateLabel": "1 {from} en {to}",
"costs.category": "Categoría",
"costs.whoPaid": "¿Quién pagó?",
"costs.splitBetween": "Dividir a partes iguales entre",
"costs.pickSomeone": "Elige al menos una persona con quien dividir.",
"costs.splitSummary": "Dividido entre {count} · {amount} cada uno",
"costs.cat.accommodation": "Alojamiento",
"costs.cat.food": "Comida y bebida",
"costs.cat.groceries": "Compras de comida",
"costs.cat.transport": "Transporte",
"costs.cat.flights": "Vuelos",
"costs.cat.activities": "Actividades",
"costs.cat.sightseeing": "Turismo",
"costs.cat.shopping": "Compras",
"costs.cat.fees": "Tasas y entradas",
"costs.cat.health": "Salud",
"costs.cat.tips": "Propinas",
"costs.cat.other": "Otros",
"costs.daysCount": "{count} días",
"costs.travelers": "{count} viajeros",
"costs.liveRate": "tasa en vivo",
"costs.settleAll": "Saldar todo",
'costs.you': 'Tú',
'costs.youShort': 'Tú',
'costs.youLower': 'tú',
'costs.youOwe': 'Debes',
'costs.youOweSub': 'Deberías pagar a otros',
'costs.youreOwed': 'Te deben',
'costs.youreOwedSub': 'Otros deberían pagarte',
'costs.totalSpend': 'Gasto total del viaje',
'costs.totalSpendSub': 'Entre todos los viajeros',
'costs.to': 'Para',
'costs.from': 'De',
'costs.allSettled': 'Estás al día con todo',
'costs.nothingOwed': 'Nadie te debe nada',
'costs.yourShare': 'Tu parte',
'costs.youPaid': 'Pagaste',
'costs.expenses': 'Gastos',
'costs.entries': '{count} entradas',
'costs.searchPlaceholder': 'Buscar gastos…',
'costs.filter.all': 'Todos',
'costs.filter.mine': 'Pagados por mí',
'costs.filter.owed': 'Me deben',
'costs.addExpense': 'Añadir gasto',
'costs.editExpense': 'Editar gasto',
'costs.noMatch': 'Ningún gasto coincide con tu búsqueda.',
'costs.emptyText': 'Aún no hay gastos. Añade el primero.',
'costs.spent': '{amount} gastados',
'costs.noDate': 'Sin fecha',
'costs.noOnePaid': 'Nadie ha pagado aún',
'costs.youLent': 'prestaste {amount}',
'costs.youBorrowed': 'tomaste prestado {amount}',
'costs.settleUp': 'Saldar cuentas',
'costs.history': 'Historial',
'costs.everyoneSquare': 'Todos están en paz',
'costs.nothingOutstanding': 'No hay pagos pendientes ahora mismo.',
'costs.pay': 'paga',
'costs.pays': 'paga',
'costs.settle': 'Saldar',
'costs.balances': 'Saldos',
'costs.byCategory': 'Por categoría',
'costs.noCategories': 'Aún no hay gastos.',
'costs.settleHistory': 'Historial de pagos',
'costs.noSettlements': 'Aún no hay pagos saldados.',
'costs.paymentsSettled': '{count} pagos saldados',
'costs.paid': 'pagado',
'costs.undo': 'Deshacer',
'costs.whatFor': '¿Para qué fue?',
'costs.namePlaceholder': 'p. ej. Cena, souvenirs, gasolina…',
'costs.totalAmount': 'Importe total',
'costs.currency': 'Moneda',
'costs.day': 'Día',
'costs.rateLabel': '1 {from} en {to}',
'costs.category': 'Categoría',
'costs.whoPaid': '¿Quién pagó?',
'costs.splitBetween': 'Dividir a partes iguales entre',
'costs.pickSomeone': 'Elige al menos una persona con quien dividir.',
'costs.splitSummary': 'Dividido entre {count} · {amount} cada uno',
'costs.cat.accommodation': 'Alojamiento',
'costs.cat.food': 'Comida y bebida',
'costs.cat.groceries': 'Compras de comida',
'costs.cat.transport': 'Transporte',
'costs.cat.flights': 'Vuelos',
'costs.cat.activities': 'Actividades',
'costs.cat.sightseeing': 'Turismo',
'costs.cat.shopping': 'Compras',
'costs.cat.fees': 'Tasas y entradas',
'costs.cat.health': 'Salud',
'costs.cat.tips': 'Propinas',
'costs.cat.other': 'Otros',
'costs.daysCount': '{count} días',
'costs.travelers': '{count} viajeros',
'costs.liveRate': 'tasa en vivo',
'costs.settleAll': 'Saldar todo',
'costs.payment': 'Pago',
'costs.editPayment': 'Editar pago',
'costs.addPayment': 'Añadir pago',
'costs.unfinished': 'Pendiente',
'costs.unfinishedHint': 'Solo en el total — aún sin saldar',
'costs.tapToInclude': 'Toca para incluir',
'costs.amount': 'Importe',
};
export default budget;
+1 -2
View File
@@ -13,8 +13,7 @@ const categories: TranslationStrings = {
'categories.defaultName': 'Categoría',
'categories.update': 'Actualizar',
'categories.create': 'Crear',
'categories.confirm.delete':
'¿Eliminar la categoría? Los lugares de esta categoría no se eliminarán.',
'categories.confirm.delete': '¿Eliminar la categoría? Los lugares de esta categoría no se eliminarán.',
'categories.toast.loadError': 'No se pudieron cargar las categorías',
'categories.toast.nameRequired': 'Introduce un nombre',
'categories.toast.updated': 'Categoría actualizada',
+2 -4
View File
@@ -13,10 +13,8 @@ const collab: TranslationStrings = {
'collab.chat.send': 'Enviar',
'collab.chat.placeholder': 'Escribe un mensaje...',
'collab.chat.empty': 'Empieza la conversación',
'collab.chat.emptyHint':
'Los mensajes se comparten con todos los miembros del viaje',
'collab.chat.emptyDesc':
'Comparte ideas, planes y novedades con tu grupo de viaje',
'collab.chat.emptyHint': 'Los mensajes se comparten con todos los miembros del viaje',
'collab.chat.emptyDesc': 'Comparte ideas, planes y novedades con tu grupo de viaje',
'collab.chat.today': 'Hoy',
'collab.chat.yesterday': 'Ayer',
'collab.chat.deletedMessage': 'eliminó un mensaje',
+1 -2
View File
@@ -16,8 +16,7 @@ const common: TranslationStrings = {
'common.deselectAll': 'Deseleccionar todo',
'common.error': 'Error',
'common.unknownError': 'Error desconocido',
'common.tooManyAttempts':
'Demasiados intentos. Inténtelo de nuevo más tarde.',
'common.tooManyAttempts': 'Demasiados intentos. Inténtelo de nuevo más tarde.',
'common.back': 'Atrás',
'common.all': 'Todo',
'common.close': 'Cerrar',
+5 -10
View File
@@ -20,8 +20,7 @@ const dashboard: TranslationStrings = {
'dashboard.timezoneCustomTzPlaceholder': 'ej. America/New_York',
'dashboard.timezoneCustomAdd': 'Añadir',
'dashboard.timezoneCustomErrorEmpty': 'Introduce una zona horaria',
'dashboard.timezoneCustomErrorInvalid':
'Zona horaria no válida. Usa formato como Europe/Madrid',
'dashboard.timezoneCustomErrorInvalid': 'Zona horaria no válida. Usa formato como Europe/Madrid',
'dashboard.timezoneCustomErrorDuplicate': 'Ya añadida',
'dashboard.emptyTitle': 'Aún no hay viajes',
'dashboard.emptyText': 'Crea tu primer viaje y empieza a planificar',
@@ -55,8 +54,7 @@ const dashboard: TranslationStrings = {
'dashboard.toast.restoreError': 'No se pudo restaurar el viaje',
'dashboard.toast.copied': '¡Viaje copiado!',
'dashboard.toast.copyError': 'No se pudo copiar el viaje',
'dashboard.confirm.delete':
'¿Eliminar el viaje "{title}"? Todos los lugares y planes se borrarán permanentemente.',
'dashboard.confirm.delete': '¿Eliminar el viaje "{title}"? Todos los lugares y planes se borrarán permanentemente.',
'dashboard.editTrip': 'Editar viaje',
'dashboard.createTrip': 'Crear nuevo viaje',
'dashboard.tripTitle': 'Título',
@@ -66,10 +64,8 @@ const dashboard: TranslationStrings = {
'dashboard.startDate': 'Fecha de inicio',
'dashboard.endDate': 'Fecha de fin',
'dashboard.dayCount': 'Número de días',
'dashboard.dayCountHint':
'Cuántos días planificar cuando no se han establecido fechas de viaje.',
'dashboard.noDateHint':
'Sin fecha definida: se crearán 7 días por defecto. Puedes cambiarlo cuando quieras.',
'dashboard.dayCountHint': 'Cuántos días planificar cuando no se han establecido fechas de viaje.',
'dashboard.noDateHint': 'Sin fecha definida: se crearán 7 días por defecto. Puedes cambiarlo cuando quieras.',
'dashboard.coverImage': 'Imagen de portada',
'dashboard.addCoverImage': 'Añadir imagen de portada',
'dashboard.addMembers': 'Compañeros de viaje',
@@ -146,8 +142,7 @@ const dashboard: TranslationStrings = {
'dashboard.confirm.copy.willCopy': 'Se copiará',
'dashboard.confirm.copy.will1': 'Días, lugares y asignaciones por día',
'dashboard.confirm.copy.will2': 'Alojamientos y reservas',
'dashboard.confirm.copy.will3':
'Partidas de presupuesto y orden de categorías',
'dashboard.confirm.copy.will3': 'Partidas de presupuesto y orden de categorías',
'dashboard.confirm.copy.will4': 'Listas de equipaje (sin marcar)',
'dashboard.confirm.copy.will5': 'Tareas (sin asignar ni marcar)',
'dashboard.confirm.copy.will6': 'Notas del día',
+1 -2
View File
@@ -9,8 +9,7 @@ const day: TranslationStrings = {
'day.hourlyForecast': 'Pronóstico por horas',
'day.climateHint':
'Promedios históricos: el pronóstico real está disponible dentro de los 16 días previos a la fecha.',
'day.noWeather':
'No hay datos meteorológicos disponibles. Añade un lugar con coordenadas.',
'day.noWeather': 'No hay datos meteorológicos disponibles. Añade un lugar con coordenadas.',
'day.overview': 'Resumen diario',
'day.accommodation': 'Alojamiento',
'day.addAccommodation': 'Añadir alojamiento',
+5 -10
View File
@@ -17,29 +17,24 @@ const dayplan: TranslationStrings = {
'dayplan.optimize': 'Optimizar',
'dayplan.optimized': 'Ruta optimizada',
'dayplan.routeError': 'No se pudo calcular la ruta',
'dayplan.toast.needTwoPlaces':
'Se necesitan al menos dos lugares para optimizar la ruta',
'dayplan.toast.needTwoPlaces': 'Se necesitan al menos dos lugares para optimizar la ruta',
'dayplan.toast.routeOptimized': 'Ruta optimizada',
'dayplan.toast.routeOptimizedFromHotel': 'Ruta optimizada desde tu alojamiento',
'dayplan.toast.noGeoPlaces':
'No se encontraron lugares con coordenadas para calcular la ruta',
'dayplan.toast.noGeoPlaces': 'No se encontraron lugares con coordenadas para calcular la ruta',
'dayplan.confirmed': 'Confirmado',
'dayplan.pendingRes': 'Pendiente',
'dayplan.pdf': 'PDF',
'dayplan.pdfTooltip': 'Exportar plan diario como PDF',
'dayplan.pdfError': 'No se pudo exportar el PDF',
'dayplan.cannotReorderTransport':
'Las reservas con hora fija no se pueden reordenar',
'dayplan.cannotReorderTransport': 'Las reservas con hora fija no se pueden reordenar',
'dayplan.confirmRemoveTimeTitle': '¿Eliminar hora?',
'dayplan.confirmRemoveTimeBody':
'Este lugar tiene una hora fija ({time}). Al moverlo se eliminará la hora y se permitirá el orden libre.',
'dayplan.confirmRemoveTimeAction': 'Eliminar hora y mover',
'dayplan.confirmDeleteNoteTitle': '¿Eliminar nota?',
'dayplan.confirmDeleteNoteBody': 'Esta nota se eliminará de forma permanente.',
'dayplan.cannotDropOnTimed':
'No se pueden colocar elementos entre entradas con hora fija',
'dayplan.cannotBreakChronology':
'Esto rompería el orden cronológico de los elementos y reservas programados',
'dayplan.cannotDropOnTimed': 'No se pueden colocar elementos entre entradas con hora fija',
'dayplan.cannotBreakChronology': 'Esto rompería el orden cronológico de los elementos y reservas programados',
'dayplan.mobile.addPlace': 'Añadir lugar',
'dayplan.mobile.searchPlaces': 'Buscar lugares...',
'dayplan.mobile.allAssigned': 'Todos los lugares asignados',
+2 -4
View File
@@ -2,8 +2,7 @@ import type { NotificationLocale } from '../externalNotifications/types';
const es: NotificationLocale = {
email: {
footer:
'Recibiste esto porque tienes las notificaciones activadas en TREK.',
footer: 'Recibiste esto porque tienes las notificaciones activadas en TREK.',
manage: 'Gestionar preferencias',
madeWith: 'Made with',
openTrek: 'Abrir TREK',
@@ -56,8 +55,7 @@ const es: NotificationLocale = {
body: 'Recibimos una solicitud para restablecer la contraseña de tu cuenta de TREK. Haz clic en el botón de abajo para establecer una nueva contraseña.',
ctaIntro: 'Restablecer contraseña',
expiry: 'Este enlace caduca en 60 minutos.',
ignore:
'Si no solicitaste esto, puedes ignorar este correo — tu contraseña no cambiará.',
ignore: 'Si no solicitaste esto, puedes ignorar este correo — tu contraseña no cambiará.',
},
};
+4 -8
View File
@@ -13,8 +13,7 @@ const files: TranslationStrings = {
'files.uploadError': 'La subida falló',
'files.dropzone': 'Arrastra aquí los archivos',
'files.dropzoneHint': 'o haz clic para explorar',
'files.allowedTypes':
'Imágenes, PDF, DOC, DOCX, XLS, XLSX, TXT, CSV · Máx. 50 MB',
'files.allowedTypes': 'Imágenes, PDF, DOC, DOCX, XLS, XLSX, TXT, CSV · Máx. 50 MB',
'files.uploading': 'Subiendo...',
'files.filterAll': 'Todo',
'files.filterPdf': 'PDF',
@@ -32,8 +31,7 @@ const files: TranslationStrings = {
'files.sourceBooking': 'Reserva',
'files.sourceTransport': 'Transporte',
'files.attach': 'Adjuntar',
'files.pasteHint':
'También puedes pegar imágenes desde el portapapeles (Ctrl+V)',
'files.pasteHint': 'También puedes pegar imágenes desde el portapapeles (Ctrl+V)',
'files.trash': 'Papelera',
'files.trashEmpty': 'La papelera está vacía',
'files.emptyTrash': 'Vaciar papelera',
@@ -55,9 +53,7 @@ const files: TranslationStrings = {
'files.toast.assigned': 'Archivo asignado',
'files.toast.assignError': 'Error al asignar',
'files.toast.restoreError': 'Error al restaurar',
'files.confirm.permanentDelete':
'Eliminar este archivo permanentemente? No se puede deshacer.',
'files.confirm.emptyTrash':
'Eliminar todos los archivos de la papelera? No se puede deshacer.',
'files.confirm.permanentDelete': 'Eliminar este archivo permanentemente? No se puede deshacer.',
'files.confirm.emptyTrash': 'Eliminar todos los archivos de la papelera? No se puede deshacer.',
};
export default files;
+14 -28
View File
@@ -14,14 +14,12 @@ const journey: TranslationStrings = {
'journey.createError': 'No se pudo crear la travesía',
'journey.deleteError': 'No se pudo eliminar la travesía',
'journey.deleteConfirmTitle': 'Eliminar',
'journey.deleteConfirmMessage':
'¿Eliminar "{title}"? Esta acción no se puede deshacer.',
'journey.deleteConfirmMessage': '¿Eliminar "{title}"? Esta acción no se puede deshacer.',
'journey.deleteConfirmGeneric': '¿Estás seguro de que quieres eliminar esto?',
'journey.notFound': 'Travesía no encontrada',
'journey.photos': 'Fotos',
'journey.timelineEmpty': 'Aún no hay paradas',
'journey.timelineEmptyHint':
'Añade un registro de ubicación o escribe una entrada de diario para empezar',
'journey.timelineEmptyHint': 'Añade un registro de ubicación o escribe una entrada de diario para empezar',
'journey.status.draft': 'Borrador',
'journey.status.active': 'Activa',
'journey.status.completed': 'Completada',
@@ -47,30 +45,25 @@ const journey: TranslationStrings = {
'journey.editor.titlePlaceholder': 'Dale un nombre a este momento...',
'journey.editor.bodyPlaceholder': 'Cuenta la historia de este día...',
'journey.editor.placePlaceholder': 'Ubicación (opcional)',
'journey.editor.tagsPlaceholder':
'Etiquetas: joya oculta, mejor comida, hay que volver...',
'journey.editor.tagsPlaceholder': 'Etiquetas: joya oculta, mejor comida, hay que volver...',
'journey.visibility.private': 'Privado',
'journey.visibility.shared': 'Compartido',
'journey.visibility.public': 'Público',
'journey.emptyState.title': 'Tu historia empieza aquí',
'journey.emptyState.subtitle':
'Registra una ubicación o escribe tu primera entrada de diario',
'journey.frontpage.subtitle':
'Convierte tus viajes en historias que nunca olvidarás',
'journey.emptyState.subtitle': 'Registra una ubicación o escribe tu primera entrada de diario',
'journey.frontpage.subtitle': 'Convierte tus viajes en historias que nunca olvidarás',
'journey.frontpage.createJourney': 'Crear travesía',
'journey.frontpage.activeJourney': 'Travesía activa',
'journey.frontpage.allJourneys': 'Todas las travesías',
'journey.frontpage.journeys': 'travesías',
'journey.frontpage.createNew': 'Crear una nueva travesía',
'journey.frontpage.createNewSub':
'Elige viajes, escribe historias, comparte tus aventuras',
'journey.frontpage.createNewSub': 'Elige viajes, escribe historias, comparte tus aventuras',
'journey.frontpage.live': 'En vivo',
'journey.frontpage.synced': 'Sincronizado',
'journey.frontpage.continueWriting': 'Seguir escribiendo',
'journey.frontpage.updated': 'Actualizado {time}',
'journey.frontpage.suggestionLabel': 'El viaje acaba de terminar',
'journey.frontpage.suggestionText':
'Convierte <strong>{title}</strong> en una travesía',
'journey.frontpage.suggestionText': 'Convierte <strong>{title}</strong> en una travesía',
'journey.frontpage.dismiss': 'Descartar',
'journey.frontpage.journeyName': 'Nombre de la travesía',
'journey.frontpage.namePlaceholder': 'p. ej. Sudeste Asiático 2026',
@@ -85,11 +78,9 @@ const journey: TranslationStrings = {
'journey.detail.newEntry': 'Nueva entrada',
'journey.detail.editEntry': 'Editar entrada',
'journey.detail.noEntries': 'Aún no hay entradas',
'journey.detail.noEntriesHint':
'Añade un viaje para empezar con entradas preliminares',
'journey.detail.noEntriesHint': 'Añade un viaje para empezar con entradas preliminares',
'journey.detail.noPhotos': 'Aún no hay fotos',
'journey.detail.noPhotosHint':
'Sube fotos a las entradas o explora tu biblioteca de Immich/Synology',
'journey.detail.noPhotosHint': 'Sube fotos a las entradas o explora tu biblioteca de Immich/Synology',
'journey.detail.journeyStats': 'Estadísticas de la travesía',
'journey.detail.syncedTrips': 'Viajes sincronizados',
'journey.detail.noTripsLinked': 'Aún no hay viajes vinculados',
@@ -110,14 +101,12 @@ const journey: TranslationStrings = {
'journey.verdict.couldBeBetter': 'Podría mejorar',
'journey.synced.places': 'lugares',
'journey.synced.synced': 'sincronizado',
'journey.editor.discardChangesConfirm':
'Tienes cambios sin guardar. ¿Descartarlos?',
'journey.editor.discardChangesConfirm': 'Tienes cambios sin guardar. ¿Descartarlos?',
'journey.editor.uploadFailed': 'Error al subir fotos',
'journey.editor.uploadPhotos': 'Subir fotos',
'journey.editor.uploading': 'Subiendo...',
'journey.editor.uploadingProgress': 'Subiendo {done}/{total}…',
'journey.editor.uploadPartialFailed':
'{failed} de {total} fotos fallaron — guarda de nuevo para reintentar',
'journey.editor.uploadPartialFailed': '{failed} de {total} fotos fallaron — guarda de nuevo para reintentar',
'journey.editor.fromGallery': 'Desde galería',
'journey.editor.allPhotosAdded': 'Todas las fotos ya fueron añadidas',
'journey.editor.writeStory': 'Escribe tu historia...',
@@ -196,12 +185,10 @@ const journey: TranslationStrings = {
'journey.settings.reopenJourney': 'Restaurar viaje',
'journey.settings.archived': 'Viaje archivado',
'journey.settings.reopened': 'Viaje reabierto',
'journey.settings.endDescription':
'Oculta la insignia En Vivo. Puedes reabrirlo en cualquier momento.',
'journey.settings.endDescription': 'Oculta la insignia En Vivo. Puedes reabrirlo en cualquier momento.',
'journey.settings.delete': 'Eliminar',
'journey.settings.deleteJourney': 'Eliminar travesía',
'journey.settings.deleteMessage':
'¿Eliminar "{title}"? Todas las entradas y fotos se perderán.',
'journey.settings.deleteMessage': '¿Eliminar "{title}"? Todas las entradas y fotos se perderán.',
'journey.settings.saved': 'Ajustes guardados',
'journey.settings.saveFailed': 'No se pudo guardar',
'journey.settings.coverUpdated': 'Portada actualizada',
@@ -212,8 +199,7 @@ const journey: TranslationStrings = {
'journey.photosUploadFailed': 'Algunas fotos no se pudieron subir',
'journey.photosAdded': '{count} fotos añadidas',
'journey.public.notFound': 'No encontrado',
'journey.public.notFoundMessage':
'Esta travesía no existe o el enlace ha expirado.',
'journey.public.notFoundMessage': 'Esta travesía no existe o el enlace ha expirado.',
'journey.public.readOnly': 'Solo lectura · Travesía pública',
'journey.public.tagline': 'Kit de recursos y exploración de viajes',
'journey.public.sharedVia': 'Compartido mediante',
+13 -26
View File
@@ -20,17 +20,14 @@ const login: TranslationStrings = {
'login.features.files': 'Documentos',
'login.features.filesDesc': 'Sube y gestiona documentos',
'login.features.routes': 'Rutas inteligentes',
'login.features.routesDesc':
'Optimización automática y exportación a Google Maps',
'login.selfHosted':
'Autoalojado · Código abierto · Tus datos siguen siendo tuyos',
'login.features.routesDesc': 'Optimización automática y exportación a Google Maps',
'login.selfHosted': 'Autoalojado · Código abierto · Tus datos siguen siendo tuyos',
'login.title': 'Iniciar sesión',
'login.subtitle': 'Bienvenido de nuevo',
'login.signingIn': 'Iniciando sesión…',
'login.signIn': 'Entrar',
'login.createAdmin': 'Crear cuenta de administrador',
'login.createAdminHint':
'Configura la primera cuenta administradora de TREK.',
'login.createAdminHint': 'Configura la primera cuenta administradora de TREK.',
'login.setNewPassword': 'Establecer nueva contraseña',
'login.setNewPasswordHint': 'Debe cambiar su contraseña antes de continuar.',
'login.createAccount': 'Crear cuenta',
@@ -41,12 +38,10 @@ const login: TranslationStrings = {
'login.register': 'Registrarse',
'login.emailPlaceholder': 'tu@correo.com',
'login.username': 'Usuario',
'login.oidc.registrationDisabled':
'El registro está desactivado. Contacta con tu administrador.',
'login.oidc.registrationDisabled': 'El registro está desactivado. Contacta con tu administrador.',
'login.oidc.noEmail': 'No se recibió ningún correo del proveedor.',
'login.mfaTitle': 'Autenticación de dos factores',
'login.mfaSubtitle':
'Introduce el código de 6 dígitos de tu app de autenticación.',
'login.mfaSubtitle': 'Introduce el código de 6 dígitos de tu app de autenticación.',
'login.mfaCodeLabel': 'Código de verificación',
'login.mfaCodeRequired': 'Introduce el código de tu app de autenticación.',
'login.mfaHint': 'Abre Google Authenticator, Authy u otra app TOTP.',
@@ -73,31 +68,23 @@ const login: TranslationStrings = {
'login.passwordsDontMatch': 'Las contraseñas no coinciden',
'login.mfaCode': 'Código 2FA',
'login.resetPasswordTitle': 'Establecer una nueva contraseña',
'login.resetPasswordBody':
'Elige una contraseña segura que no hayas usado aquí antes. Mínimo 8 caracteres.',
'login.resetPasswordMfaBody':
'Introduce tu código 2FA o un código de respaldo para completar el restablecimiento.',
'login.resetPasswordBody': 'Elige una contraseña segura que no hayas usado aquí antes. Mínimo 8 caracteres.',
'login.resetPasswordMfaBody': 'Introduce tu código 2FA o un código de respaldo para completar el restablecimiento.',
'login.resetPasswordSubmit': 'Restablecer contraseña',
'login.resetPasswordVerify': 'Verificar y restablecer',
'login.resetPasswordSuccessTitle': 'Contraseña actualizada',
'login.resetPasswordSuccessBody':
'Ya puedes iniciar sesión con tu nueva contraseña.',
'login.resetPasswordSuccessBody': 'Ya puedes iniciar sesión con tu nueva contraseña.',
'login.resetPasswordInvalidLink': 'Enlace de restablecimiento no válido',
'login.resetPasswordInvalidLinkBody':
'Este enlace falta o está roto. Solicita uno nuevo para continuar.',
'login.resetPasswordFailed':
'Restablecimiento fallido. El enlace puede haber caducado.',
'login.resetPasswordInvalidLinkBody': 'Este enlace falta o está roto. Solicita uno nuevo para continuar.',
'login.resetPasswordFailed': 'Restablecimiento fallido. El enlace puede haber caducado.',
'login.oidc.tokenFailed': 'La autenticación falló.',
'login.oidc.invalidState': 'Sesión no válida. Inténtalo de nuevo.',
'login.demoFailed': 'Falló el acceso a la demo',
'login.oidcSignIn': 'Entrar con {name}',
'login.demoHint': 'Prueba la demo: no necesitas registrarte',
'login.oidcOnly':
'La autenticación por contraseña está desactivada. Por favor, inicia sesión con tu proveedor SSO.',
'login.oidcLoggedOut':
'Has cerrado sesión. Vuelve a iniciar sesión con tu proveedor SSO.',
'login.oidcOnly': 'La autenticación por contraseña está desactivada. Por favor, inicia sesión con tu proveedor SSO.',
'login.oidcLoggedOut': 'Has cerrado sesión. Vuelve a iniciar sesión con tu proveedor SSO.',
'login.passkey.signIn': 'Iniciar sesión con una passkey',
'login.passkey.failed':
'Error al iniciar sesión con la passkey. Inténtalo de nuevo.',
'login.passkey.failed': 'Error al iniciar sesión con la passkey. Inténtalo de nuevo.',
};
export default login;
+7 -14
View File
@@ -3,14 +3,12 @@ import type { TranslationStrings } from '../types';
const memories: TranslationStrings = {
'memories.title': 'Fotos',
'memories.notConnected': 'Immich no conectado',
'memories.notConnectedHint':
'Conecta tu instancia de Immich en Ajustes para ver tus fotos de viaje aquí.',
'memories.notConnectedHint': 'Conecta tu instancia de Immich en Ajustes para ver tus fotos de viaje aquí.',
'memories.notConnectedMultipleHint':
'Conecta alguno de estos proveedores de fotos: {provider_names} en Configuración para poder añadir fotos a este viaje.',
'memories.noDates': 'Añade fechas a tu viaje para cargar fotos.',
'memories.noPhotos': 'No se encontraron fotos',
'memories.noPhotosHint':
'No se encontraron fotos en Immich para el rango de fechas de este viaje.',
'memories.noPhotosHint': 'No se encontraron fotos en Immich para el rango de fechas de este viaje.',
'memories.photosFound': 'fotos',
'memories.fromOthers': 'de otros',
'memories.sharePhotos': 'Compartir fotos',
@@ -24,10 +22,8 @@ const memories: TranslationStrings = {
'memories.providerPassword': 'Contraseña',
'memories.providerOTP': 'Código MFA (si está habilitado)',
'memories.skipSSLVerification': 'Omitir verificación del certificado SSL',
'memories.immichAutoUpload':
'Duplicar las fotos del journey en Immich al subirlas',
'memories.providerUrlHintSynology':
'Incluye la ruta de la aplicación Photos en la URL, p.ej. https://nas:5001/photo',
'memories.immichAutoUpload': 'Duplicar las fotos del journey en Immich al subirlas',
'memories.providerUrlHintSynology': 'Incluye la ruta de la aplicación Photos en la URL, p.ej. https://nas:5001/photo',
'memories.testConnection': 'Probar conexión',
'memories.testShort': 'Probar',
'memories.testFirst': 'Probar conexión primero',
@@ -39,12 +35,9 @@ const memories: TranslationStrings = {
'memories.providerDisconnectedBanner':
'Se perdió la conexión con {provider_name}. Vuelve a conectar en Configuración para ver las fotos.',
'memories.saveError': 'No se pudieron guardar los ajustes de {provider_name}',
'memories.saveRouteNotConfigured':
'La ruta de guardado no está configurada para este proveedor',
'memories.testRouteNotConfigured':
'La ruta de prueba no está configurada para este proveedor',
'memories.fillRequiredFields':
'Por favor complete todos los campos requeridos',
'memories.saveRouteNotConfigured': 'La ruta de guardado no está configurada para este proveedor',
'memories.testRouteNotConfigured': 'La ruta de prueba no está configurada para este proveedor',
'memories.fillRequiredFields': 'Por favor complete todos los campos requeridos',
'memories.oldest': 'Más antiguas',
'memories.newest': 'Más recientes',
'memories.allLocations': 'Todas las ubicaciones',
+2 -4
View File
@@ -14,8 +14,7 @@ const notif: TranslationStrings = {
'notif.todo_due.title': 'Tarea pendiente',
'notif.todo_due.text': '{todo} en {trip} vence el {due}',
'notif.vacay_invite.title': 'Invitación Vacay Fusion',
'notif.vacay_invite.text':
'{actor} te invitó a fusionar planes de vacaciones',
'notif.vacay_invite.text': '{actor} te invitó a fusionar planes de vacaciones',
'notif.photos_shared.title': 'Fotos compartidas',
'notif.photos_shared.text': '{actor} compartió {count} foto(s) en {trip}',
'notif.collab_message.title': 'Nuevo mensaje',
@@ -36,7 +35,6 @@ const notif: TranslationStrings = {
'notif.generic.title': 'Notificación',
'notif.generic.text': 'Tienes una nueva notificación',
'notif.dev.unknown_event.title': '[DEV] Evento desconocido',
'notif.dev.unknown_event.text':
'El tipo de evento "{event}" no está registrado en EVENT_NOTIFICATION_CONFIG',
'notif.dev.unknown_event.text': 'El tipo de evento "{event}" no está registrado en EVENT_NOTIFICATION_CONFIG',
};
export default notif;
+2 -4
View File
@@ -26,11 +26,9 @@ const notifications: TranslationStrings = {
'notifications.test.navigateText': 'Notificación de prueba de navegación.',
'notifications.test.goThere': 'Ir allí',
'notifications.test.adminTitle': 'Difusión de administrador',
'notifications.test.adminText':
'{actor} envió una notificación de prueba a todos los administradores.',
'notifications.test.adminText': '{actor} envió una notificación de prueba a todos los administradores.',
'notifications.test.tripTitle': '{actor} publicó en tu viaje',
'notifications.test.tripText':
'Notificación de prueba para el viaje "{trip}".',
'notifications.test.tripText': 'Notificación de prueba para el viaje "{trip}".',
'notifications.versionAvailable.title': 'Actualización disponible',
'notifications.versionAvailable.text': 'TREK {version} ya está disponible.',
'notifications.versionAvailable.button': 'Ver detalles',
+31 -62
View File
@@ -17,95 +17,66 @@ const oauth: TranslationStrings = {
'oauth.scope.trips:read.label': 'Ver viajes e itinerarios',
'oauth.scope.trips:read.description': 'Leer viajes, días, notas y miembros',
'oauth.scope.trips:write.label': 'Editar viajes e itinerarios',
'oauth.scope.trips:write.description':
'Crear y actualizar viajes, días, notas y gestionar miembros',
'oauth.scope.trips:write.description': 'Crear y actualizar viajes, días, notas y gestionar miembros',
'oauth.scope.trips:delete.label': 'Eliminar viajes',
'oauth.scope.trips:delete.description':
'Eliminar viajes permanentemente — esta acción es irreversible',
'oauth.scope.trips:delete.description': 'Eliminar viajes permanentemente — esta acción es irreversible',
'oauth.scope.trips:share.label': 'Gestionar enlaces de compartir',
'oauth.scope.trips:share.description':
'Crear, actualizar y revocar enlaces públicos de viaje',
'oauth.scope.trips:share.description': 'Crear, actualizar y revocar enlaces públicos de viaje',
'oauth.scope.places:read.label': 'Ver lugares y datos del mapa',
'oauth.scope.places:read.description':
'Leer lugares, asignaciones de días, etiquetas y categorías',
'oauth.scope.places:read.description': 'Leer lugares, asignaciones de días, etiquetas y categorías',
'oauth.scope.places:write.label': 'Gestionar lugares',
'oauth.scope.places:write.description':
'Crear, actualizar y eliminar lugares, asignaciones y etiquetas',
'oauth.scope.places:write.description': 'Crear, actualizar y eliminar lugares, asignaciones y etiquetas',
'oauth.scope.atlas:read.label': 'Ver Atlas',
'oauth.scope.atlas:read.description':
'Leer países visitados, regiones y lista de deseos',
'oauth.scope.atlas:read.description': 'Leer países visitados, regiones y lista de deseos',
'oauth.scope.atlas:write.label': 'Gestionar Atlas',
'oauth.scope.atlas:write.description':
'Marcar países y regiones como visitados, gestionar lista de deseos',
'oauth.scope.atlas:write.description': 'Marcar países y regiones como visitados, gestionar lista de deseos',
'oauth.scope.packing:read.label': 'Ver listas de equipaje',
'oauth.scope.packing:read.description':
'Leer artículos, maletas y responsables de categoría',
'oauth.scope.packing:read.description': 'Leer artículos, maletas y responsables de categoría',
'oauth.scope.packing:write.label': 'Gestionar listas de equipaje',
'oauth.scope.packing:write.description':
'Agregar, actualizar, eliminar, marcar y reordenar artículos y maletas',
'oauth.scope.packing:write.description': 'Agregar, actualizar, eliminar, marcar y reordenar artículos y maletas',
'oauth.scope.todos:read.label': 'Ver listas de tareas',
'oauth.scope.todos:read.description':
'Leer tareas del viaje y responsables de categoría',
'oauth.scope.todos:read.description': 'Leer tareas del viaje y responsables de categoría',
'oauth.scope.todos:write.label': 'Gestionar listas de tareas',
'oauth.scope.todos:write.description':
'Crear, actualizar, marcar, eliminar y reordenar tareas',
'oauth.scope.todos:write.description': 'Crear, actualizar, marcar, eliminar y reordenar tareas',
'oauth.scope.budget:read.label': 'Ver presupuesto',
'oauth.scope.budget:read.description':
'Leer partidas de presupuesto y desglose de gastos',
'oauth.scope.budget:read.description': 'Leer partidas de presupuesto y desglose de gastos',
'oauth.scope.budget:write.label': 'Gestionar presupuesto',
'oauth.scope.budget:write.description':
'Crear, actualizar y eliminar partidas de presupuesto',
'oauth.scope.budget:write.description': 'Crear, actualizar y eliminar partidas de presupuesto',
'oauth.scope.reservations:read.label': 'Ver reservas',
'oauth.scope.reservations:read.description':
'Leer reservas y detalles de alojamiento',
'oauth.scope.reservations:read.description': 'Leer reservas y detalles de alojamiento',
'oauth.scope.reservations:write.label': 'Gestionar reservas',
'oauth.scope.reservations:write.description':
'Crear, actualizar, eliminar y reordenar reservas',
'oauth.scope.reservations:write.description': 'Crear, actualizar, eliminar y reordenar reservas',
'oauth.scope.collab:read.label': 'Ver colaboración',
'oauth.scope.collab:read.description':
'Leer notas colaborativas, encuestas y mensajes',
'oauth.scope.collab:read.description': 'Leer notas colaborativas, encuestas y mensajes',
'oauth.scope.collab:write.label': 'Gestionar colaboración',
'oauth.scope.collab:write.description':
'Crear, actualizar y eliminar notas, encuestas y mensajes',
'oauth.scope.collab:write.description': 'Crear, actualizar y eliminar notas, encuestas y mensajes',
'oauth.scope.notifications:read.label': 'Ver notificaciones',
'oauth.scope.notifications:read.description':
'Leer notificaciones y conteos no leídos',
'oauth.scope.notifications:read.description': 'Leer notificaciones y conteos no leídos',
'oauth.scope.notifications:write.label': 'Gestionar notificaciones',
'oauth.scope.notifications:write.description':
'Marcar notificaciones como leídas y responderlas',
'oauth.scope.notifications:write.description': 'Marcar notificaciones como leídas y responderlas',
'oauth.scope.vacay:read.label': 'Ver planes de vacaciones',
'oauth.scope.vacay:read.description':
'Leer datos de planificación, entradas y estadísticas de vacaciones',
'oauth.scope.vacay:read.description': 'Leer datos de planificación, entradas y estadísticas de vacaciones',
'oauth.scope.vacay:write.label': 'Gestionar planes de vacaciones',
'oauth.scope.vacay:write.description':
'Crear y gestionar entradas de vacaciones, festivos y planes de equipo',
'oauth.scope.vacay:write.description': 'Crear y gestionar entradas de vacaciones, festivos y planes de equipo',
'oauth.scope.geo:read.label': 'Mapas y geocodificación',
'oauth.scope.geo:read.description':
'Buscar lugares, resolver URLs de mapa y geocodificar coordenadas',
'oauth.scope.geo:read.description': 'Buscar lugares, resolver URLs de mapa y geocodificar coordenadas',
'oauth.scope.weather:read.label': 'Previsiones meteorológicas',
'oauth.scope.weather:read.description':
'Obtener previsiones meteorológicas para lugares y fechas del viaje',
'oauth.scope.weather:read.description': 'Obtener previsiones meteorológicas para lugares y fechas del viaje',
'oauth.scope.journey:read.label': 'Ver travesías',
'oauth.scope.journey:read.description':
'Leer travesías, entradas y lista de colaboradores',
'oauth.scope.journey:read.description': 'Leer travesías, entradas y lista de colaboradores',
'oauth.scope.journey:write.label': 'Gestionar travesías',
'oauth.scope.journey:write.description':
'Crear, actualizar y eliminar travesías y sus entradas',
'oauth.scope.journey:write.description': 'Crear, actualizar y eliminar travesías y sus entradas',
'oauth.scope.journey:share.label': 'Gestionar enlaces de travesías',
'oauth.scope.journey:share.description':
'Crear, actualizar y revocar enlaces públicos de compartir para travesías',
'oauth.scope.journey:share.description': 'Crear, actualizar y revocar enlaces públicos de compartir para travesías',
'oauth.authorize.authorizing': 'Authorizing…', // en-fallback
'oauth.authorize.loading': 'Loading…', // en-fallback
'oauth.authorize.errorTitle': 'Authorization Error', // en-fallback
'oauth.authorize.loginTitle': 'Sign in to continue', // en-fallback
'oauth.authorize.loginDescription':
'{client} wants access to your TREK account. Please sign in first.', // en-fallback
'oauth.authorize.loginDescription': '{client} wants access to your TREK account. Please sign in first.', // en-fallback
'oauth.authorize.loginButton': 'Sign in to TREK', // en-fallback
'oauth.authorize.requestLabel': 'Authorization Request', // en-fallback
'oauth.authorize.requestDescription':
'This application is requesting access to your TREK account.', // en-fallback
'oauth.authorize.trustNote':
'Only grant access to applications you trust. Your data stays on your server.', // en-fallback
'oauth.authorize.requestDescription': 'This application is requesting access to your TREK account.', // en-fallback
'oauth.authorize.trustNote': 'Only grant access to applications you trust. Your data stays on your server.', // en-fallback
'oauth.authorize.selectScope': 'Select at least one scope', // en-fallback
'oauth.authorize.approveOneScope': 'Approve ({count} scope)', // en-fallback
'oauth.authorize.approveManyScopes': 'Approve ({count} scopes)', // en-fallback
@@ -114,9 +85,7 @@ const oauth: TranslationStrings = {
'oauth.authorize.choosePermissions': 'Choose which permissions to grant', // en-fallback
'oauth.authorize.permissionsRequested': 'Permissions requested', // en-fallback
'oauth.authorize.alwaysIncluded': 'Always included', // en-fallback
'oauth.authorize.alwaysTool.listTrips':
'List your trips so the AI can discover trip IDs', // en-fallback
'oauth.authorize.alwaysTool.getTripSummary':
'Read a trip overview needed to use any other tool', // en-fallback
'oauth.authorize.alwaysTool.listTrips': 'List your trips so the AI can discover trip IDs', // en-fallback
'oauth.authorize.alwaysTool.getTripSummary': 'Read a trip overview needed to use any other tool', // en-fallback
};
export default oauth;
+2 -4
View File
@@ -51,10 +51,8 @@ const packing: TranslationStrings = {
'packing.bagName': 'Nombre...',
'packing.addBag': 'Añadir equipaje',
'packing.changeCategory': 'Cambiar categoría',
'packing.confirm.clearChecked':
'¿Seguro que quieres eliminar {count} elementos marcados?',
'packing.confirm.deleteCat':
'¿Seguro que quieres eliminar la categoría "{name}" con {count} elementos?',
'packing.confirm.clearChecked': '¿Seguro que quieres eliminar {count} elementos marcados?',
'packing.confirm.deleteCat': '¿Seguro que quieres eliminar la categoría "{name}" con {count} elementos?',
'packing.defaultCategory': 'Otros',
'packing.toast.saveError': 'No se pudo guardar',
'packing.toast.deleteError': 'No se pudo eliminar',
+12 -24
View File
@@ -32,32 +32,20 @@ const perm: TranslationStrings = {
'perm.action.collab_edit': 'Colaboración (notas, encuestas, chat)',
'perm.action.share_manage': 'Gestionar enlaces compartidos',
'perm.actionHint.trip_create': 'Quién puede crear nuevos viajes',
'perm.actionHint.trip_edit':
'Quién puede cambiar el nombre, fechas, descripción y moneda del viaje',
'perm.actionHint.trip_delete':
'Quién puede eliminar permanentemente un viaje',
'perm.actionHint.trip_edit': 'Quién puede cambiar el nombre, fechas, descripción y moneda del viaje',
'perm.actionHint.trip_delete': 'Quién puede eliminar permanentemente un viaje',
'perm.actionHint.trip_archive': 'Quién puede archivar o desarchivar un viaje',
'perm.actionHint.trip_cover_upload':
'Quién puede subir o cambiar la imagen de portada',
'perm.actionHint.member_manage':
'Quién puede invitar o eliminar miembros del viaje',
'perm.actionHint.trip_cover_upload': 'Quién puede subir o cambiar la imagen de portada',
'perm.actionHint.member_manage': 'Quién puede invitar o eliminar miembros del viaje',
'perm.actionHint.file_upload': 'Quién puede subir archivos a un viaje',
'perm.actionHint.file_edit':
'Quién puede editar descripciones y enlaces de archivos',
'perm.actionHint.file_delete':
'Quién puede mover archivos a la papelera o eliminarlos permanentemente',
'perm.actionHint.file_edit': 'Quién puede editar descripciones y enlaces de archivos',
'perm.actionHint.file_delete': 'Quién puede mover archivos a la papelera o eliminarlos permanentemente',
'perm.actionHint.place_edit': 'Quién puede añadir, editar o eliminar lugares',
'perm.actionHint.day_edit':
'Quién puede editar días, notas de días y asignaciones de lugares',
'perm.actionHint.reservation_edit':
'Quién puede crear, editar o eliminar reservas',
'perm.actionHint.budget_edit':
'Quién puede crear, editar o eliminar partidas del presupuesto',
'perm.actionHint.packing_edit':
'Quién puede gestionar artículos de equipaje y bolsas',
'perm.actionHint.collab_edit':
'Quién puede crear notas, encuestas y enviar mensajes',
'perm.actionHint.share_manage':
'Quién puede crear o eliminar enlaces compartidos públicos',
'perm.actionHint.day_edit': 'Quién puede editar días, notas de días y asignaciones de lugares',
'perm.actionHint.reservation_edit': 'Quién puede crear, editar o eliminar reservas',
'perm.actionHint.budget_edit': 'Quién puede crear, editar o eliminar partidas del presupuesto',
'perm.actionHint.packing_edit': 'Quién puede gestionar artículos de equipaje y bolsas',
'perm.actionHint.collab_edit': 'Quién puede crear notas, encuestas y enviar mensajes',
'perm.actionHint.share_manage': 'Quién puede crear o eliminar enlaces compartidos públicos',
};
export default perm;
+7 -14
View File
@@ -6,13 +6,10 @@ const places: TranslationStrings = {
'places.sidebarDrop': 'Soltar para importar',
'places.importFileHint':
'Importa archivos .gpx, .kml o .kmz de herramientas como Google My Maps, Google Earth o un rastreador GPS.',
'places.importFileDropHere':
'Haz clic para seleccionar un archivo o arrástralo aquí',
'places.importFileDropHere': 'Haz clic para seleccionar un archivo o arrástralo aquí',
'places.importFileDropActive': 'Suelta el archivo para seleccionarlo',
'places.importFileUnsupported':
'Tipo de archivo no compatible. Usa .gpx, .kml o .kmz.',
'places.importFileTooLarge':
'El archivo es demasiado grande. El tamaño máximo de carga es {maxMb} MB.',
'places.importFileUnsupported': 'Tipo de archivo no compatible. Usa .gpx, .kml o .kmz.',
'places.importFileTooLarge': 'El archivo es demasiado grande. El tamaño máximo de carga es {maxMb} MB.',
'places.importFileError': 'Importación fallida',
'places.importAllSkipped': 'Todos los lugares ya estaban en el viaje.',
'places.gpxImported': '{count} lugares importados desde GPX',
@@ -30,16 +27,13 @@ const places: TranslationStrings = {
'places.kmlKmzImported': '{count} lugares importados desde KMZ/KML',
'places.urlResolved': 'Lugar importado desde URL',
'places.importList': 'Importar lista',
'places.kmlKmzSummaryValues':
'Placemarks: {total} • Importados: {created} • Omitidos: {skipped}',
'places.kmlKmzSummaryValues': 'Placemarks: {total} • Importados: {created} • Omitidos: {skipped}',
'places.importGoogleList': 'Lista Google',
'places.importNaverList': 'Lista Naver',
'places.googleListHint':
'Pega un enlace compartido de una lista de Google Maps para importar todos los lugares.',
'places.googleListHint': 'Pega un enlace compartido de una lista de Google Maps para importar todos los lugares.',
'places.googleListImported': '{count} lugares importados de "{list}"',
'places.googleListError': 'Error al importar la lista de Google Maps',
'places.naverListHint':
'Pega un enlace compartido de una lista de Naver Maps para importar todos los lugares.',
'places.naverListHint': 'Pega un enlace compartido de una lista de Naver Maps para importar todos los lugares.',
'places.naverListImported': '{count} lugares importados de "{list}"',
'places.naverListError': 'Error al importar la lista de Naver Maps',
'places.viewDetails': 'Ver detalles',
@@ -76,8 +70,7 @@ const places: TranslationStrings = {
'places.formNotes': 'Notas',
'places.formNotesPlaceholder': 'Notas personales...',
'places.formReservation': 'Reserva',
'places.reservationNotesPlaceholder':
'Notas de reserva, número de confirmación...',
'places.reservationNotesPlaceholder': 'Notas de reserva, número de confirmación...',
'places.mapsSearchPlaceholder': 'Buscar lugares...',
'places.mapsSearchError': 'La búsqueda de lugares falló.',
'places.loadingDetails': 'Cargando detalles del lugar…',
+1 -2
View File
@@ -48,8 +48,7 @@ const planner: TranslationStrings = {
'planner.route': 'Ruta',
'planner.optimize': 'Optimizar',
'planner.openGoogleMaps': 'Abrir en Google Maps',
'planner.selectDayHint':
'Selecciona un día de la lista izquierda para ver su plan',
'planner.selectDayHint': 'Selecciona un día de la lista izquierda para ver su plan',
'planner.noPlacesForDay': 'Aún no hay lugares para este día',
'planner.addPlacesLink': 'Añadir lugares →',
'planner.minTotal': 'min en total',
+15 -30
View File
@@ -37,8 +37,7 @@ const reservations: TranslationStrings = {
'reservations.type.bicycle': 'Bicicleta',
'reservations.type.taxi': 'Taxi',
'reservations.type.transport_other': 'Otro',
'reservations.confirm.delete':
'¿Seguro que quieres eliminar la reserva "{name}"?',
'reservations.confirm.delete': '¿Seguro que quieres eliminar la reserva "{name}"?',
'reservations.confirm.deleteTitle': '¿Eliminar reserva?',
'reservations.confirm.deleteBody': '« {name} » se eliminará permanentemente.',
'reservations.toast.updated': 'Reserva actualizada',
@@ -72,8 +71,7 @@ const reservations: TranslationStrings = {
'reservations.budgetCategory': 'Categoría de presupuesto',
'reservations.budgetCategoryPlaceholder': 'ej. Transporte, Alojamiento',
'reservations.budgetCategoryAuto': 'Automático (según tipo de reserva)',
'reservations.budgetHint':
'Se creará automáticamente una entrada presupuestaria al guardar.',
'reservations.budgetHint': 'Se creará automáticamente una entrada presupuestaria al guardar.',
'reservations.departureDate': 'Salida',
'reservations.arrivalDate': 'Llegada',
'reservations.departureTime': 'Hora salida',
@@ -94,8 +92,7 @@ const reservations: TranslationStrings = {
'reservations.span.start': 'Inicio',
'reservations.span.end': 'Fin',
'reservations.span.ongoing': 'En curso',
'reservations.validation.endBeforeStart':
'La fecha/hora de fin debe ser posterior a la de inicio',
'reservations.validation.endBeforeStart': 'La fecha/hora de fin debe ser posterior a la de inicio',
'reservations.addBooking': 'Añadir reserva',
'reservations.meta.airline': 'Aerolínea',
'reservations.meta.flightNumber': 'N° de vuelo',
@@ -126,55 +123,43 @@ const reservations: TranslationStrings = {
'reservations.meta.selectDay': 'Seleccionar día',
'reservations.import.title': 'Importar confirmaciones de reserva',
'reservations.import.cta': 'Importar desde archivo',
'reservations.import.dropHere':
'Suelta los archivos de confirmación de reserva aquí o haz clic para seleccionar',
'reservations.import.dropHere': 'Suelta los archivos de confirmación de reserva aquí o haz clic para seleccionar',
'reservations.import.dropActive': 'Suelta los archivos para importar',
'reservations.import.acceptedFormats':
'Aceptados: EML, PDF, PKPass, HTML, TXT (máx. 10 MB por archivo, hasta 5 archivos)',
'reservations.import.parsing': 'Analizando archivos…',
'reservations.import.previewHeading': '{count} reserva(s) encontrada(s)',
'reservations.import.previewEmpty':
'No se pudieron extraer reservas de los archivos subidos.',
'reservations.import.previewEmpty': 'No se pudieron extraer reservas de los archivos subidos.',
'reservations.import.removeItem': 'Eliminar',
'reservations.import.confirm': 'Importar {count} reserva(s)',
'reservations.import.back': 'Atrás',
'reservations.import.success': '{count} reserva(s) importada(s)',
'reservations.import.partialFailure':
'{created} importada(s), {failed} fallida(s)',
'reservations.import.error':
'Error al analizar. Asegúrate de que el archivo sea una confirmación de reserva válida.',
'reservations.import.unavailable':
'La importación de reservas no está disponible en este servidor.',
'reservations.import.unsupportedFormat':
'Formato de archivo no compatible. Usa EML, PDF, PKPass, HTML o TXT.',
'reservations.import.fileTooLarge':
'El archivo «{name}» supera el límite de 10 MB.',
'reservations.import.partialFailure': '{created} importada(s), {failed} fallida(s)',
'reservations.import.error': 'Error al analizar. Asegúrate de que el archivo sea una confirmación de reserva válida.',
'reservations.import.unavailable': 'La importación de reservas no está disponible en este servidor.',
'reservations.import.unsupportedFormat': 'Formato de archivo no compatible. Usa EML, PDF, PKPass, HTML o TXT.',
'reservations.import.fileTooLarge': 'El archivo «{name}» supera el límite de 10 MB.',
'reservations.airtrail.title': 'Importar desde AirTrail',
'reservations.airtrail.cta': 'AirTrail',
'reservations.airtrail.synced': 'AirTrail',
'reservations.airtrail.syncedHint':
'Sincronizado desde AirTrail: las ediciones se mantienen sincronizadas en ambos sentidos.',
'reservations.airtrail.notSynced': 'No sincronizado',
'reservations.airtrail.notSyncedHint':
'Este vuelo se eliminó en AirTrail y ya no se sincroniza.',
'reservations.airtrail.loadError':
'No se pudieron cargar tus vuelos de AirTrail.',
'reservations.airtrail.notSyncedHint': 'Este vuelo se eliminó en AirTrail y ya no se sincroniza.',
'reservations.airtrail.loadError': 'No se pudieron cargar tus vuelos de AirTrail.',
'reservations.airtrail.imported': '{count} vuelo(s) importado(s)',
'reservations.airtrail.skippedDuplicate':
'{count} ya en este viaje, omitido(s)',
'reservations.airtrail.skippedDuplicate': '{count} ya en este viaje, omitido(s)',
'reservations.airtrail.nothingImported': 'No hay nada que importar.',
'reservations.airtrail.importError': 'Error al importar. Inténtalo de nuevo.',
'reservations.airtrail.undo': 'Importar desde AirTrail',
'reservations.airtrail.alreadyImported': 'Importado',
'reservations.airtrail.duringTrip': 'Durante este viaje',
'reservations.airtrail.otherFlights': 'Otros vuelos',
'reservations.airtrail.empty':
'No se encontraron vuelos en tu cuenta de AirTrail.',
'reservations.airtrail.empty': 'No se encontraron vuelos en tu cuenta de AirTrail.',
'reservations.airtrail.importCta': 'Importar {count}',
'reservations.costsLabel': 'Costs',
'reservations.createExpense': 'Create expense',
'reservations.createExpenseHint':
'Saves the booking, then opens the Costs editor.',
'reservations.createExpenseHint': 'Saves the booking, then opens the Costs editor.',
'reservations.linkedExpense': 'Linked expense',
'reservations.removeExpense': 'Remove expense',
};
+30 -49
View File
@@ -14,12 +14,10 @@ const settings: TranslationStrings = {
'settings.mapTemplate': 'Plantilla del mapa',
'settings.mapTemplatePlaceholder.select': 'Seleccionar plantilla...',
'settings.mapDefaultHint': 'Déjalo vacío para OpenStreetMap (por defecto)',
'settings.mapTemplatePlaceholder':
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
'settings.mapTemplatePlaceholder': 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
'settings.mapHint': 'Plantilla de URL para los mosaicos del mapa',
'settings.mapProvider': 'Proveedor de mapa',
'settings.mapProviderHint':
'Afecta a los mapas de Trip Planner y Journey. Atlas siempre usa Leaflet.',
'settings.mapProviderHint': 'Afecta a los mapas de Trip Planner y Journey. Atlas siempre usa Leaflet.',
'settings.mapLeafletSubtitle': 'Clásico 2D, cualquier mosaico raster',
'settings.mapMapboxSubtitle': 'Mosaicos vectoriales, edificios 3D y terreno',
'settings.mapExperimental': 'Experimental',
@@ -35,8 +33,7 @@ const settings: TranslationStrings = {
'settings.mapHighQuality': 'Modo de alta calidad',
'settings.mapHighQualityHint':
'Antialiasing + proyección global para bordes más nítidos y una vista realista del mundo.',
'settings.mapHighQualityWarning':
'Puede afectar el rendimiento en dispositivos menos potentes.',
'settings.mapHighQualityWarning': 'Puede afectar el rendimiento en dispositivos menos potentes.',
'settings.mapTipLabel': 'Consejo:',
'settings.mapTip':
'Clic derecho y arrastrar para rotar/inclinar el mapa. Clic central para añadir un lugar (el clic derecho está reservado para la rotación).',
@@ -45,11 +42,9 @@ const settings: TranslationStrings = {
'settings.saveMap': 'Guardar mapa',
'settings.apiKeys': 'Claves API',
'settings.mapsKey': 'Clave API de Google Maps',
'settings.mapsKeyHint':
'Necesaria para buscar lugares. Consíguela en console.cloud.google.com',
'settings.mapsKeyHint': 'Necesaria para buscar lugares. Consíguela en console.cloud.google.com',
'settings.weatherKey': 'Clave API de OpenWeatherMap',
'settings.weatherKeyHint':
'Para datos meteorológicos. Gratis en openweathermap.org/api',
'settings.weatherKeyHint': 'Para datos meteorológicos. Gratis en openweathermap.org/api',
'settings.keyPlaceholder': 'Introduce la clave...',
'settings.configured': 'Configurado',
'settings.saveKeys': 'Guardar claves',
@@ -78,8 +73,7 @@ const settings: TranslationStrings = {
'settings.notificationsDisabled':
'Las notificaciones no están configuradas. Pida a un administrador que active las notificaciones por correo o webhook.',
'settings.notificationsActive': 'Canal activo',
'settings.notificationsManagedByAdmin':
'Los eventos de notificación son configurados por el administrador.',
'settings.notificationsManagedByAdmin': 'Los eventos de notificación son configurados por el administrador.',
'settings.on': 'Activado',
'settings.off': 'Desactivado',
'settings.mcp.title': 'Configuración MCP',
@@ -93,8 +87,7 @@ const settings: TranslationStrings = {
'settings.mcp.copied': '¡Copiado!',
'settings.mcp.apiTokens': 'Tokens de API',
'settings.mcp.createToken': 'Crear nuevo token',
'settings.mcp.noTokens':
'Sin tokens aún. Crea uno para conectar clientes MCP.',
'settings.mcp.noTokens': 'Sin tokens aún. Crea uno para conectar clientes MCP.',
'settings.mcp.tokenCreatedAt': 'Creado',
'settings.mcp.tokenUsedAt': 'Usado',
'settings.mcp.deleteTokenTitle': 'Eliminar token',
@@ -102,8 +95,7 @@ const settings: TranslationStrings = {
'Este token dejará de funcionar de inmediato. Cualquier cliente MCP que lo use perderá el acceso.',
'settings.mcp.modal.createTitle': 'Crear token de API',
'settings.mcp.modal.tokenName': 'Nombre del token',
'settings.mcp.modal.tokenNamePlaceholder':
'p. ej. Claude Desktop, Portátil de trabajo',
'settings.mcp.modal.tokenNamePlaceholder': 'p. ej. Claude Desktop, Portátil de trabajo',
'settings.mcp.modal.creating': 'Creando…',
'settings.mcp.modal.create': 'Crear token',
'settings.mcp.modal.createdTitle': 'Token creado',
@@ -139,15 +131,13 @@ const settings: TranslationStrings = {
'settings.oauth.sessionExpires': 'Expira',
'settings.oauth.revoke': 'Revocar',
'settings.oauth.revokeSession': 'Revocar sesión',
'settings.oauth.revokeSessionMessage':
'Esto revocará inmediatamente el acceso de esta sesión OAuth.',
'settings.oauth.revokeSessionMessage': 'Esto revocará inmediatamente el acceso de esta sesión OAuth.',
'settings.oauth.modal.createTitle': 'Registrar cliente OAuth',
'settings.oauth.modal.presets': 'Ajustes rápidos',
'settings.oauth.modal.clientName': 'Nombre de la aplicación',
'settings.oauth.modal.clientNamePlaceholder': 'ej. Claude Web, Mi app MCP',
'settings.oauth.modal.redirectUris': 'URIs de redirección',
'settings.oauth.modal.redirectUrisPlaceholder':
'https://your-app.com/callback\nhttps://your-app.com/auth',
'settings.oauth.modal.redirectUrisPlaceholder': 'https://your-app.com/callback\nhttps://your-app.com/auth',
'settings.oauth.modal.redirectUrisHint':
'Un URI por línea. HTTPS obligatorio (localhost exento). Coincidencia exacta.',
'settings.oauth.modal.scopes': 'Ámbitos permitidos',
@@ -166,8 +156,7 @@ const settings: TranslationStrings = {
'settings.oauth.toast.revoked': 'Sesión revocada',
'settings.oauth.toast.revokeError': 'Error al revocar la sesión',
'settings.oauth.toast.rotateError': 'Error al renovar el secreto del cliente',
'settings.oauth.modal.machineClient':
'Cliente de máquina (sin inicio de sesión en el navegador)',
'settings.oauth.modal.machineClient': 'Cliente de máquina (sin inicio de sesión en el navegador)',
'settings.oauth.modal.machineClientHint':
'Usa el grant client_credentials — sin URIs de redirección. El token se emite directamente vía client_id + client_secret y actúa como tú dentro de los alcances seleccionados.',
'settings.oauth.modal.machineClientUsage':
@@ -188,15 +177,13 @@ const settings: TranslationStrings = {
'settings.about.supporters.tierEmpty': 'Sé el primero',
'settings.about.supporter.tier.noReturnTicket': 'No Return Ticket',
'settings.about.supporter.tier.lostLuggageVip': 'Lost Luggage VIP',
'settings.about.supporter.tier.businessClassDreamer':
'Business Class Dreamer',
'settings.about.supporter.tier.businessClassDreamer': 'Business Class Dreamer',
'settings.about.supporter.tier.budgetTraveller': 'Budget Traveller',
'settings.about.supporter.tier.hostelBunkmate': 'Hostel Bunkmate',
'settings.about.description':
'TREK es un planificador de viajes autoalojado que te ayuda a organizar tus viajes desde la primera idea hasta el último recuerdo. Planificación diaria, presupuesto, listas de equipaje, fotos y mucho más — todo en un solo lugar, en tu propio servidor.',
'settings.about.madeWith': 'Hecho con',
'settings.about.madeBy':
'por Maurice y una creciente comunidad de código abierto.',
'settings.about.madeBy': 'por Maurice y una creciente comunidad de código abierto.',
'settings.username': 'Usuario',
'settings.email': 'Correo',
'settings.role': 'Rol',
@@ -229,10 +216,8 @@ const settings: TranslationStrings = {
'settings.mfa.requiredByPolicy':
'Tu administrador exige autenticación en dos factores. Configura una app de autenticación abajo antes de continuar.',
'settings.mfa.backupTitle': 'Códigos de respaldo',
'settings.mfa.backupDescription':
'Usa estos códigos de un solo uso si pierdes acceso a tu app autenticadora.',
'settings.mfa.backupWarning':
'Guárdalos ahora. Cada código solo se puede usar una vez.',
'settings.mfa.backupDescription': 'Usa estos códigos de un solo uso si pierdes acceso a tu app autenticadora.',
'settings.mfa.backupWarning': 'Guárdalos ahora. Cada código solo se puede usar una vez.',
'settings.mfa.backupCopy': 'Copiar códigos',
'settings.mfa.backupDownload': 'Descargar TXT',
'settings.mfa.backupPrint': 'Imprimir / PDF',
@@ -240,15 +225,13 @@ const settings: TranslationStrings = {
'settings.mfa.enabled': '2FA está activado en tu cuenta.',
'settings.mfa.disabled': '2FA no está activado.',
'settings.mfa.setup': 'Configurar autenticador',
'settings.mfa.scanQr':
'Escanea este código QR con tu app o introduce la clave manualmente.',
'settings.mfa.scanQr': 'Escanea este código QR con tu app o introduce la clave manualmente.',
'settings.mfa.secretLabel': 'Clave secreta (entrada manual)',
'settings.mfa.codePlaceholder': 'Código de 6 dígitos',
'settings.mfa.enable': 'Activar 2FA',
'settings.mfa.cancelSetup': 'Cancelar',
'settings.mfa.disableTitle': 'Desactivar 2FA',
'settings.mfa.disableHint':
'Introduce tu contraseña y un código actual de tu autenticador.',
'settings.mfa.disableHint': 'Introduce tu contraseña y un código actual de tu autenticador.',
'settings.mfa.disable': 'Desactivar 2FA',
'settings.mfa.toastEnabled': 'Autenticación de dos factores activada',
'settings.mfa.toastDisabled': 'Autenticación de dos factores desactivada',
@@ -266,8 +249,7 @@ const settings: TranslationStrings = {
'settings.bookingLabelsHint':
'Muestra nombres de estaciones / aeropuertos en el mapa. Desactivado, solo se muestra el icono.',
'settings.currentPasswordRequired': 'La contraseña actual es obligatoria',
'settings.passwordWeak':
'La contraseña debe contener mayúsculas, minúsculas, números y un carácter especial',
'settings.passwordWeak': 'La contraseña debe contener mayúsculas, minúsculas, números y un carácter especial',
'settings.notifyVersionAvailable': 'Nueva versión disponible',
'settings.notificationPreferences.noChannels':
'No hay canales de notificación configurados. Pide a un administrador que configure notificaciones por correo o webhook.',
@@ -286,20 +268,18 @@ const settings: TranslationStrings = {
'settings.ntfyUrl.hint':
'Introduce tu tema de Ntfy para recibir notificaciones push. Deja el servidor en blanco para usar el predeterminado configurado por tu administrador.',
'settings.ntfyUrl.tokenLabel': 'Token de acceso (opcional)',
'settings.ntfyUrl.tokenHint':
'Requerido para temas protegidos con contraseña.',
'settings.ntfyUrl.tokenHint': 'Requerido para temas protegidos con contraseña.',
'settings.ntfyUrl.saved': 'Configuración de Ntfy guardada',
'settings.ntfyUrl.test': 'Probar',
'settings.ntfyUrl.testSuccess':
'Notificación de prueba de Ntfy enviada correctamente',
'settings.ntfyUrl.testSuccess': 'Notificación de prueba de Ntfy enviada correctamente',
'settings.ntfyUrl.testFailed': 'Error en la notificación de prueba de Ntfy',
'settings.ntfyUrl.tokenCleared': 'Token de acceso eliminado',
'settings.notificationPreferences.inapp': 'In-App',
'settings.notificationPreferences.webhook': 'Webhook',
'settings.notificationPreferences.email': 'Email',
'settings.notificationPreferences.ntfy': 'Ntfy',
"settings.currency": "Currency",
"settings.currencyHint": "All amounts in Costs are converted to and shown in this currency.",
'settings.currency': 'Currency',
'settings.currencyHint': 'All amounts in Costs are converted to and shown in this currency.',
'settings.passkey.title': 'Passkeys',
'settings.passkey.description':
'Inicia sesión más rápido y con protección frente al phishing usando una passkey: tu huella, tu cara, tu PIN o una llave de seguridad física. Tu contraseña sigue disponible como respaldo.',
@@ -307,8 +287,7 @@ const settings: TranslationStrings = {
'Las passkeys están habilitadas, pero aún no están del todo configuradas en este servidor. Pide a tu administrador que defina el dominio de WebAuthn.',
'settings.passkey.add': 'Añadir una passkey',
'settings.passkey.addTitle': 'Añadir una passkey',
'settings.passkey.passwordPrompt':
'Confirma tu contraseña actual y luego sigue las indicaciones de tu dispositivo.',
'settings.passkey.passwordPrompt': 'Confirma tu contraseña actual y luego sigue las indicaciones de tu dispositivo.',
'settings.passkey.passwordRequired': 'Se requiere tu contraseña actual.',
'settings.passkey.namePlaceholder': 'Nombre (opcional, p. ej. "iPhone")',
'settings.passkey.addedToast': 'Passkey añadida',
@@ -316,8 +295,7 @@ const settings: TranslationStrings = {
'settings.passkey.addError': 'No se pudo añadir la passkey',
'settings.passkey.cancelled': 'Configuración de la passkey cancelada',
'settings.passkey.deleted': 'Passkey eliminada',
'settings.passkey.deleteConfirm':
'¿Eliminar esta passkey? Confírmalo con tu contraseña.',
'settings.passkey.deleteConfirm': '¿Eliminar esta passkey? Confírmalo con tu contraseña.',
'settings.passkey.rename': 'Renombrar',
'settings.passkey.defaultName': 'Passkey',
'settings.passkey.synced': 'Sincronizada',
@@ -325,9 +303,11 @@ const settings: TranslationStrings = {
'settings.passkey.lastUsed': 'Último uso',
'settings.passkey.neverUsed': 'Nunca usada',
'settings.mapPoiPill': 'Explorar lugares en el mapa',
'settings.mapPoiPillHint': 'Muestra una píldora de categorías en el mapa del viaje para encontrar restaurantes, alojamientos y más cerca, desde OpenStreetMap.',
'settings.mapPoiPillHint':
'Muestra una píldora de categorías en el mapa del viaje para encontrar restaurantes, alojamientos y más cerca, desde OpenStreetMap.',
'settings.airtrail.title': 'AirTrail',
'settings.airtrail.hint': 'Conecta tu AirTrail autoalojado para importar y sincronizar vuelos. Crea una clave de API en AirTrail en Ajustes → Seguridad.',
'settings.airtrail.hint':
'Conecta tu AirTrail autoalojado para importar y sincronizar vuelos. Crea una clave de API en AirTrail en Ajustes → Seguridad.',
'settings.airtrail.url': 'URL de la instancia',
'settings.airtrail.apiKey': 'Clave de API',
'settings.airtrail.apiKeyPlaceholder': 'Clave de API Bearer',
@@ -335,7 +315,8 @@ const settings: TranslationStrings = {
'settings.airtrail.allowInsecureTls': 'Permitir certificados autofirmados',
'settings.airtrail.allowInsecureTlsHint': 'Actívalo solo para una instancia de confianza en tu propia red.',
'settings.airtrail.writeBack': 'Escribir cambios de vuelta en AirTrail',
'settings.airtrail.writeBackHint': 'Desactivado por defecto: AirTrail es la fuente de referencia y TREK solo lee de él. Actívalo para enviar a AirTrail los cambios hechos en TREK.',
'settings.airtrail.writeBackHint':
'Desactivado por defecto: AirTrail es la fuente de referencia y TREK solo lee de él. Actívalo para enviar a AirTrail los cambios hechos en TREK.',
'settings.airtrail.connected': 'Conectado',
'settings.airtrail.notConnected': 'No conectado',
'settings.airtrail.toast.saved': 'Conexión con AirTrail guardada',
+14 -28
View File
@@ -5,14 +5,10 @@ const system_notice: TranslationStrings = {
'system_notice.welcome_v1.body':
'Tu planificador de viajes todo en uno. Crea itinerarios, comparte viajes con amigos y mantente organizado, online o sin conexión.',
'system_notice.welcome_v1.cta_label': 'Planificar un viaje',
'system_notice.welcome_v1.hero_alt':
'Destino de viaje pintoresco con la interfaz de TREK',
'system_notice.welcome_v1.highlight_plan':
'Itinerarios día a día para cualquier viaje',
'system_notice.welcome_v1.highlight_share':
'Colabora con tus compañeros de viaje',
'system_notice.welcome_v1.highlight_offline':
'Funciona sin conexión en móvil',
'system_notice.welcome_v1.hero_alt': 'Destino de viaje pintoresco con la interfaz de TREK',
'system_notice.welcome_v1.highlight_plan': 'Itinerarios día a día para cualquier viaje',
'system_notice.welcome_v1.highlight_share': 'Colabora con tus compañeros de viaje',
'system_notice.welcome_v1.highlight_offline': 'Funciona sin conexión en móvil',
'system_notice.dev_test_modal.title': '[Dev] Test notice',
'system_notice.dev_test_modal.body': 'This is a dev-only test notice.',
'system_notice.pager.prev': 'Aviso anterior',
@@ -28,36 +24,26 @@ const system_notice: TranslationStrings = {
'Documenta tus viajes como historias enriquecidas con cronologías, galerías de fotos y mapas interactivos.',
'system_notice.v3_journey.cta_label': 'Abrir Journey',
'system_notice.v3_journey.highlight_timeline': 'Cronología y galería por día',
'system_notice.v3_journey.highlight_photos':
'Importar desde Immich o Synology',
'system_notice.v3_journey.highlight_share':
'Compartir públicamente — sin inicio de sesión',
'system_notice.v3_journey.highlight_export':
'Exportar como libro de fotos PDF',
'system_notice.v3_journey.highlight_photos': 'Importar desde Immich o Synology',
'system_notice.v3_journey.highlight_share': 'Compartir públicamente — sin inicio de sesión',
'system_notice.v3_journey.highlight_export': 'Exportar como libro de fotos PDF',
'system_notice.v3_features.title': 'Más novedades en 3.0',
'system_notice.v3_features.body':
'Otras cosas que vale la pena conocer de esta versión.',
'system_notice.v3_features.highlight_dashboard':
'Rediseño del panel mobile-first',
'system_notice.v3_features.highlight_offline':
'Modo sin conexión completo como PWA',
'system_notice.v3_features.highlight_search':
'Autocompletado de lugares en tiempo real',
'system_notice.v3_features.highlight_import':
'Importar lugares desde archivos KMZ/KML',
'system_notice.v3_features.body': 'Otras cosas que vale la pena conocer de esta versión.',
'system_notice.v3_features.highlight_dashboard': 'Rediseño del panel mobile-first',
'system_notice.v3_features.highlight_offline': 'Modo sin conexión completo como PWA',
'system_notice.v3_features.highlight_search': 'Autocompletado de lugares en tiempo real',
'system_notice.v3_features.highlight_import': 'Importar lugares desde archivos KMZ/KML',
'system_notice.v3_mcp.title': 'MCP: actualización OAuth 2.1',
'system_notice.v3_mcp.body':
'La integración MCP ha sido completamente renovada. OAuth 2.1 es ahora el método de autenticación recomendado. Los tokens estáticos (trek_…) están obsoletos y se eliminarán en una versión futura.',
'system_notice.v3_mcp.highlight_oauth': 'OAuth 2.1 recomendado (mcp-remote)',
'system_notice.v3_mcp.highlight_scopes': '24 ámbitos de permisos granulares',
'system_notice.v3_mcp.highlight_deprecated':
'Tokens estáticos trek_ obsoletos',
'system_notice.v3_mcp.highlight_deprecated': 'Tokens estáticos trek_ obsoletos',
'system_notice.v3_mcp.highlight_tools': 'Herramientas y prompts ampliados',
'system_notice.v3_thankyou.title': 'Una nota personal de mi parte',
'system_notice.v3_thankyou.body':
'Antes de seguir — quiero tomarme un momento.\n\nTREK empezó como un proyecto personal que construí para mis propios viajes. Nunca imaginé que crecería hasta convertirse en algo en lo que 4.000 de vosotros confían para planificar sus aventuras. Cada estrella, cada issue, cada solicitud de funcionalidad — los leo todos, y son lo que me mantiene en pie durante las noches largas entre un trabajo a jornada completa y la universidad.\n\nQuiero que sepáis: TREK siempre será open source, siempre self-hosted, siempre vuestro. Sin rastreo, sin suscripciones, sin letra pequeña. Solo una herramienta hecha por alguien que ama viajar tanto como vosotros.\n\nUn agradecimiento especial a [jubnl](https://github.com/jubnl) — te has convertido en un colaborador increíble. Mucho de lo que hace grande la versión 3.0 lleva tu huella. Gracias por creer en este proyecto cuando todavía era un borrador.\n\nY a cada uno de vosotros que reportó un bug, tradujo un texto, compartió TREK con un amigo o simplemente lo usó para planificar un viaje — **gracias**. Vosotros sois la razón de que esto exista.\n\nPor muchas más aventuras juntos.\n\n— Maurice\n\n---\n\n[Únete a la comunidad en Discord](https://discord.gg/7Q6M6jDwzf)\n\nSi TREK mejora tus viajes, un [pequeño café](https://ko-fi.com/mauriceboe) siempre mantiene las luces encendidas.',
'system_notice.v3014_whitespace_collision.title':
'Acción requerida: conflicto de cuenta de usuario',
'system_notice.v3014_whitespace_collision.title': 'Acción requerida: conflicto de cuenta de usuario',
'system_notice.v3014_whitespace_collision.body':
'La actualización 3.0.14 detectó uno o más conflictos de nombre de usuario o correo electrónico causados por espacios en blanco al inicio o al final de los valores almacenados. Las cuentas afectadas se renombraron automáticamente. Revisa los registros del servidor en busca de líneas que empiecen por **[migration] WHITESPACE COLLISION** para identificar qué cuentas necesitan revisión.',
};
+1 -1
View File
@@ -9,7 +9,7 @@ const trip: TranslationStrings = {
'trip.tabs.packingShort': 'Equipaje',
'trip.tabs.lists': 'Listas',
'trip.tabs.listsShort': 'Listas',
'trip.tabs.budget': "Costs",
'trip.tabs.budget': 'Costs',
'trip.tabs.files': 'Archivos',
'trip.loading': 'Cargando viaje...',
'trip.loadingPhotos': 'Cargando fotos de los lugares...',
+12 -24
View File
@@ -8,8 +8,7 @@ const vacay: TranslationStrings = {
'vacay.addPrevYear': 'Añadir año anterior',
'vacay.removeYear': 'Eliminar año',
'vacay.removeYearConfirm': '¿Eliminar {year}?',
'vacay.removeYearHint':
'Todas las vacaciones y festivos de empresa de este año se borrarán permanentemente.',
'vacay.removeYearHint': 'Todas las vacaciones y festivos de empresa de este año se borrarán permanentemente.',
'vacay.remove': 'Eliminar',
'vacay.persons': 'Personas',
'vacay.noPersons': 'No se han añadido personas',
@@ -17,8 +16,7 @@ const vacay: TranslationStrings = {
'vacay.editPerson': 'Editar persona',
'vacay.removePerson': 'Eliminar persona',
'vacay.removePersonConfirm': '¿Eliminar a {name}?',
'vacay.removePersonHint':
'Todas las vacaciones de esta persona se borrarán permanentemente.',
'vacay.removePersonHint': 'Todas las vacaciones de esta persona se borrarán permanentemente.',
'vacay.personName': 'Nombre',
'vacay.personNamePlaceholder': 'Introduce un nombre',
'vacay.color': 'Color',
@@ -49,25 +47,20 @@ const vacay: TranslationStrings = {
'vacay.selectCountry': 'Seleccionar país',
'vacay.selectRegion': 'Seleccionar región (opcional)',
'vacay.companyHolidays': 'Festivos de empresa',
'vacay.companyHolidaysHint':
'Permitir marcar días festivos comunes de la empresa',
'vacay.companyHolidaysNoDeduct':
'Los festivos de empresa no descuentan días de vacaciones.',
'vacay.companyHolidaysHint': 'Permitir marcar días festivos comunes de la empresa',
'vacay.companyHolidaysNoDeduct': 'Los festivos de empresa no descuentan días de vacaciones.',
'vacay.weekStart': 'La semana comienza el',
'vacay.weekStartHint': 'Elige si la semana comienza el lunes o el domingo',
'vacay.carryOver': 'Arrastrar saldo',
'vacay.carryOverHint':
'Trasladar automáticamente los días restantes al año siguiente',
'vacay.carryOverHint': 'Trasladar automáticamente los días restantes al año siguiente',
'vacay.sharing': 'Compartir',
'vacay.sharingHint':
'Comparte tu calendario de vacaciones con otros usuarios de TREK',
'vacay.sharingHint': 'Comparte tu calendario de vacaciones con otros usuarios de TREK',
'vacay.owner': 'Propietario',
'vacay.shareEmailPlaceholder': 'Correo electrónico del usuario de TREK',
'vacay.shareSuccess': 'Plan compartido correctamente',
'vacay.shareError': 'No se pudo compartir el plan',
'vacay.dissolve': 'Deshacer fusión',
'vacay.dissolveHint':
'Separar de nuevo los calendarios. Tus entradas se conservarán.',
'vacay.dissolveHint': 'Separar de nuevo los calendarios. Tus entradas se conservarán.',
'vacay.dissolveAction': 'Disolver',
'vacay.dissolved': 'Calendario separado',
'vacay.fusedWith': 'Fusionado con',
@@ -75,8 +68,7 @@ const vacay: TranslationStrings = {
'vacay.noData': 'Sin datos',
'vacay.changeColor': 'Cambiar color',
'vacay.inviteUser': 'Invitar usuario',
'vacay.inviteHint':
'Invita a otro usuario de TREK a compartir un calendario combinado de vacaciones.',
'vacay.inviteHint': 'Invita a otro usuario de TREK a compartir un calendario combinado de vacaciones.',
'vacay.selectUser': 'Seleccionar usuario',
'vacay.sendInvite': 'Enviar invitación',
'vacay.inviteSent': 'Invitación enviada',
@@ -87,15 +79,11 @@ const vacay: TranslationStrings = {
'vacay.decline': 'Rechazar',
'vacay.acceptFusion': 'Aceptar y fusionar',
'vacay.inviteTitle': 'Solicitud de fusión',
'vacay.inviteWantsToFuse':
'quiere compartir un calendario de vacaciones contigo.',
'vacay.fuseInfo1':
'Ambos veréis todas las entradas de vacaciones en un único calendario compartido.',
'vacay.inviteWantsToFuse': 'quiere compartir un calendario de vacaciones contigo.',
'vacay.fuseInfo1': 'Ambos veréis todas las entradas de vacaciones en un único calendario compartido.',
'vacay.fuseInfo2': 'Ambas partes pueden crear y editar entradas mutuamente.',
'vacay.fuseInfo3':
'Ambas partes pueden borrar entradas y cambiar el número de días de vacaciones disponibles.',
'vacay.fuseInfo4':
'Ajustes como festivos y festivos de empresa se comparten.',
'vacay.fuseInfo3': 'Ambas partes pueden borrar entradas y cambiar el número de días de vacaciones disponibles.',
'vacay.fuseInfo4': 'Ajustes como festivos y festivos de empresa se comparten.',
'vacay.fuseInfo5':
'La fusión puede disolverse en cualquier momento por cualquiera de las partes. Tus entradas se conservarán.',
'vacay.addCalendar': 'Añadir calendario',