mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
b401da2264
CARTO started stamping "API KEY REQUIRED" across every keyless basemap tile on 26.08.2026. #2060 added a key field as the immediate answer, but it leaves a self-hosted instance needing an email exchange with CARTO before its maps look right, and every default in the client still pointed at CARTO. Default to OpenFreeMap Positron instead: no key, no account, no request limit, commercial use allowed, attribution required. OpenFreeMap serves vector tiles only, so the Leaflet basemap is a MapLibre style document rather than an XYZ template. maplibre-gl-leaflet hangs a GL canvas into Leaflet's own tile pane, which leaves everything above it alone - markers, GeoJSON, clusters, plugin layers, the custom panes, and the click handling, since Leaflet's CSS already puts pointer-events:none on that layer. maplibre-gl still arrives only through a dynamic import, so no chunk that draws a map grows by a megabyte. Switched: the trip planner, the MapView fallback every preview goes through, the journey map, collections, the atlas, the shared trip page and the offline tile prefetch. OpenFreeMap Positron and Bright join the tile presets in settings, the admin defaults and both mobile screens. A CARTO template that is already saved keeps working when a key backs it - that stays a supported choice. Without a key it is not drawn at all: resolveTileUrl falls back to the default rather than to a watermark, so an instance that upgrades with one in its settings sees the new basemap immediately and needs no migration. The stored value is left as it is, so the Map settings tab still shows what was chosen and the warning underneath it explains why - one sentence appended, in all 23 locales. OpenFreeMap asks for a credit of its own; OpenStreetMap alone under its tiles is wrong and a licence problem. attributionForTile() derives it from the URL rather than from a flag at each call site, and the shared trip map, which carried no attribution at all, now gets one. Offline maps keep working and get cheaper. A vector style is four things instead of one, so sync/glPrefetcher.ts walks the style document, its sprite, the Latin glyph ranges of each font stack it uses, the TileJSON - the planet path is versioned, so guessing it answers 200 with an empty body - and then the .pbf tiles. Over the Berlin bounding box TREK computes, raster z10-16 is 2237 requests and 34.6 MB and gives up above z16; vector z10-14 is 177 requests and 32.1 MB and stays sharp above that, because MapLibre scales the z14 tile rather than asking for another. The Workbox rule for tiles.openfreemap.org moves to CacheFirst and shares the prefetcher's cache, so browsing tops a downloaded region up instead of filling a second copy beside it - a versioned tile path can never be stale. Clearing offline maps clears it too. The atlas loses its second raster layer. It existed to warm the HTTP cache of neighbouring zoom levels, which a vector basemap does not need; a second one would only cost a second WebGL context. OpenFreeMap has no label-free style, so its labels are switched off on the live map instead - they are all symbol layers, while borders and coastlines are line and fill - re-armed on style.load so a theme switch keeps them off. Theme changes call setStyle in place rather than rebuilding the layer: a swap per toggle would leak a WebGL context, and browsers cap those in the low teens.
563 lines
36 KiB
TypeScript
563 lines
36 KiB
TypeScript
import type { TranslationStrings } from '../types';
|
|
|
|
const settings: TranslationStrings = {
|
|
'settings.title': 'Ajustes',
|
|
'settings.subtitle': 'Configura tus ajustes personales',
|
|
'settings.tabs.display': 'Pantalla',
|
|
'settings.tabs.map': 'Mapa',
|
|
'settings.tabs.notifications': 'Notificaciones',
|
|
'settings.tabs.integrations': 'Integraciones',
|
|
'settings.plugins.oauth.connected': 'Conectado',
|
|
'settings.plugins.oauth.notConnected': 'No conectado',
|
|
'settings.plugins.oauth.connect': 'Conectar',
|
|
'settings.plugins.oauth.disconnect': 'Desconectar',
|
|
'settings.tabs.plugins': 'Complementos',
|
|
'settings.plugins.title': 'Ajustes de complementos',
|
|
'settings.plugins.subtitle': 'Tus ajustes personales para los complementos que usas (claves de API, preferencias).',
|
|
'settings.plugins.empty': 'No hay complementos activos.',
|
|
'settings.plugins.saved': 'Ajustes guardados',
|
|
'settings.tabs.account': 'Cuenta',
|
|
'settings.tabs.offline': 'Offline',
|
|
'settings.tabs.about': 'Acerca de',
|
|
'settings.map': 'Mapa',
|
|
'settings.mapTemplate': 'Plantilla del mapa',
|
|
'settings.mapTemplatePlaceholder.select': 'Seleccionar plantilla...',
|
|
'settings.mapDefaultHint': 'Déjalo vacío para OpenStreetMap (por defecto)',
|
|
'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.mapLeafletSubtitle': 'Clásico 2D, cualquier mosaico raster',
|
|
'settings.mapMapboxSubtitle': 'Mosaicos vectoriales, edificios 3D y terreno',
|
|
'settings.mapMapLibreSubtitle': 'Mosaicos vectoriales de OpenFreeMap, sin token',
|
|
'settings.mapExperimental': 'Experimental',
|
|
'settings.mapMapboxToken': 'Token de acceso de Mapbox',
|
|
'settings.mapMapboxTokenHint': 'Token público (pk.*) de',
|
|
'settings.mapMapboxTokenLink': 'mapbox.com → Tokens de acceso',
|
|
'settings.mapCartoKey': 'Clave de API de CARTO',
|
|
'settings.mapCartoKeyHint': 'Los mapas base de CARTO muestran una marca de agua sin clave. Gratuita y sin cuenta, en',
|
|
'settings.mapCartoKeyLink': 'clave de API de mapas base de carto.com',
|
|
'settings.mapCartoKeyMissing':
|
|
'Esta plantilla es un mapa base de CARTO. Sin clave, CARTO estampa "API KEY REQUIRED" en cada tesela. Hasta que introduzcas una, TREK muestra el mapa base predeterminado.',
|
|
'settings.mapStyle': 'Estilo de mapa',
|
|
'settings.mapStylePlaceholder': 'Seleccionar un estilo de Mapbox',
|
|
'settings.mapStyleHint': 'Preset o tu propia URL mapbox://styles/USER/ID',
|
|
'settings.mapOpenFreeMapStylePlaceholder': 'Seleccionar un estilo de OpenFreeMap',
|
|
'settings.mapOpenFreeMapStyleHint':
|
|
'Preset o URL de estilo de OpenFreeMap. Los estilos de OpenFreeMap funcionan sin token.',
|
|
'settings.map3dBuildings': 'Edificios 3D y terreno',
|
|
'settings.map3dHint':
|
|
'Inclinación + extrusiones 3D reales de edificios — funciona con todos los estilos, incluyendo satélite.',
|
|
'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.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).',
|
|
'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.weatherKey': 'Clave API de OpenWeatherMap',
|
|
'settings.weatherKeyHint': 'Para datos meteorológicos. Gratis en openweathermap.org/api',
|
|
'settings.keyPlaceholder': 'Introduce la clave...',
|
|
'settings.configured': 'Configurado',
|
|
'settings.saveKeys': 'Guardar claves',
|
|
'settings.display': 'Visualización',
|
|
'settings.colorMode': 'Modo de color',
|
|
'settings.light': 'Claro',
|
|
'settings.dark': 'Oscuro',
|
|
'settings.auto': 'Automático',
|
|
'settings.language': 'Idioma',
|
|
'settings.temperature': 'Unidad de temperatura',
|
|
'settings.distance': 'Unidad de distancia',
|
|
'settings.timeFormat': 'Formato de hora',
|
|
'settings.blurBookingCodes': 'Difuminar códigos de reserva',
|
|
'settings.aiAlwaysRetry': 'Always retry booking imports with AI',
|
|
'settings.aiAlwaysRetryHint': 'When a file cannot be read by the standard parser, automatically retry it with AI.',
|
|
'settings.optimizeFromAccommodation': 'Optimizar la ruta desde el alojamiento',
|
|
'settings.optimizeFromAccommodationHint':
|
|
'Al optimizar un día, comienza la ruta en el hotel donde despiertas y termínala en aquel en el que te registras esa noche.',
|
|
'settings.notifications': 'Notificaciones',
|
|
'settings.notifyTripInvite': 'Invitaciones de viaje',
|
|
'settings.notifyBookingChange': 'Cambios en reservas',
|
|
'settings.notifyTripReminder': 'Recordatorios de viaje',
|
|
'settings.notifyTodoDue': 'Tarea próxima',
|
|
'settings.notifyVacayInvite': 'Invitaciones de fusión Vacay',
|
|
'settings.notifyVacayShare': 'Calendarios Vacay compartidos',
|
|
'settings.notifyPhotosShared': 'Fotos compartidas (Immich)',
|
|
'settings.notifyCollabMessage': 'Mensajes de chat (Collab)',
|
|
'settings.notifyPackingTagged': 'Lista de equipaje: asignaciones',
|
|
'settings.notifyWebhook': 'Notificaciones webhook',
|
|
'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.on': 'Activado',
|
|
'settings.off': 'Desactivado',
|
|
'settings.mcp.title': 'Configuración MCP',
|
|
'settings.mcp.endpoint': 'Endpoint MCP',
|
|
'settings.mcp.clientConfig': 'Configuración del cliente',
|
|
'settings.mcp.clientConfigHint':
|
|
'Reemplaza <your_token> con un token de la lista de abajo. Es posible que debas ajustar la ruta de npx según tu sistema (p. ej. C:\\PROGRA~1\\nodejs\\npx.cmd en Windows).',
|
|
'settings.mcp.clientConfigHintOAuth':
|
|
'Reemplaza <your_client_id> y <your_client_secret> con las credenciales del cliente OAuth 2.1 que creaste arriba. mcp-remote abrirá el navegador para completar la autorización la primera vez que te conectes. Es posible que debas ajustar la ruta de npx según tu sistema (p. ej. C:\\PROGRA~1\\nodejs\\npx.cmd en Windows).',
|
|
'settings.mcp.copy': 'Copiar',
|
|
'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.tokenCreatedAt': 'Creado',
|
|
'settings.mcp.tokenUsedAt': 'Usado',
|
|
'settings.mcp.deleteTokenTitle': 'Eliminar token',
|
|
'settings.mcp.deleteTokenMessage':
|
|
'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.creating': 'Creando…',
|
|
'settings.mcp.modal.create': 'Crear token',
|
|
'settings.mcp.modal.createdTitle': 'Token creado',
|
|
'settings.mcp.modal.createdWarning':
|
|
'Este token solo se mostrará una vez. Cópialo y guárdalo ahora — no se podrá recuperar.',
|
|
'settings.mcp.modal.done': 'Listo',
|
|
'settings.mcp.toast.created': 'Token creado',
|
|
'settings.mcp.toast.createError': 'Error al crear el token',
|
|
'settings.mcp.toast.deleted': 'Token eliminado',
|
|
'settings.mcp.toast.deleteError': 'Error al eliminar el token',
|
|
'settings.mcp.apiTokensDeprecated':
|
|
'Los tokens de API están obsoletos y se eliminarán en una versión futura. Utilice los clientes OAuth 2.1 en su lugar.',
|
|
'settings.oauth.clients': 'Clientes OAuth 2.1',
|
|
'settings.oauth.clientsHint':
|
|
'Registre clientes OAuth 2.1 para que las aplicaciones MCP de terceros (Claude Web, Cursor, etc.) puedan conectarse sin tokens estáticos.',
|
|
'settings.oauth.createClient': 'Nuevo cliente',
|
|
'settings.oauth.noClients': 'No hay clientes OAuth registrados.',
|
|
'settings.oauth.clientId': 'ID de cliente',
|
|
'settings.oauth.clientSecret': 'Secreto de cliente',
|
|
'settings.oauth.deleteClient': 'Eliminar cliente',
|
|
'settings.oauth.deleteClientMessage':
|
|
'Este cliente y todas las sesiones activas se eliminarán permanentemente. Cualquier aplicación que lo use perderá el acceso inmediatamente.',
|
|
'settings.oauth.rotateSecret': 'Renovar secreto',
|
|
'settings.oauth.rotateSecretMessage':
|
|
'Se generará un nuevo secreto de cliente y todas las sesiones existentes se invalidarán de inmediato. Actualice su aplicación antes de cerrar este diálogo.',
|
|
'settings.oauth.rotateSecretConfirm': 'Renovar',
|
|
'settings.oauth.rotateSecretConfirming': 'Renovando…',
|
|
'settings.oauth.rotateSecretDoneTitle': 'Nuevo secreto generado',
|
|
'settings.oauth.rotateSecretDoneWarning':
|
|
'Este secreto solo se muestra una vez. Cópielo ahora y actualice su aplicación — todas las sesiones anteriores han sido invalidadas.',
|
|
'settings.oauth.activeSessions': 'Sesiones OAuth activas',
|
|
'settings.oauth.sessionScopes': 'Ámbitos',
|
|
'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.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.redirectUrisHint':
|
|
'Un URI por línea. HTTPS obligatorio (localhost exento). Coincidencia exacta.',
|
|
'settings.oauth.modal.scopes': 'Ámbitos permitidos',
|
|
'settings.oauth.modal.scopesHint':
|
|
'list_trips y get_trip_summary siempre están disponibles — sin ámbito requerido. Permiten a la IA descubrir los IDs de viaje necesarios.',
|
|
'settings.oauth.modal.selectAll': 'Seleccionar todo',
|
|
'settings.oauth.modal.deselectAll': 'Deseleccionar todo',
|
|
'settings.oauth.modal.creating': 'Registrando…',
|
|
'settings.oauth.modal.create': 'Registrar cliente',
|
|
'settings.oauth.modal.createdTitle': 'Cliente registrado',
|
|
'settings.oauth.modal.createdWarning':
|
|
'El secreto del cliente solo se muestra una vez. Cópielo ahora — no se puede recuperar.',
|
|
'settings.oauth.toast.createError': 'Error al registrar el cliente OAuth',
|
|
'settings.oauth.toast.deleted': 'Cliente OAuth eliminado',
|
|
'settings.oauth.toast.deleteError': 'Error al eliminar el cliente OAuth',
|
|
'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.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':
|
|
'Obtener token: POST /oauth/token con grant_type=client_credentials, client_id y client_secret. Sin navegador, sin token de actualización.',
|
|
'settings.oauth.badge.machine': 'máquina',
|
|
'settings.account': 'Cuenta',
|
|
'settings.about': 'Acerca de',
|
|
'settings.about.reportBug': 'Reportar un error',
|
|
'settings.about.reportBugHint': 'Encontraste un problema? Avísanos',
|
|
'settings.about.featureRequest': 'Solicitar función',
|
|
'settings.about.featureRequestHint': 'Sugiere una nueva función',
|
|
'settings.about.wikiHint': 'Documentación y guías',
|
|
'settings.about.descriptionManaged':
|
|
'TREK helps you organize your trips from the first idea to the last memory. Day planning, budget, packing lists, photos and much more — all in one place.',
|
|
'settings.about.sourceTitle': 'Source code',
|
|
'settings.about.sourceHint': 'TREK is open source, licensed AGPL-3.0',
|
|
'settings.about.supporters.badge': 'Patrocinadores Mensuales',
|
|
'settings.about.supporters.title': 'Compañía de viaje para TREK',
|
|
'settings.about.supporters.subtitle':
|
|
'Mientras planeas tu próxima ruta, estas personas ayudan a planear el futuro de TREK. Su aporte mensual va directo al desarrollo y a las horas reales invertidas — para que TREK siga siendo Open Source.',
|
|
'settings.about.supporters.since': 'patrocinador desde {date}',
|
|
'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.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.username': 'Usuario',
|
|
'settings.email': 'Correo',
|
|
'settings.role': 'Rol',
|
|
'settings.roleAdmin': 'Administrador',
|
|
'settings.oidcLinked': 'Vinculado con',
|
|
'settings.changePassword': 'Cambiar contraseña',
|
|
'settings.mustChangePassword':
|
|
'Debe cambiar su contraseña antes de continuar. Establezca una nueva contraseña a continuación.',
|
|
'settings.currentPassword': 'Contraseña actual',
|
|
'settings.newPassword': 'Nueva contraseña',
|
|
'settings.confirmPassword': 'Confirmar nueva contraseña',
|
|
'settings.updatePassword': 'Actualizar contraseña',
|
|
'settings.passwordRequired': 'Introduce la contraseña actual y la nueva',
|
|
'settings.passwordTooShort': 'La contraseña debe tener al menos 8 caracteres',
|
|
'settings.passwordMismatch': 'Las contraseñas no coinciden',
|
|
'settings.passwordChanged': 'Contraseña cambiada correctamente',
|
|
'settings.deleteAccount': 'Eliminar cuenta',
|
|
'settings.deleteAccountTitle': '¿Eliminar tu cuenta?',
|
|
'settings.deleteAccountWarning':
|
|
'Tu cuenta y todos tus viajes, lugares y archivos se eliminarán permanentemente. Esta acción no se puede deshacer.',
|
|
'settings.deleteAccountConfirm': 'Eliminar permanentemente',
|
|
'settings.deleteBlockedTitle': 'No es posible eliminarla',
|
|
'settings.deleteBlockedMessage':
|
|
'Eres el único administrador. Asciende a otro usuario a administrador antes de eliminar tu cuenta.',
|
|
'settings.roleUser': 'Usuario',
|
|
'settings.saveProfile': 'Guardar perfil',
|
|
'settings.mfa.title': 'Autenticación de dos factores (2FA)',
|
|
'settings.mfa.description':
|
|
'Añade un segundo paso al iniciar sesión. Usa una app de autenticación (Google Authenticator, Authy, etc.).',
|
|
'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.backupCopy': 'Copiar códigos',
|
|
'settings.mfa.backupDownload': 'Descargar TXT',
|
|
'settings.mfa.backupPrint': 'Imprimir / PDF',
|
|
'settings.mfa.backupCopied': 'Códigos de respaldo copiados',
|
|
'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.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.disable': 'Desactivar 2FA',
|
|
'settings.mfa.toastEnabled': 'Autenticación de dos factores activada',
|
|
'settings.mfa.toastDisabled': 'Autenticación de dos factores desactivada',
|
|
'settings.mfa.demoBlocked': 'No disponible en modo demo',
|
|
'settings.toast.mapSaved': 'Ajustes del mapa guardados',
|
|
'settings.toast.keysSaved': 'Claves API guardadas',
|
|
'settings.toast.displaySaved': 'Ajustes de visualización guardados',
|
|
'settings.toast.profileSaved': 'Perfil guardado',
|
|
'settings.uploadAvatar': 'Subir foto de perfil',
|
|
'settings.removeAvatar': 'Eliminar foto de perfil',
|
|
'settings.avatarUploaded': 'Foto de perfil actualizada',
|
|
'settings.avatarRemoved': 'Foto de perfil eliminada',
|
|
'settings.avatarError': 'Falló la subida',
|
|
'settings.avatarRemoveError': 'Error al eliminar',
|
|
'settings.bookingLabels': 'Etiquetas de rutas de reservas',
|
|
'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.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.',
|
|
'settings.webhookUrl.label': 'URL del webhook',
|
|
'settings.webhookUrl.placeholder': 'https://discord.com/api/webhooks/...',
|
|
'settings.webhookUrl.hint':
|
|
'Introduce tu URL de webhook de Discord, Slack o personalizada para recibir notificaciones.',
|
|
'settings.webhookUrl.saved': 'URL del webhook guardada',
|
|
'settings.webhookUrl.test': 'Probar',
|
|
'settings.webhookUrl.testSuccess': 'Webhook de prueba enviado correctamente',
|
|
'settings.webhookUrl.testFailed': 'Error al enviar el webhook de prueba',
|
|
'settings.ntfyUrl.topicLabel': 'Tema de Ntfy',
|
|
'settings.ntfyUrl.topicPlaceholder': 'my-trek-alerts',
|
|
'settings.ntfyUrl.serverLabel': 'URL del servidor Ntfy (opcional)',
|
|
'settings.ntfyUrl.serverPlaceholder': 'https://ntfy.sh',
|
|
'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.saved': 'Configuración de Ntfy guardada',
|
|
'settings.ntfyUrl.test': 'Probar',
|
|
'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.notConfigured': 'Aún no configurado — configúralo en los ajustes del plugin',
|
|
'settings.plugins.actions': 'Acciones',
|
|
'settings.plugins.actions.confirm': '¿Ejecutar esta acción?',
|
|
'settings.notificationPreferences.sendTest': 'Enviar prueba',
|
|
'settings.notificationPreferences.configure': 'Configurar',
|
|
'settings.notificationPreferences.testSuccess': 'Notificación de prueba enviada.',
|
|
'settings.notificationPreferences.testFailed': 'La prueba falló.',
|
|
'settings.notificationPreferences.pluginConfigured':
|
|
'Configurado. Gestiona tus credenciales en la página de ajustes del plugin.',
|
|
'settings.notificationPreferences.webhook': 'Webhook',
|
|
'settings.notificationPreferences.email': 'Email',
|
|
'settings.notificationPreferences.ntfy': 'Ntfy',
|
|
'settings.currency': 'Moneda de visualización',
|
|
'settings.currencyHint':
|
|
'Los importes en Costes se muestran convertidos a esta moneda solo a efectos de visualización — los importes originales no se modifican.',
|
|
'settings.currencyTrip': 'Moneda del viaje',
|
|
'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.',
|
|
'settings.passkey.notConfigured':
|
|
'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.passwordRequired': 'Se requiere tu contraseña actual.',
|
|
'settings.passkey.namePlaceholder': 'Nombre (opcional, p. ej. "iPhone")',
|
|
'settings.passkey.addedToast': 'Passkey añadida',
|
|
'settings.passkey.added': 'Añadida',
|
|
'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.rename': 'Renombrar',
|
|
'settings.passkey.defaultName': 'Passkey',
|
|
'settings.passkey.synced': 'Sincronizada',
|
|
'settings.passkey.deviceBound': 'Este dispositivo',
|
|
'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.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.url': 'URL de la instancia',
|
|
'settings.airtrail.apiKey': 'Clave de API',
|
|
'settings.airtrail.apiKeyPlaceholder': 'Clave de API Bearer',
|
|
'settings.airtrail.apiKeyHint': 'Generada en AirTrail en Ajustes → Seguridad. Se almacena cifrada.',
|
|
'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.connected': 'Conectado',
|
|
'settings.airtrail.notConnected': 'No conectado',
|
|
'settings.airtrail.toast.saved': 'Conexión con AirTrail guardada',
|
|
'settings.airtrail.toast.saveError': 'No se pudo guardar la conexión',
|
|
'settings.airtrail.test.button': 'Probar conexión',
|
|
'settings.airtrail.test.success': 'Conectado: {count} vuelo(s) encontrado(s)',
|
|
'settings.airtrail.test.failed': 'Error de conexión',
|
|
'settings.aiParsing.title': 'Análisis con IA',
|
|
'settings.aiParsing.hint':
|
|
'Elige el modelo de IA que se usa para extraer reservas de los archivos subidos. Esto solo se aplica cuando tu administrador no ha configurado un modelo para toda la instancia.',
|
|
'settings.aiParsing.provider': 'Proveedor',
|
|
'settings.aiParsing.providerLocal': 'Local (Ollama)',
|
|
'settings.aiParsing.providerOpenai': 'OpenAI',
|
|
'settings.aiParsing.providerAnthropic': 'Anthropic',
|
|
'settings.aiParsing.localAdminOnly':
|
|
'Un endpoint local (Ollama) se configura una sola vez para toda la instancia en los ajustes de administración. Aquí puedes seguir usando tu propia clave de OpenAI o Anthropic.',
|
|
'settings.aiParsing.model': 'Modelo',
|
|
'settings.aiParsing.baseUrl': 'URL base',
|
|
'settings.aiParsing.baseUrlHint':
|
|
'Donde se ejecuta el modelo: un servidor Ollama local o un endpoint compatible con OpenAI.',
|
|
'settings.aiParsing.apiKey': 'Clave de API',
|
|
'settings.aiParsing.apiKeyHint': 'Se almacena cifrada. Déjalo en blanco para mantener la clave actual.',
|
|
'settings.aiParsing.multimodal': 'Enviar documentos como imágenes',
|
|
'settings.aiParsing.multimodalHint': 'Para modelos con visión: envía el PDF original en lugar del texto extraído.',
|
|
'settings.aiParsing.toast.saved': 'Ajustes de IA guardados',
|
|
'settings.aiParsing.toast.saveError': 'No se han podido guardar los ajustes de IA',
|
|
'settings.tabs.appearance': 'Appearance',
|
|
'settings.appearance.theme': 'Theme',
|
|
'settings.appearance.scheme': 'Color scheme',
|
|
'settings.appearance.scheme.default': 'Default',
|
|
'settings.appearance.scheme.highContrast': 'High contrast',
|
|
'settings.appearance.scheme.indigo': 'Indigo',
|
|
'settings.appearance.scheme.teal': 'Teal',
|
|
'settings.appearance.scheme.rose': 'Rose',
|
|
'settings.appearance.scheme.amber': 'Amber',
|
|
'settings.appearance.scheme.violet': 'Violet',
|
|
'settings.appearance.scheme.custom': 'Custom',
|
|
'settings.appearance.customAccent': 'Custom accent',
|
|
'settings.appearance.contrastOk': 'Good contrast',
|
|
'settings.appearance.contrastLow': 'Low contrast',
|
|
'settings.appearance.readability': 'Readability',
|
|
'settings.appearance.transparency': 'Transparency',
|
|
'settings.appearance.transparencyHint':
|
|
'Glassy translucent surfaces. Turn off for solid, higher-contrast backgrounds.',
|
|
'settings.appearance.reduceMotion': 'Reduce motion',
|
|
'settings.appearance.reduceMotionHint': 'Minimize animations and transitions.',
|
|
'settings.appearance.density': 'Density',
|
|
'settings.appearance.comfortable': 'Comfortable',
|
|
'settings.appearance.compact': 'Compact',
|
|
'settings.appearance.textSize': 'Text size',
|
|
'settings.appearance.advancedTextSizes': 'Advanced text sizes',
|
|
'settings.appearance.hideAdvanced': 'Hide advanced',
|
|
'settings.appearance.tier.title': 'Titles',
|
|
'settings.appearance.tier.subtitle': 'Subtitles',
|
|
'settings.appearance.tier.body': 'Body',
|
|
'settings.appearance.tier.caption': 'Captions',
|
|
'settings.appearance.dashboardWidgets': 'Dashboard widgets',
|
|
'settings.appearance.dashboardWidgetsHint': 'Show or hide dashboard widgets independently on desktop and mobile.',
|
|
'settings.appearance.desktop': 'Desktop',
|
|
'settings.appearance.mobile': 'Mobile',
|
|
'settings.appearance.widget.sidebar': 'Right sidebar',
|
|
'settings.appearance.widget.currency': 'Currency',
|
|
'settings.appearance.widget.collections': 'Colecciones',
|
|
'settings.appearance.widget.timezones': 'Timezones',
|
|
'settings.appearance.widget.upcomingReservations': 'Upcoming reservations',
|
|
'settings.appearance.widget.atlas': 'Atlas / countries',
|
|
'settings.appearance.widget.tripsTotal': 'Trips total',
|
|
'settings.appearance.widget.daysTraveled': 'Days traveled',
|
|
'settings.appearance.widget.distanceFlown': 'Distance flown',
|
|
'settings.appearance.reset': 'Reset to defaults',
|
|
'settings.appearance.group.belowHero': 'Below the hero',
|
|
'settings.appearance.group.bottomOfPage': 'Bottom of page',
|
|
'settings.appearance.sidebarHint': 'The whole right column. Turn off and the dashboard centers.',
|
|
'settings.appearance.densityHint':
|
|
'Compact tightens spacing and padding for a denser layout that fits more on screen.',
|
|
'settings.appearance.textSizeAll': 'Everything',
|
|
'settings.appearance.perSize': 'Adjust each size separately',
|
|
'settings.appearance.size.large': 'Large',
|
|
'settings.appearance.size.medium': 'Medium',
|
|
'settings.appearance.size.normal': 'Normal',
|
|
'settings.appearance.size.small': 'Small',
|
|
'settings.appearance.preview.large': 'Large heading',
|
|
'settings.appearance.preview.medium': 'Medium subtitle',
|
|
'settings.appearance.preview.normal': 'Normal body text',
|
|
'settings.appearance.preview.small': 'Small caption / address',
|
|
'settings.appearance.example.large': 'Headings, big numbers',
|
|
'settings.appearance.example.medium': 'Sub-headings',
|
|
'settings.appearance.example.normal': 'Place names, descriptions',
|
|
'settings.appearance.example.small': 'Addresses, labels',
|
|
'settings.appearance.experimental': 'Experimental',
|
|
'settings.appearance.mobileNav': 'Barra de navegación inferior',
|
|
'settings.appearance.mobileNav.hint':
|
|
'Elige qué elementos aparecen en la barra y cuáles quedan en «Más». Dashboard siempre va primero.',
|
|
'settings.appearance.mobileNav.inBar': 'En la barra',
|
|
'settings.appearance.mobileNav.underMore': 'En «Más»',
|
|
'settings.appearance.mobileNav.moreEmpty': 'Aún no hay nada aquí — todo cabe en la barra.',
|
|
'settings.appearance.mobileNav.pinned': 'Fijado',
|
|
'settings.appearance.mobileNav.toMore': 'Mover a «Más»',
|
|
'settings.appearance.mobileNav.toBar': 'Mover a la barra',
|
|
'settings.appearance.dashOrder': 'Orden del panel',
|
|
'settings.appearance.dashOrder.hint':
|
|
'Reordena cómo se apilan la lista de viajes y los widgets en el panel de tu teléfono. El viaje destacado siempre queda arriba.',
|
|
'settings.appearance.dashOrder.trips': 'Viajes',
|
|
'settings.appearance.dashOrder.hidden': 'Oculto',
|
|
'settings.general.languageRegion': 'Language & region',
|
|
'settings.general.travelMap': 'Travel & map',
|
|
'settings.general.startup': 'Inicio',
|
|
'settings.startPage': 'Página de inicio',
|
|
'settings.startPageDashboard': 'Panel',
|
|
'settings.startPageActiveTrip': 'Viaje activo',
|
|
'settings.startPageHint':
|
|
'TREK abre directamente el viaje que está en curso o el siguiente que empieza. Es el mismo viaje que destaca el panel.',
|
|
'settings.startTripTab': 'Pestaña de inicio',
|
|
'settings.startTripTabHint':
|
|
'La pestaña con la que se abre el viaje. Si pertenece a un complemento desactivado, se abre la vista de plan.',
|
|
|
|
// ── Offline (#1135)
|
|
'settings.offline.cache.title': 'Caché offline',
|
|
'settings.offline.mode.title': 'Modo offline',
|
|
'settings.offline.mode.force': 'Forzar el modo offline',
|
|
'settings.offline.mode.forceHint':
|
|
'Trabaja solo con los datos en caché y pon tus cambios en cola. Desactívalo para reconectar y sincronizar.',
|
|
'settings.offline.mode.active':
|
|
'El modo offline está activado: tus cambios están en cola y se sincronizarán cuando lo desactives.',
|
|
'settings.offline.prepare.title': 'Prepárate para estar offline',
|
|
'settings.offline.prepare.hint':
|
|
'Descarga todo lo que necesitas —datos del viaje, documentos y mosaicos del mapa— antes de perder la conexión.',
|
|
'settings.offline.prepare.button': 'Descargar para uso offline',
|
|
'settings.offline.prepare.running': 'Descargando…',
|
|
'settings.offline.prepare.done': 'Listo para usar offline',
|
|
'settings.offline.prepare.phase.trips': 'Datos del viaje',
|
|
'settings.offline.prepare.phase.files': 'Documentos',
|
|
'settings.offline.prepare.phase.tiles': 'Mosaicos del mapa',
|
|
'settings.offline.resync': 'Volver a sincronizar ahora',
|
|
'settings.offline.resyncing': 'Sincronizando…',
|
|
'settings.offline.storage.title': 'Qué almacenar offline',
|
|
'settings.offline.storage.tiles': 'Almacenar mosaicos del mapa offline',
|
|
'settings.offline.storage.tilesHint':
|
|
'Los mosaicos del mapa ocupan más almacenamiento. Desactívalo para conservar offline solo los datos del viaje y los documentos.',
|
|
'settings.offline.storage.tripsTitle': 'Viajes',
|
|
'settings.offline.storage.tripOn': 'Almacenado offline',
|
|
'settings.offline.storage.tripOff': 'No almacenado',
|
|
'settings.offline.clear': 'Vaciar caché',
|
|
'settings.offline.clearConfirm':
|
|
'¿Vaciar todos los datos de viaje offline? Puedes volver a sincronizar en cualquier momento con conexión.',
|
|
'settings.offline.stats.trips': 'Viajes en caché',
|
|
'settings.offline.stats.pending': 'Cambios pendientes',
|
|
'settings.offline.stats.failed': 'Cambios fallidos',
|
|
'settings.offline.stats.conflicts': 'Conflictos',
|
|
'settings.offline.empty': 'Aún no hay viajes en caché. Conéctate a internet para sincronizar.',
|
|
'settings.offline.loading': 'Cargando…',
|
|
'settings.offline.conflicts.title': 'Conflictos de sincronización',
|
|
'settings.offline.conflicts.hint':
|
|
'Los cambios que hiciste offline chocan con cambios más recientes en el servidor. Elige qué versión conservar.',
|
|
'settings.offline.conflicts.keepMine': 'Conservar la mía',
|
|
'settings.offline.conflicts.keepServer': 'Conservar la del servidor',
|
|
'settings.offline.conflicts.mine': 'Tu versión',
|
|
'settings.offline.conflicts.server': 'Versión del servidor',
|
|
'settings.offline.conflicts.item': 'Cambio en “{name}”',
|
|
'settings.offline.conflicts.strategyTitle': 'Cuando ocurre un conflicto',
|
|
'settings.offline.conflicts.strategy.ask': 'Preguntarme cada vez',
|
|
'settings.offline.conflicts.strategy.mine': 'Conservar siempre mi versión',
|
|
'settings.offline.conflicts.strategy.server': 'Conservar siempre la versión del servidor',
|
|
'settings.offline.banner.offline': 'Offline',
|
|
'settings.offline.banner.forced': 'Modo offline',
|
|
'settings.offline.banner.queued': 'Offline · {count} en cola',
|
|
'settings.offline.banner.syncing': 'Sincronizando {count}…',
|
|
'settings.offline.banner.failed': 'Error al sincronizar: {count}',
|
|
'settings.offline.banner.conflicts': 'Conflictos: {count}',
|
|
'settings.pluginActivity.title': 'Actividad de plugins',
|
|
'settings.pluginActivity.description': 'Cada acción que un plugin realizó en tu nombre, las más recientes primero.',
|
|
'settings.pluginActivity.empty': 'Todavía no hay actividad de plugins.',
|
|
'settings.pluginActivity.refresh': 'Actualizar',
|
|
'settings.pluginActivity.columns.plugin': 'Plugin',
|
|
'settings.pluginActivity.columns.action': 'Acción',
|
|
'settings.pluginActivity.columns.resource': 'Recurso',
|
|
'settings.pluginActivity.columns.when': 'Cuándo',
|
|
'settings.pluginActivity.columns.status': 'Resultado',
|
|
'settings.alwaysShowRoutes': 'Mostrar siempre las rutas de reserva',
|
|
'settings.alwaysShowRoutesHint':
|
|
'Muestra automáticamente en el mapa la ruta de cada vuelo, tren y otra reserva, sin necesidad de activarla una por una.',
|
|
|
|
// Public API keys (Settings -> Integrations)
|
|
'settings.apiKeys.title': 'Claves API',
|
|
'settings.apiKeys.description': 'Claves para la API pública, para que otro software pueda leer tus viajes. Solo lectura: una clave no puede cambiar ni borrar nada.',
|
|
'settings.apiKeys.create': 'Crear clave',
|
|
'settings.apiKeys.empty': 'Todavía no hay claves. Crea una para conectar otro software.',
|
|
'settings.apiKeys.createdAt': 'creada',
|
|
'settings.apiKeys.usedAt': 'último uso',
|
|
'settings.apiKeys.deleteTitle': 'Eliminar clave',
|
|
'settings.apiKeys.deleteMessage': 'Todo lo que use esta clave dejará de funcionar de inmediato. Esto no se puede deshacer.',
|
|
'settings.apiKeys.deleted': 'Clave eliminada',
|
|
'settings.apiKeys.deleteFailed': 'No se pudo eliminar la clave',
|
|
'settings.apiKeys.createFailed': 'No se pudo crear la clave',
|
|
'settings.apiKeys.copy': 'Copiar',
|
|
'settings.apiKeys.docsHint': 'Envía la clave como "Authorization: Bearer ..." o "X-API-Key: ..." a /api/v1.',
|
|
'settings.apiKeys.modal.createTitle': 'Crear clave API',
|
|
'settings.apiKeys.modal.name': 'Nombre',
|
|
'settings.apiKeys.modal.namePlaceholder': 'p. ej. Dawarich',
|
|
'settings.apiKeys.modal.nameHint': 'Solo para ti, para que reconozcas la clave más adelante.',
|
|
'settings.apiKeys.modal.creating': 'Creando...',
|
|
'settings.apiKeys.modal.create': 'Crear',
|
|
'settings.apiKeys.modal.createdTitle': 'Clave API creada',
|
|
'settings.apiKeys.modal.createdWarning': 'Copia la clave ahora. Se muestra una sola vez y no se puede recuperar después.',
|
|
'settings.apiKeys.modal.done': 'Listo',
|
|
};
|
|
|
|
export default settings;
|