diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 3188c5d2a..09007a1fa 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -2921,6 +2921,327 @@ "strengthSaveFailed": "No se pudieron guardar los cambios", "reportContactLabel": "Contacto (opcional)", "reportContactHint": "Correo o Discord, solo si quieres una respuesta", + "alarmNextLabel": "SIGUIENTE", + "alarmScheduleGroup": "Horario semanal", + "alarmWakeTimeRowTitle": "Hora de despertar", + "devicesWhichSourceWins": "Qué fuente tiene prioridad", + "devicesWhichSourceWinsSub": "Cuando dos de tus dispositivos miden lo mismo", + "devicesResetToDefault": "Volver al orden predeterminado", + "devicesCouldNotReachCorosWatch": "No se pudo conectar. Tiene que estar cerca y no estar conectado a otra app.", + "deviceFilterAllDevices": "Todos los dispositivos", + "devicesSyncNowSubListen": "Escuchar lo que envíe ahora mismo", + "devicePickerTitle": "Conecta tus dispositivos", + "devicePickerSubtitle": "Trae lo que uses. Puedes añadir más en cualquier momento.", + "devicePickerBrowseByCategory": "Explorar por categoría", + "devicePickerPrivacyNote": "Todo se queda en este teléfono. No se envía nada a ningún sitio a menos que decidas exportarlo.", + "devicePickerSearchLabel": "Buscar dispositivos o tipos", + "devicePickerSearchHint": "Buscar dispositivos o tipos", + "devicePickerNothingNearbyTitle": "Todavía no se ha encontrado nada", + "devicePickerNothingNearbyBody": "Un dispositivo solo responde mientras está activo, puesto y sin conectar a otro teléfono o app.", + "devicePickerNearby": "Cerca", + "devicePickerScanning": "Buscando dispositivos cercanos…", + "devicePickerBlurbBand": "La banda para la que se creó esta app. WHOOP 4 o 5.", + "devicePickerBlurbRing": "Lee el anillo directamente, sin cuenta ni suscripción de Oura.", + "devicePickerBlurbPolarPmd": "Un Polar Verity Sense u OH1. Mide el tiempo entre latidos de forma óptica y lo transmite durante un entrenamiento, igual que una banda pectoral.", + "devicePickerBlurbSensor": "Una banda pectoral o un brazalete, para el tiempo entre latidos durante un entrenamiento.", + "devicePickerBlurbCoros": "Un reloj deportivo. Lee la batería y la frecuencia cardíaca en vivo; las actividades grabadas se quedan en el reloj.", + "devicePickerBlurbColmi": "Un anillo Colmi. Sincroniza frecuencia cardíaca, fases del sueño, pasos, SpO2, VFC y estrés; los valores que calcula el propio anillo se etiquetan como de Colmi. Experimental.", + "devicePickerCannotPairFromHere": "Ese dispositivo no se puede emparejar desde esta pantalla.", + "welcomeLabResultsWritten": "{n, plural, one{1 resultado de laboratorio escrito} other{{n} resultados de laboratorio escritos}}", + "readinessDetailBreakdownNoScoreNote": "Una vista más aproximada de las mismas cuatro entradas. No suman la puntuación de hoy, que falta por el motivo indicado arriba.", + "readinessDetailNightsOfTarget": "{have} de {need} noches", + "readinessDetailOutsideRange": "no, fuera de tu rango habitual", + "readinessDetailLiftingScore": "sube tu puntuación", + "readinessDetailLoweringScore": "baja tu puntuación", + "readinessDetailAskHrv": "¿Está tu VFC en su rango habitual?", + "readinessDetailAskRhr": "¿Está tu frecuencia cardíaca en reposo en su rango habitual?", + "readinessDetailAskResp": "¿Está tu frecuencia respiratoria en su rango habitual?", + "readinessDetailAskTemp": "¿Está la temperatura de tu piel en su rango habitual?", + "dayTimelineDeviceBounded": "El detalle por dispositivo solo se guarda para los días recientes. Antes del {oldest} sabemos qué dispositivo registró, no lo que dijo.", + "metricDetailUsingForX": "Usando {device} para {metric}.", + "metricDetailPreferX": "Preferir {device}", + "metricDetailHistoryKeepsSource": "Los días ya terminados conservan la fuente con la que se calcularon.", + "metricDetailDimmedCaption": "Estos son los días en los que intervino {device}. La línea es tu lectura combinada.", + "metricDetailSlotNoValueRecording": "{day}, sin valor · {who}", + "metricDetailSlotNothingRecording": "{day}, nada estaba registrando", + "metricDetailRankToday": "Hoy es más alto que el {pct}% de tus propios días.", + "metricDetailRankTodayBand": "Hoy es más alto que el {pct}% de tus propios días — {band}.", + "metricDetailRankFrom": "Tu lectura del {date} es más alta que el {pct}% de tus propios días.", + "metricDetailRankFromBand": "Tu lectura del {date} es más alta que el {pct}% de tus propios días — {band}.", + "homeSyncedThrough": "Sincronizado hasta {when}", + "homeSyncedNever": "Todavía no hay datos de la banda", + "homeBriefingTitle": "Resumen", + "homeBriefingSubtitleEmpty": "Toca para escribir el resumen de hoy", + "sleepDetailEditNaps": "Siestas", + "sleepDetailIWasAsleep": "Estaba dormido", + "sleepDetailAskEnough": "¿Dormiste lo suficiente?", + "sleepDetailAskDeep": "¿Tuviste tu sueño profundo habitual?", + "sleepDetailAskSleptThrough": "¿Dormiste durante todo el tiempo en cama?", + "sleepDetailAskOnTime": "¿Te dormiste a tu hora habitual?", + "metricHeartEffortTitle": "Esfuerzo cardíaco", + "activitySetupWorkLabel": "Trabajo", + "activitySetupRestLabel": "Descanso", + "activitySetupRoundsLabel": "Rondas", + "activityZonesAnchorManual": "Definidas por ti, no calculadas: estos cinco umbrales sustituyen a los que te habrían dado tu edad o un máximo medido.", + "activityZonesSetYourOwnLink": "Definir tus propias zonas", + "activityZonesEditYourOwnLink": "Editar tus propias zonas", + "activityZonesEditYourOwnTitle": "Definir tus propias zonas", + "activityZonesEditYourOwnBody": "Cinco umbrales en lpm, de menor a mayor: dónde empieza cada zona. Borra los cinco para volver a las zonas que calculamos para ti.", + "activityZonesNeedAllFive": "Hacen falta los cinco umbrales, de menor a mayor. No se guardó nada.", + "activityZonesMustAscend": "Cada zona debe empezar más alto que la anterior. No se guardó nada.", + "activityZonesCurrentEdgesNote": "Los rangos son los límites actuales de tus zonas; las sesiones anteriores pueden haberse contado con otros.", + "activitySummaryShareToStrava": "Compartir en Strava", + "activitySummaryLapFastest": "{time}, la más rápida", + "signalRrIntervals": "Intervalos entre latidos", + "signalHr1Hz": "Frecuencia cardíaca continua", + "signalHrSparse": "Frecuencia cardíaca", + "signalAccel1Hz": "Movimiento", + "signalAccelHighRate": "Movimiento de alta frecuencia", + "signalPpgGreen": "PPG verde", + "signalPpgRedIr": "PPG rojo/infrarrojo", + "signalSkinTempRaw": "Temperatura de la piel", + "signalVendorScalars": "Los valores propios del dispositivo", + "missingSignalRrIntervals": "sin intervalos entre latidos", + "missingSignalHr1Hz": "sin frecuencia cardíaca continua", + "missingSignalHrSparse": "sin frecuencia cardíaca", + "missingSignalAccel1Hz": "sin acelerómetro", + "missingSignalAccelHighRate": "sin acelerómetro de alta frecuencia", + "missingSignalPpgGreen": "sin PPG verde", + "missingSignalPpgRedIr": "sin PPG rojo/infrarrojo", + "missingSignalSkinTempRaw": "sin sensor de temperatura", + "missingSignalVendorScalars": "no informa de nada propio", + "missingSignalUnknown": "no puede aportar esto", + "devicesSensorLimit": "{count, plural, =1{Este teléfono empareja como máximo un sensor junto a tu banda. Quítalo para añadir otro.} other{Este teléfono empareja como máximo {count} sensores junto a tu banda. Quita uno para añadir otro.}}", + "devicesOrderNotSaved": "No se pudo guardar ese orden. No cambió nada.", + "devicesRequestNotSaved": "No se pudo guardar esa solicitud. Inténtalo de nuevo.", + "activityReviewTitle": "Actividades detectadas", + "activityPossibleNap": "Posible siesta", + "activityPossibleWorkout": "Posible entrenamiento", + "activityConfirm": "Confirmar", + "activityEdit": "Editar", + "activityDiscard": "Descartar", + "activityChangeSport": "Cambiar deporte", + "activityNotAWorkout": "No es un entrenamiento", + "activitySaveConfirm": "Guardar y confirmar", + "activityNothing": "Nada que revisar", + "activityEmptyBody": "Las posibles siestas y entrenamientos aparecerán aquí.", + "activityLoadFailed": "No se pudieron cargar las actividades. Inténtalo de nuevo.", + "activityReviewProblem": "No se pudo terminar", + "activityReview": "Revisar", + "activityLoading": "Cargando…", + "activityPending": "{count} por revisar", + "activityLengthMinutes": "{minutes} min", + "activityStart": "Inicio", + "activityEnd": "Fin", + "activityCheckTimes": "Revisa las horas", + "activityNapWindow": "Elige un intervalo pasado de entre 5 minutos y 3 horas.", + "activityEditNap": "Editar siesta", + "activityEditWorkout": "Editar entrenamiento", + "activityNapAlerts": "Siestas detectadas", + "activityPushHint": "Solo notificaciones push. Las sugerencias siguen en Actividades detectadas.", + "activityCatalogueName": "{key, select, kcardio{Cardio} kstrength{Fuerza} ksports{Deportes} kathletics{Atletismo} koutdoor{Aire libre} kmindbody{Cuerpo y mente} keveryday{Día a día} kother{Otros} krunning{Carrera} ktrailrunning{Trail running} kwalking{Caminata} khiking{Senderismo} kcycling{Ciclismo} kindoorbike{Bicicleta estática} krowing{Remo} kswimming{Natación} kelliptical{Elíptica} kstairclimber{Escaladora} ktreadmill{Cinta de correr} kjumprope{Saltar la cuerda} kweighttraining{Entrenamiento con pesas} kpowerlifting{Powerlifting} kbodyweight{Peso corporal} kcalisthenics{Calistenia} kkettlebell{Kettlebell} kcrossfit{CrossFit} khiit{HIIT} kcircuittraining{Entrenamiento en circuito} kfunctional{Entrenamiento funcional} kfootball{Fútbol} kbasketball{Baloncesto} kcricket{Críquet} ktennis{Tenis} kbadminton{Bádminton} ktabletennis{Tenis de mesa} ksquash{Squash} kpadel{Pádel} kvolleyball{Voleibol} khockey{Hockey} kbaseball{Béisbol} krugby{Rugby} kgolf{Golf} kbowling{Bolos} kboxing{Boxeo} kmartialarts{Artes marciales} kwrestling{Lucha} kclimbing{Escalada} ksprinting{Esprint} ktrackintervals{Series en pista} kcrosscountry{Campo a través} khurdles{Vallas} klongjump{Salto de longitud} kshotput{Lanzamiento de peso} kjavelin{Lanzamiento de jabalina} kpolevault{Salto con pértiga} kmountainbiking{Ciclismo de montaña} kkayaking{Kayak} ksurfing{Surf} kpaddleboard{Paddle surf} kskiing{Esquí} ksnowboarding{Snowboard} kskating{Patinaje} kskateboarding{Skateboarding} khorseriding{Equitación} kyoga{Yoga} kpilates{Pilates} kstretching{Estiramientos} kmobility{Movilidad} ktaichi{Taichí} kbreathwork{Ejercicios de respiración} kmeditation{Meditación} khousework{Tareas del hogar} kgardening{Jardinería} kdogwalking{Pasear al perro} kchildcare{Cuidado de niños} kdiy{Bricolaje} kshopping{Compras} kstairs{Escaleras} kgeneralworkout{Entrenamiento general} kdancing{Baile} kintimacy{Intimidad} kphysiotherapy{Fisioterapia} ksauna{Sauna} kcoldplunge{Baño frío} other{{name}}}", + "exerciseCatalogueName": "{key, select, other{{name}}}", + "presentationBluetoothHeartRateSensor": "Sensor de frecuencia cardíaca Bluetooth", + "presentationGarminWatch": "Reloj Garmin", + "presentationPolarSensor": "Sensor Polar", + "presentationCorosWatch": "Reloj Coros", + "presentationCOROSWatch": "Reloj COROS", + "presentationSmartRingR11MR10M": "Anillo inteligente (R11M/R10M)", + "presentationDaFitMOYOUNGWatch": "Reloj DaFit / MOYOUNG", + "presentationWearFitBand": "Banda WearFit", + "presentationSmartRingBandLefunProtocol": "Anillo/banda inteligente (protocolo Lefun)", + "presentationHPlusHRBand": "Banda HPlus HR", + "presentationFossilSkagenHybridSmartwatch": "Reloj híbrido Fossil/Skagen", + "presentationColmiRing": "Anillo Colmi", + "presentationNoSleepWasScoredForThisDayRestingHR": "no se puntuó ningún sueño para este día — la FC en reposo solo se mide durante un periodo de sueño, nunca en horas de vigilia.", + "presentationBaevskyStressIndex0100RestingAutonomicTensionPRV": "Índice de estrés de Baevsky → 0–100; tensión autonómica en reposo (PRV).", + "presentationNoReadinessInputsPresentNeverImputed": "no hay entradas de recuperación — \"—\" (nunca se imputan).", + "presentationMETValueYourWeightRefinedByHeartRateOr": "Valor MET × tu peso, ajustado por la frecuencia cardíaca; o solo la frecuencia cardíaca, para una actividad sin MET.", + "presentationMood": "Ánimo", + "presentationSleepQuality": "Calidad del sueño", + "presentationS": "s", + "presentationV": "µV", + "presentationReadsTheRingDirectlyNoAccountNoKeyExchange": "Lee el anillo directamente, sin cuenta ni intercambio de claves.", + "presentationPebble2OrPebble2SEOnlyPairsOnly": "Solo Pebble 2 o Pebble 2 SE. Por ahora solo se empareja; todavía no se lee ni se guarda nada.", + "presentationTheOriginalFossilSkagenHybridSmartwatchNotTheNewer": "El reloj híbrido Fossil/Skagen original, no el Hybrid HR más reciente. Se empareja y se conecta; todavía no se deriva nada de él.", + "presentationABudgetActivityBandPairsAndBanksItsRaw": "Una banda de actividad económica. Se empareja y guarda sus datos en bruto, pero todavía no se deriva nada de ellos.", + "presentationPairsAndBanksItsRawDataNothingIsDecoded": "Se empareja y guarda sus datos en bruto; todavía no se decodifica nada.", + "presentationAGenericRingOrBandSoldUnderManyStorefront": "Un anillo o una banda genéricos que se venden con muchos nombres comerciales. Se empareja y se conecta; todavía no informa de nada.", + "presentationAGenericHPlusFamilyHRBandPairsAndBanks": "Una banda HR genérica de la familia HPlus. Se empareja y guarda su historial; todavía no se decodifica nada en un número.", + "presentationPairsAndBanksItsRawDataInTheBackground": "Se empareja y guarda sus datos en bruto en segundo plano, pero todavía no deriva nada de ellos.", + "presentationAnUnbrandedDaFitMOYOUNGStyleWatchPairsAndBanks": "Un reloj sin marca del tipo DaFit/MOYOUNG. Se empareja y guarda sus propios datos; todavía no se deriva nada de él.", + "presentationAnUnbrandedMakibesHR3BoardPairsAndBanksIts": "Una placa Makibes HR3 sin marca. Se empareja y guarda sus datos en bruto; todavía no se deriva nada de ellos.", + "presentationAnUnbrandedID115BoardPairsAndBanksItsRaw": "Una placa ID115 sin marca. Se empareja y guarda sus datos en bruto; todavía no se deriva nada de ellos.", + "presentationAnUnbrandedXWatchBoardPairsAndBanksItsRaw": "Una placa XWatch sin marca. Se empareja y guarda sus datos en bruto; todavía no se deriva nada de ellos.", + "presentationAnUnbrandedWatch9BoardPairsAndBanksItsRaw": "Una placa Watch9 sin marca. Se empareja y guarda sus datos en bruto; todavía no se deriva nada de ellos.", + "presentationAnSMAQ2OSSSmartwatchPairsAndBanksIts": "Un reloj inteligente SMA-Q2-OSS. Se empareja y guarda sus datos en bruto; todavía no se deriva nada de ellos.", + "presentationATLW64OrNO1F1FitnessBandPairsAnd": "Una banda de actividad TLW64 o NO1 F1. Se empareja y guarda sus datos en bruto; todavía no se deriva nada de ellos.", + "presentationCaffeine": "Cafeína", + "presentationAlcohol": "Alcohol", + "presentationMeasurementsOf": "{have} de {total} medidas", + "presentationAveragePulse": "{value} lpm de media", + "presentationSoreness": "Dolor muscular", + "presentationScreensBeforeBed": "Pantallas antes de dormir", + "presentationIn": "in", + "presentationLb": "lb", + "presentationMl": "ml", + "presentationMg": "mg", + "presentationUnits": "unidades", + "presentationWeightRepsLogged": "{weight} {unit} × {reps} registrado", + "presentationVolumeUnit": "{unit} de volumen", + "journalTagCaffeine": "cafeína", + "journalTagAlcohol": "alcohol", + "journalTagLateMeal": "cena tardía", + "journalTagStress": "estrés", + "journalTagPoorSleep": "mal sueño", + "journalTagTravel": "viaje", + "journalTagScreensLate": "pantallas tarde", + "journalTagMeds": "medicación", + "journalTagSick": "enfermo", + "journalTagSauna": "sauna", + "journalTagColdPlunge": "baño frío", + "journalTagSocial": "vida social", + "journalTagWorkout": "entrenamiento", + "journalTagRestDay": "día de descanso", + "liveHrShowingDeviceSemantics": "Mostrando {label}. Toca para cambiar de dispositivo.", + "devicesResetSourceSemantics": "Restablecer {signal} al orden predeterminado", + "metricDetailStepsGoalValue": "{count, plural, one{{value} paso} other{{value} pasos}}", + "scrubberNothingSelected": "Nada seleccionado", + "activityZonesNameWarmUp": "Calentamiento", + "activityZonesNameEasy": "Suave", + "activityZonesNameAerobic": "Aeróbico", + "activityZonesNameThreshold": "Umbral", + "activityZonesNameMaxEffort": "Esfuerzo máximo", + "findingIllnessTitle": "La frecuencia cardíaca en reposo ha estado elevada", + "findingIllnessDetail": "Las últimas noches sitúan tu frecuencia cardíaca en reposo por encima de lo habitual, por una noche muy alta o por varias ligeramente elevadas. Una sola señal: un patrón, no una causa.", + "findingLowReadinessTitle": "Recuperación baja", + "findingLowReadinessDetail": "La recuperación estuvo en su franja más baja. En conjunto, las señales de esa noche quedaron muy por debajo de lo habitual.", + "findingLowReadinessScoredDetail": "La recuperación fue de {score}, su franja más baja. En conjunto, las señales de esa noche quedaron muy por debajo de lo habitual.", + "missingSignalSteps": "sin recuento de pasos", + "missingSignalSkinTempC": "sin temperatura de la piel", + "missingSignalActivityLevel": "sin registro de actividad", + "missingSignalDeviceHrv": "sin VFC propia", + "missingSignalDeviceStages": "sin fases del sueño propias", + "missingSignalDeviceResp": "sin frecuencia respiratoria propia", + "missingSignalDeviceStress": "sin estrés propio", + "missingSignalDeviceSpo2": "sin SpO2 propia", + "signalSteps": "Pasos", + "signalSkinTempC": "Temperatura de la piel (°C)", + "signalActivityLevel": "Actividad", + "signalDeviceHrv": "La VFC propia del dispositivo", + "signalDeviceStages": "Las fases del sueño propias del dispositivo", + "signalDeviceResp": "La frecuencia respiratoria propia del dispositivo", + "signalDeviceStress": "El estrés propio del dispositivo", + "signalDeviceSpo2": "La SpO2 propia del dispositivo", + "devicePickerBlurbThermometer": "Guarda cada lectura como temperatura corporal.", + "devicePickerBlurbMiscaleBc": "Guarda cada peso estabilizado y su bioimpedancia, incluidos los almacenados.", + "devicePickerBlurbMiscale2": "Guarda cada peso estabilizado, incluidos los almacenados.", + "dayTimelineZoomNoHr": "Sin frecuencia cardíaca en este tramo", + "dayTimelineZoomPerMinute": "Promedios de 1 minuto. Arrastra los tiradores para ampliar; con dos horas o menos se muestra cada segundo mientras se conserve.", + "dayTimelineZoomPerMinuteOnly": "Promedios de 1 minuto. Las lecturas segundo a segundo ya no se conservan para este tramo.", + "dayTimelineZoomPerSecond": "Cada segundo que registró la banda. Las lecturas segundo a segundo solo se conservan para los días recientes.", + "dataExportHeartRate": "Exportar la frecuencia cardíaca, minuto a minuto", + "dataExportHeartRateSub": "Un CSV de los días que elijas, con un promedio de 1 minuto por cada minuto registrado. Los datos segundo a segundo están en la exportación de la base de datos", + "dataHeartRateRangeHelp": "La frecuencia cardíaca se conserva del {first} al {last}", + "trendNormalForYou": "Normal para ti", + "trendAboveUsual": "Por encima de lo habitual", + "trendBelowUsual": "Por debajo de lo habitual", + "trendVsUsual": "{diff} respecto a tu valor habitual de {usual}", + "trendUsualRange": "Rango habitual {lo}–{hi}{unit}", + "trendNeedsDays": "Tu rango habitual aparece después de {need} días. Llevas {have}.", + "monthGridLegendBetter": "Mejor de lo habitual", + "monthGridLegendUsual": "Habitual para ti", + "monthGridLegendWorse": "Peor de lo habitual", + "monthGridLegendOutside": "Fuera de tu rango habitual", + "monthGridRangeFootnote": "Una celda por día. Una barra arriba significa por encima de tu rango habitual; abajo, por debajo. Una celda con solo el contorno no tiene valor.", + "monthGridNoRangeTitle": "{title}: todavía sin rango habitual", + "monthGridFlatBody": "Todos tus días han sido más o menos iguales, así que todavía no hay un rango habitual con el que comparar un día.", + "monthGridRowSemantics": "{title}: {have} de {total} días tienen valor. {below} por debajo y {above} por encima de tu rango habitual.", + "zoneRowsRange": "{lo}–{hi} lpm", + "zoneRowsRangeTop": "{lo}+ lpm", + "zoneRowsMinutes": "{minutes} min", + "advancedTitle": "Gráficas avanzadas", + "advancedIntro": "Vistas de investigación de los mismos datos. Nada de esto cambia tus puntuaciones.", + "advancedBeatsTitle": "Latido a latido", + "advancedBeatsSub": "Cada latido frente al anterior, la VFC a lo largo de la noche, la capacidad de desaceleración", + "advancedRhythmTitle": "Horario de sueño y ritmo diario", + "advancedRhythmSub": "El sueño hora a hora, la variabilidad en reposo, la forma prevista de hoy", + "healthAdvancedLinkTitle": "Gráficas avanzadas", + "healthAdvancedLinkSub": "Detalle latido a latido y horario de sueño, para los curiosos", + "profileBandBattery": "Banda {pct}%", + "profileExportRow": "Exportación y copia de seguridad", + "profileExportRowSub": "Hojas de cálculo, una copia completa e importación del historial", + "profileSettingsRow": "Ajustes", + "profileSettingsRowSub": "Banda, app, datos, privacidad y avanzado", + "sleepTabPlanTitle": "Tu plan de sueño", + "sleepTabMoreTitle": "Alarma y reloj biológico", + "healthWellbeingTitle": "Mente, hábitos y medicación", + "healthWellbeingMindSub": "Respiración, ánimo y el diario", + "healthWellbeingHabitsSub": "Hábitos diarios, contados como días cumplidos", + "healthWellbeingMedsSub": "Las dosis de hoy y la última semana", + "healthWellbeingCycleSub": "Registra tu periodo y mira en qué punto del ciclo estás", + "activityStepsFoodTitle": "Pasos y comida", + "activityStepsSub": "Hoy y todos los días anteriores", + "activityNutritionSub": "Registra la comida y mira la proteína de hoy", + "homeBackToToday": "Volver a hoy", + "homeSomeDataMissingTitle": "Faltan algunos datos de hoy", + "homeFirstWeekTitle": "Tus primeras semanas", + "homeFirstWeekWear": "Usa la banda esta noche", + "homeFirstWeekSleep": "Sueño: la mañana después de tu primera noche", + "homeFirstWeekStrain": "Esfuerzo: a partir del día {day}", + "homeFirstWeekRecovery": "Recuperación: a partir de la noche {night}, cuando conozca tu normalidad", + "homeFirstWeekSoFar": "{count, plural, =1{1 día registrado hasta ahora} other{{count} días registrados hasta ahora}}", + "homeFirstWeekDone": "Hecho: {step}", + "homeCoachSetUpChip": "Haz preguntas sobre tus datos: configura el coach", + "homeRecoverySleeping": "Durmiendo…", + "homeRecoveryAfterWake": "La recuperación se puntúa cuando te despiertas.", + "homeRecoveryFinishingUp": "Terminando", + "homeRecoveryUpdated": "Actualizado {time} · {from} → {to}", + "dataRecoveryChanged": "La recuperación cambió: {list}", + "homeRecoveryStartsIn": "{count, plural, =1{La recuperación empieza en 1 noche} other{La recuperación empieza en {count} noches}}", + "healthWellbeingAllSub": "Respiración, ánimo, el diario, hábitos y medicación", + "healthWellbeingAllSubCycle": "Respiración, ánimo, el diario, hábitos, medicación y ciclo", + "settingsStepCalibration": "Calibración de pasos", + "settingsStepCalibrationSub": "Aprende cuánto cuenta tu banda de más o de menos al caminar y lo corrige en el teléfono. No se escribe nada en la banda y nada sale del dispositivo", + "stepCalTitle": "Calibración de pasos", + "stepCalIntro": "Tu banda cuenta los pasos con su propio sensor de movimiento, y cuánto se desvía depende de ti. Estas rutinas lo miden. Nada sale de tu teléfono.", + "stepCalSlowTitle": "Caminata lenta", + "stepCalSlowSub": "camina despacio, con el teléfono en el bolsillo", + "stepCalSlowGuide": "Camina despacio y a ritmo constante, con la banda ajustada. Cuenta tú 100 pasos.", + "stepCalBriskTitle": "Caminata rápida", + "stepCalBriskSub": "camina a tu ritmo habitual", + "stepCalBriskGuide": "Camina a tu ritmo normal. Cuenta tú 100 pasos.", + "stepCalJogTitle": "Trote", + "stepCalJogSub": "trota a ritmo constante", + "stepCalJogGuide": "Trota a ritmo constante. Cuenta tú 100 pasos.", + "stepCalEverydayTitle": "Por casa", + "stepCalEverydaySub": "ordena durante tres minutos, con el teléfono en el bolsillo", + "stepCalEverydayGuide": "Haz cosas normales por casa (llevar, levantar, ordenar) con el teléfono en el bolsillo. Tres minutos. No camines de un lado a otro a propósito.", + "stepCalCalibrated": "Calibrado — contado {n} veces", + "stepCalNotCalibrated": "Todavía sin calibrar", + "stepCalBandSeen": "{count, plural, one{paso visto por la banda} other{pasos vistos por la banda}}", + "stepCalCountYourself": "Cuenta tus propios pasos. Detente al llegar a {target}.", + "stepCalElapsed": "Sigue: esta va por tiempo.", + "stepCalHowManyCounted": "¿Cuántos pasos contaste?", + "stepCalFinish": "Listo", + "stepCalCancel": "Cancelar", + "stepCalKeepWalking": "Todavía no se ha registrado nada: empieza a caminar con la banda ajustada.", + "stepCalKeepMoving": "Todavía no se ha registrado nada: lleva el teléfono encima y sigue moviéndote.", + "stepCalNoSignal": "La banda no registró nada durante esa rutina.", + "stepCalNoPhoneAccess": "Esta rutina necesita el contador de pasos de tu teléfono y no se concedió el acceso. Ese contador es la referencia para el movimiento en casa.", + "stepCalPhoneNotReady": "El contador de pasos de tu teléfono no respondió. Inténtalo de nuevo en un momento.", + "stepCalNoPhone": "Tu teléfono no contó ningún paso mientras lo hacías. La próxima vez llévalo en el bolsillo: es la referencia para el movimiento en casa.", + "stepCalBandQuiet": "La banda casi no detectó movimiento. Conviene comprobar que la llevas ajustada y que está transmitiendo.", + "stepCalTooShort": "Esa rutina fue demasiado corta para medir. Camina el recuento completo.", + "stepCalMismatch": "La banda contó muchos más pasos que tú. Estaba captando algo que no era caminar.", + "stepCalWrongSource": "Esa rutina usó la referencia equivocada.", + "stepCalBadData": "Esa rutina produjo datos del sensor ilegibles.", + "stepCalRatioOutOfRange": "Tu recuento y el de la banda están demasiado lejos para usarlos. Repite la rutina y camina el recuento completo.", + "stepCalCadenceOutOfRange": "La banda no encontró un ritmo de caminata en esa rutina. Empieza a caminar justo después de pulsar inicio y mantén un ritmo constante.", + "stepCalRoutineTooShort": "Esa rutina terminó antes de que acabara el temporizador. Sigue hasta que se complete.", + "stepCalSaveFailed": "No se pudo guardar esa calibración.", + "stepCalDoneGait": "Guardado. Contaste {count} pasos y la banda vio {band}. A partir de ahora, este tipo de caminata se corrige un {pct}%.", + "stepCalDoneHousehold": "Guardado. Tu teléfono contó {count} de los {band} pasos que vio la banda. El movimiento en casa ahora se escala a {gain}.", "whoopFirmwareWarningTitle": "Usuarios de WHOOP: no vuelvas a conectarte a la app de WHOOP", "whoopFirmwareWarningAction": "Si usas OpenStrap u otra app de código abierto, o piensas cambiarte a una más adelante, no vuelvas a conectar tu banda a la app oficial de WHOOP. Puede instalar actualizaciones de firmware automáticamente. Desinstala o desactiva la app de WHOOP para evitar que actualice tu banda.", "whoopFirmwareWarningDetails": "Hay informes de que el firmware 50.43.1.0 y 50.43.2.0 de WHOOP 5.0 / MG bloquea el acceso a los datos. Es posible que el Bluetooth siga conectándose. OpenStrap no puede emitir el token de membresía firmado por WHOOP que se necesita para desbloquear las bandas afectadas. Estamos trabajando en una solución, pero todavía no hay ningún arreglo disponible." diff --git a/test/spanish_coverage_test.dart b/test/spanish_coverage_test.dart new file mode 100644 index 000000000..49af7cf3e --- /dev/null +++ b/test/spanish_coverage_test.dart @@ -0,0 +1,54 @@ +// Spanish was missing 321 strings outside the supplement catalogue, so whole +// screens (device picker, detected activities, step calibration, trends) fell +// back to English on an otherwise Spanish app. +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/widgets.dart'; +import 'package:flutter_test/flutter_test.dart'; + +import 'package:openstrap_edge/l10n/app_localizations.dart'; + +void main() { + final es = lookupAppLocalizations(const Locale('es')); + final en = lookupAppLocalizations(const Locale('en')); + + test('spanish has every english string outside the two known gaps', () { + Map arb(String code) => + jsonDecode(File('lib/l10n/app_$code.arb').readAsStringSync()) + as Map; + final spanish = arb('es'); + final missing = [ + for (final k in arb('en').keys) + if (!k.startsWith('@') && !spanish.containsKey(k)) k, + ]; + // Still to do: the supplement catalogue. The WHOOP firmware warning is + // added by its own change. + missing.removeWhere((k) => + k.startsWith('supplement') || k.startsWith('whoopFirmwareWarning')); + expect(missing, isEmpty); + }); + + test('the newly covered screens read in spanish', () { + expect(es.devicePickerTitle, 'Conecta tus dispositivos'); + expect(es.activityReviewTitle, 'Actividades detectadas'); + expect(es.stepCalTitle, 'Calibración de pasos'); + expect(es.stepCalTitle, isNot(en.stepCalTitle)); + }); + + test('built-in activities are named in spanish, custom ones pass through', + () { + expect(es.activityCatalogueName('krunning', 'Running'), 'Carrera'); + expect(es.activityCatalogueName('kcardio', 'Cardio'), 'Cardio'); + expect(es.activityCatalogueName('custom', 'Mi deporte'), 'Mi deporte'); + }); + + test('counts agree with their noun', () { + expect(es.stepCalBandSeen(1), 'paso visto por la banda'); + expect(es.stepCalBandSeen(5), 'pasos vistos por la banda'); + expect(es.homeFirstWeekSoFar(1), '1 día registrado hasta ahora'); + expect(es.homeFirstWeekSoFar(3), '3 días registrados hasta ahora'); + expect(es.welcomeLabResultsWritten(1), '1 resultado de laboratorio escrito'); + expect(es.devicesSensorLimit(2), contains('2 sensores')); + }); +}