From 48ac8f7e2d8bf83ea56a4145219ba9f9032ae623 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Bombeck?= Date: Sun, 26 Jul 2026 00:02:04 +0200 Subject: [PATCH] fix(ui): a mis-tap must not be able to destroy an allergy list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Settings → AI "About me" had one Clear control wired to `save.mutate({ aboutMe: "", allergies: "" })`. One tap, no dialog, and the allergy line went with the note — while the toast it raised said "About-me note cleared", which is what the control looks like it does. The allergy line is the first thing a clinician reads and the column is overwritten in place, so there is nothing to restore afterwards. Scope the control rather than only gating it: it now writes `aboutMe` alone and omits `allergies`, which the PUT leaves untouched by contract, so the payload cannot carry the allergy line away even if the dialog is ever dropped. Clearing allergies stays possible in the allergies field itself, which is a deliberate act on the thing being emptied. The confirmation on top guards the note. The same one-tap shape ran through thirteen other controls that overwrite a column or drop a credential with nothing to restore from. They route through the shared confirmation now: both Codex disconnects (personal and the instance-wide shared account), the AI server key, the profile photo, the threshold reset — all, per metric, and the override switch, whose off position performed the same irreversible delete from a control that reads as a display toggle — the source-priority order, the dashboard layout, the Insights overview, a single target range, a remembered Coach fact, a past Coach plan, a logged cycle day and a custom cycle symptom. `ConfirmButton` moves to `components/ui`, since it is no longer a settings-local helper, and gains `ConfirmDialog`: the same dialog without a trigger, for destructive controls that are not buttons. A switch has to stay on when the dialog its off position raised is cancelled, and a control that could not reach for the primitive reached for nothing — which is a fair part of why those were the ones that shipped unguarded. Copy lands in all six locales. --- messages/de.json | 46 +++++++ messages/en.json | 46 +++++++ messages/es.json | 46 +++++++ messages/fr.json | 46 +++++++ messages/it.json | 46 +++++++ messages/pl.json | 46 +++++++ src/app/coach/plans/page.tsx | 21 ++-- .../admin/ai-server-key-section.tsx | 17 +-- .../admin/central-codex-section.tsx | 23 ++-- src/components/cycle/log-day-sheet.tsx | 40 ++++-- .../insights/insights-edit-mode.tsx | 24 ++-- .../__tests__/coach-memory-section.test.tsx | 6 +- src/components/settings/about-me-section.tsx | 43 +++++-- .../account-section/avatar-section.tsx | 23 ++-- .../settings/ai/codex-provider-form.tsx | 22 ++-- .../settings/coach-memory-section.tsx | 34 +++--- .../settings/coach-reminders-section.tsx | 2 +- .../settings/dashboard-layout-section.tsx | 18 +-- .../settings/environment-section.tsx | 2 +- .../settings/security-sessions-card.tsx | 2 +- src/components/settings/sources-section.tsx | 19 +-- .../settings/thresholds-editor-section.tsx | 56 ++++++--- .../settings/trusted-devices-card.tsx | 2 +- src/components/targets/target-edit-sheet.tsx | 24 ++-- .../{settings => ui}/confirm-button.tsx | 115 +++++++++++++----- 25 files changed, 587 insertions(+), 182 deletions(-) rename src/components/{settings => ui}/confirm-button.tsx (54%) diff --git a/messages/de.json b/messages/de.json index 31f362748..e6e20165d 100644 --- a/messages/de.json +++ b/messages/de.json @@ -455,6 +455,9 @@ "scoreRingsTitle": "Score-Ringe", "scoreRingsDescription": "Bis zu drei zusätzliche Ringe neben dem Health Score – zum Beispiel Bereitschaft, Erholung, Schlaf oder Therapietreue. Zum Umsortieren ziehen; der Health Score steht standardmäßig vorne.", "layoutReset": "Auf Defaults zurücksetzen", + "layoutResetTitle": "Dashboard-Layout zurücksetzen?", + "layoutResetBody": "Deine Kachel-Reihenfolge, die ausgeblendeten Kacheln und die gewählten Ringe kehren zu den Standardwerten zurück. Die Anordnung wird nirgends sonst gespeichert.", + "layoutResetConfirm": "Layout zurücksetzen", "layoutSaveSuccess": "Dashboard-Layout gespeichert", "layoutSaveError": "Layout konnte nicht gespeichert werden", "layoutConflictReloaded": "Layout wurde vom Server neu geladen. Bitte nimm deine Änderung erneut vor.", @@ -2141,6 +2144,9 @@ "editMode": { "done": "Fertig", "reset": "Zurücksetzen", + "resetTitle": "Übersicht zurücksetzen?", + "resetBody": "Abschnittsreihenfolge und ausgeblendete Abschnitte kehren zu den Standardwerten zurück. Deine Anordnung wird nirgends sonst gespeichert.", + "resetConfirm": "Übersicht zurücksetzen", "title": "Übersicht anpassen", "description": "Zum Sortieren ziehen, zum Ein- oder Ausblenden auf das Auge tippen.", "dragHandle": "Zum Sortieren ziehen", @@ -3988,6 +3994,12 @@ "overrideToggleLabel": "Eigene Werte", "resetAction": "Auf Default zurücksetzen", "resetAllAction": "Alle auf Default zurücksetzen", + "resetAllTitle": "Alle eigenen Bereiche zurücksetzen?", + "resetAllBody": "Jede Messgröße kehrt zu ihrem Standardbereich zurück. Die von dir gesetzten Werte werden nirgends sonst gespeichert und lassen sich nicht wiederherstellen.", + "resetAllConfirm": "Alle zurücksetzen", + "resetTitle": "Diesen Bereich zurücksetzen?", + "resetBody": "Die Messgröße kehrt zu ihrem Standardbereich zurück. Die von dir gesetzten Werte werden nirgends sonst gespeichert und lassen sich nicht wiederherstellen.", + "resetConfirm": "Bereich zurücksetzen", "minLabel": "Min", "maxLabel": "Max", "unitSuffix": "({unit})", @@ -4356,6 +4368,9 @@ "cardTitle": "Quellen-Priorität pro Metrik", "help": "Liefern mehrere Quellen denselben Wert am selben Tag, zählt die oberste Quelle als kanonisch. Die übrigen bleiben für die Audit-Spur gespeichert.", "resetDefaults": "Auf Standard zurücksetzen", + "resetDefaultsTitle": "Quellen-Reihenfolge zurücksetzen?", + "resetDefaultsBody": "Jede von dir angeordnete Rangfolge kehrt zur Standardreihenfolge zurück, für alle Messgrößen und Gerätetypen auf einmal. Das wird sofort gespeichert und lässt sich nicht wiederherstellen.", + "resetDefaultsConfirm": "Reihenfolge zurücksetzen", "moveUp": "Nach oben", "moveDown": "Nach unten", "saveSuccess": "Quellen-Priorität gespeichert.", @@ -4787,6 +4802,9 @@ "upload": "Foto hochladen", "replace": "Foto ersetzen", "remove": "Entfernen", + "removeTitle": "Profilbild entfernen?", + "removeBody": "Das Bild wird von deinem Server gelöscht, an seine Stelle treten deine Initialen. Zum erneuten Hochladen brauchst du die Originaldatei.", + "removeConfirm": "Bild entfernen", "hint": "JPEG, PNG oder WebP. Bis zu 2 MB und 2048×2048 Pixel.", "uploaded": "Profilfoto aktualisiert", "removed": "Profilfoto entfernt", @@ -4946,6 +4964,9 @@ "statusExpired": "Verbindung abgelaufen", "connectButton": "Mit ChatGPT verbinden", "disconnectButton": "Trennen", + "disconnectTitle": "ChatGPT trennen?", + "disconnectBody": "Die gespeicherte Anmeldung wird zusammen mit deinem zwischengespeicherten Insight-Text verworfen. Für eine neue Verbindung musst du dich erneut über den Gerätecode-Ablauf anmelden.", + "disconnectConfirm": "Trennen", "modelSlugLabel": "Modell-Slug", "modelSlugBody": "Codex nutzt das Modell, auf das dein ChatGPT-Abo routet. Die Umgebungsvariable CODEX_MODEL kann das instanzweit überschreiben.", "lastInsight": "Letzte Analyse: {when}" @@ -4976,6 +4997,9 @@ "categoryContext": "Kontext", "forget": "Vergessen", "forgetAria": "Diese Angabe vergessen", + "forgetTitle": "Diese Notiz vergessen?", + "forgetBody": "Der Coach nutzt sie ab der nächsten Nachricht nicht mehr. Eine vergessene Notiz lässt sich nicht wiederherstellen.", + "forgetConfirm": "Vergessen", "forgetAll": "Alles vergessen", "forgetAllConfirmTitle": "Alles vergessen, woran sich der Coach erinnert?", "forgetAllConfirmBody": "Dadurch werden alle gespeicherten Angaben entfernt. Der Coach beginnt beim nächsten Gespräch von vorn. Das lässt sich nicht rückgängig machen.", @@ -5019,6 +5043,9 @@ "placeholder": "Z. B. Schichtarbeit, vegetarische Ernährung, Knieverletzung, Training für einen Halbmarathon…", "charCount": "{used} / {max} Zeichen", "clear": "Leeren", + "clearTitle": "Über-mich-Notiz leeren?", + "clearBody": "Entfernt nur den Freitext. Allergien und Unverträglichkeiten bleiben unverändert.", + "clearConfirm": "Notiz leeren", "save": "Speichern", "savedToast": "Über-mich-Notiz gespeichert.", "clearedToast": "Über-mich-Notiz gelöscht.", @@ -5844,6 +5871,9 @@ "baseUrlLabel": "Basis-URL", "save": "Speichern", "remove": "Schlüssel entfernen", + "removeTitle": "Server-Schlüssel entfernen?", + "removeBody": "Konten ohne eigenen Schlüssel verlieren die KI-Funktionen sofort. Der Schlüssel wird nach dem Speichern nirgends mehr angezeigt — zum Wiederherstellen brauchst du das Original.", + "removeConfirm": "Schlüssel entfernen", "saved": "KI-Server-Schlüssel gespeichert", "error": "Speichern des KI-Server-Schlüssels fehlgeschlagen" }, @@ -6366,6 +6396,9 @@ "statusExpired": "Abgelaufen", "connectButton": "ChatGPT-Konto verbinden", "disconnectButton": "Trennen", + "disconnectTitle": "Gemeinsames KI-Konto trennen?", + "disconnectBody": "Alle Nutzer auf diesem Server, die die gemeinsame Verbindung nutzen, verlieren die KI-Funktionen, bis wieder ein Konto verknüpft wird. Die gespeicherte Anmeldung lässt sich nicht wiederherstellen.", + "disconnectConfirm": "Trennen", "connectedSince": "Verbunden seit {when}", "connected": "Gemeinsame KI-Verbindung verknüpft", "disconnected": "Gemeinsame KI-Verbindung entfernt", @@ -6842,6 +6875,10 @@ "diastolicMax": "Diastolisch max", "boundsHint": "Erlaubter Bereich: {min}–{max} {unit}", "resetToDefault": "Auf Standard zurücksetzen", + "resetTitle": "Dieses Ziel zurücksetzen?", + "resetBody": "Der Bereich kehrt zum Standard zurück. Die von dir gesetzten Werte werden nirgends sonst gespeichert und lassen sich nicht wiederherstellen.", + "resetBodyBp": "Sowohl der systolische als auch der diastolische Bereich kehren zum Standard zurück. Die von dir gesetzten Werte werden nirgends sonst gespeichert und lassen sich nicht wiederherstellen.", + "resetConfirm": "Ziel zurücksetzen", "saveSuccess": "Zielbereich aktualisiert", "saveError": "Zielbereich konnte nicht gespeichert werden", "resetSuccess": "Zielbereich auf Standard zurückgesetzt", @@ -7074,6 +7111,9 @@ "icon": "Symbol", "limitReached": "Höchstzahl an eigenen Symptomen erreicht.", "remove": "{label} entfernen", + "removeTitle": "Dieses Symptom entfernen?", + "removeBody": "„{label}“ verschwindet aus der Symptomliste. Bereits damit markierte Tage behalten es, du kannst es aber nicht mehr auswählen.", + "removeConfirm": "Entfernen", "fallbackLabel": "Eigenes Symptom" } }, @@ -7306,6 +7346,9 @@ "severity": "Schweregrad", "severityLevel": "Schweregrad {level} von 4", "delete": "Löschen", + "deleteTitle": "Diesen Tag löschen?", + "deleteBody": "Alles, was für diesen Tag erfasst ist, verschwindet: Blutung, Temperatur, Symptome und deine Notiz. Es lässt sich nicht wiederherstellen.", + "deleteConfirm": "Tag löschen", "temperatureSection": "Temperatur & Eisprung", "intimacySection": "Intimität & Verhütung", "testsSection": "Tests", @@ -8099,6 +8142,9 @@ "markMet": "Ziel erreicht", "abandon": "Plan beenden", "remove": "Entfernen", + "removeTitle": "Diesen Plan entfernen?", + "removeBody": "Der Plan und sein Verlauf verschwinden aus deiner Historie. Er lässt sich nicht wiederherstellen.", + "removeConfirm": "Plan entfernen", "empty": "Noch keine Pläne. Wenn du dich im Gespräch zu einer konkreten Wenn-dann-Absicht bekennst, schlägt der Coach sie hier zur Bestätigung vor.", "groupProposed": "Vorschläge", "groupActive": "Aktiv", diff --git a/messages/en.json b/messages/en.json index 3fcc3b6cb..b1b50f6fc 100644 --- a/messages/en.json +++ b/messages/en.json @@ -455,6 +455,9 @@ "scoreRingsTitle": "Score rings", "scoreRingsDescription": "Up to three additional rings next to the health score — for example readiness, recovery, sleep or adherence. Drag to reorder; the health score leads by default.", "layoutReset": "Reset to defaults", + "layoutResetTitle": "Reset the dashboard layout?", + "layoutResetBody": "Your tile order, the tiles you hid and the rings you chose all go back to defaults. The arrangement is not stored anywhere else.", + "layoutResetConfirm": "Reset layout", "layoutSaveSuccess": "Dashboard layout saved", "layoutSaveError": "Could not save dashboard layout", "layoutConflictReloaded": "Layout reloaded from the server. Please make your change again.", @@ -2143,6 +2146,9 @@ "editMode": { "done": "Done", "reset": "Reset", + "resetTitle": "Reset the overview?", + "resetBody": "Section order and the sections you hid go back to defaults. Your arrangement is not stored anywhere else.", + "resetConfirm": "Reset overview", "title": "Customize overview", "description": "Drag to reorder, tap the eye to show or hide.", "dragHandle": "Drag to reorder", @@ -3988,6 +3994,12 @@ "overrideToggleLabel": "Custom range", "resetAction": "Reset to default", "resetAllAction": "Reset all to default", + "resetAllTitle": "Reset every custom range?", + "resetAllBody": "Every metric goes back to its default range. The values you set are not stored anywhere else and cannot be brought back.", + "resetAllConfirm": "Reset all", + "resetTitle": "Reset this range?", + "resetBody": "The metric goes back to its default range. The values you set are not stored anywhere else and cannot be brought back.", + "resetConfirm": "Reset range", "minLabel": "Min", "maxLabel": "Max", "unitSuffix": "({unit})", @@ -4356,6 +4368,9 @@ "cardTitle": "Source priority by metric", "help": "When several sources deliver the same value on the same day, the top source counts as canonical. The others stay stored for the audit trail.", "resetDefaults": "Reset to defaults", + "resetDefaultsTitle": "Reset the source order?", + "resetDefaultsBody": "Every ladder you arranged goes back to the default order, for all metrics and device types at once. This is saved immediately and cannot be brought back.", + "resetDefaultsConfirm": "Reset order", "moveUp": "Move up", "moveDown": "Move down", "saveSuccess": "Source priority saved.", @@ -4787,6 +4802,9 @@ "upload": "Upload photo", "replace": "Replace photo", "remove": "Remove", + "removeTitle": "Remove the profile photo?", + "removeBody": "The image is deleted from your server and your initials take its place. You would need the original file to upload it again.", + "removeConfirm": "Remove photo", "hint": "JPEG, PNG, or WebP. Up to 2 MB and 2048×2048 pixels.", "uploaded": "Profile photo updated", "removed": "Profile photo removed", @@ -4946,6 +4964,9 @@ "statusExpired": "Connection expired", "connectButton": "Connect with ChatGPT", "disconnectButton": "Disconnect", + "disconnectTitle": "Disconnect ChatGPT?", + "disconnectBody": "The stored sign-in is dropped along with your cached insight text. Reconnecting means signing in through the device-code flow again.", + "disconnectConfirm": "Disconnect", "modelSlugLabel": "Model slug", "modelSlugBody": "Codex uses the model your ChatGPT subscription routes to. The CODEX_MODEL environment variable lets ops override this on the instance.", "lastInsight": "Last insight: {when}" @@ -4976,6 +4997,9 @@ "categoryContext": "Context", "forget": "Forget", "forgetAria": "Forget this fact", + "forgetTitle": "Forget this fact?", + "forgetBody": "The Coach stops using it from the next message on. There is no way to bring a forgotten fact back.", + "forgetConfirm": "Forget", "forgetAll": "Forget everything", "forgetAllConfirmTitle": "Forget everything the Coach remembers?", "forgetAllConfirmBody": "This removes every stored fact. The Coach will start fresh the next time you chat. This cannot be undone.", @@ -5019,6 +5043,9 @@ "placeholder": "E.g. shift work, vegetarian diet, knee injury, training for a half marathon…", "charCount": "{used} / {max} characters", "clear": "Clear", + "clearTitle": "Clear the about-me note?", + "clearBody": "This removes the free-text note only. Your allergies and intolerances stay exactly as they are.", + "clearConfirm": "Clear note", "save": "Save", "savedToast": "About-me note saved.", "clearedToast": "About-me note cleared.", @@ -5844,6 +5871,9 @@ "baseUrlLabel": "Base URL", "save": "Save", "remove": "Remove key", + "removeTitle": "Remove the server key?", + "removeBody": "Accounts without their own key lose AI features straight away. The key is not shown anywhere after it is stored, so you will need the original to put it back.", + "removeConfirm": "Remove key", "saved": "AI server key settings saved", "error": "Saving the AI server key failed" }, @@ -6366,6 +6396,9 @@ "statusExpired": "Expired", "connectButton": "Connect a ChatGPT account", "disconnectButton": "Disconnect", + "disconnectTitle": "Disconnect the shared AI account?", + "disconnectBody": "Every user on this server who relies on the shared connection loses AI features until someone links an account again. The stored sign-in cannot be recovered.", + "disconnectConfirm": "Disconnect", "connectedSince": "Connected since {when}", "connected": "Shared AI connection linked", "disconnected": "Shared AI connection removed", @@ -6842,6 +6875,10 @@ "diastolicMax": "Diastolic max", "boundsHint": "Allowed range: {min}–{max} {unit}", "resetToDefault": "Reset to default", + "resetTitle": "Reset this target?", + "resetBody": "The range goes back to the default. The values you set are not stored anywhere else and cannot be brought back.", + "resetBodyBp": "Both the systolic and the diastolic range go back to the default. The values you set are not stored anywhere else and cannot be brought back.", + "resetConfirm": "Reset target", "saveSuccess": "Target range updated", "saveError": "Could not save the target range", "resetSuccess": "Target range reset to default", @@ -7074,6 +7111,9 @@ "icon": "Icon", "limitReached": "Custom symptom limit reached.", "remove": "Remove {label}", + "removeTitle": "Remove this symptom?", + "removeBody": "“{label}” disappears from the symptom list. Days you already tagged with it keep it, but you cannot pick it again.", + "removeConfirm": "Remove", "fallbackLabel": "Custom symptom" } }, @@ -7300,6 +7340,9 @@ "severity": "Severity", "severityLevel": "Severity {level} of 4", "delete": "Delete", + "deleteTitle": "Delete this day?", + "deleteBody": "Everything logged for this day goes: flow, temperature, symptoms and your note. There is no way to bring it back.", + "deleteConfirm": "Delete day", "note": "Note", "notePlaceholder": "Anything you want to remember about today…", "save": "Save", @@ -8099,6 +8142,9 @@ "markMet": "Goal met", "abandon": "End plan", "remove": "Remove", + "removeTitle": "Remove this plan?", + "removeBody": "The plan and how it went disappear from your history. There is no way to bring it back.", + "removeConfirm": "Remove plan", "empty": "No plans yet. When you commit to a concrete if-then intention in a conversation, the Coach proposes it here for confirmation.", "groupProposed": "Suggestions", "groupActive": "Active", diff --git a/messages/es.json b/messages/es.json index ce0c60e5e..9f56ae1f6 100644 --- a/messages/es.json +++ b/messages/es.json @@ -455,6 +455,9 @@ "scoreRingsTitle": "Anillos de puntuación", "scoreRingsDescription": "Hasta tres anillos adicionales junto a la puntuación de salud, por ejemplo preparación, recuperación, sueño o cumplimiento. Arrastra para reordenar; la puntuación de salud va primero de forma predeterminada.", "layoutReset": "Restablecer valores por defecto", + "layoutResetTitle": "¿Restablecer el diseño del panel?", + "layoutResetBody": "El orden de tus tarjetas, las que ocultaste y los anillos que elegiste vuelven a los valores predeterminados. La disposición no se guarda en ningún otro sitio.", + "layoutResetConfirm": "Restablecer diseño", "layoutSaveSuccess": "Diseño del panel guardado", "layoutSaveError": "No se ha podido guardar el diseño", "layoutConflictReloaded": "Se ha recargado el diseño desde el servidor. Vuelve a aplicar tu cambio.", @@ -2143,6 +2146,9 @@ "editMode": { "done": "Listo", "reset": "Restablecer", + "resetTitle": "¿Restablecer la vista general?", + "resetBody": "El orden de las secciones y las que ocultaste vuelven a los valores predeterminados. Tu disposición no se guarda en ningún otro sitio.", + "resetConfirm": "Restablecer vista", "title": "Personalizar resumen", "description": "Arrastra para reordenar, toca el ojo para mostrar u ocultar.", "dragHandle": "Arrastra para reordenar", @@ -3988,6 +3994,12 @@ "overrideToggleLabel": "Valores propios", "resetAction": "Restablecer valor por defecto", "resetAllAction": "Restablecer todos los valores", + "resetAllTitle": "¿Restablecer todos los rangos personalizados?", + "resetAllBody": "Cada métrica vuelve a su rango predeterminado. Los valores que definiste no se guardan en ningún otro sitio y no se pueden recuperar.", + "resetAllConfirm": "Restablecer todo", + "resetTitle": "¿Restablecer este rango?", + "resetBody": "La métrica vuelve a su rango predeterminado. Los valores que definiste no se guardan en ningún otro sitio y no se pueden recuperar.", + "resetConfirm": "Restablecer rango", "minLabel": "Mín", "maxLabel": "Máx", "unitSuffix": "({unit})", @@ -4356,6 +4368,9 @@ "cardTitle": "Prioridad de fuentes por métrica", "help": "Si varias fuentes entregan el mismo valor el mismo día, la fuente superior cuenta como canónica. Las demás se conservan para la traza de auditoría.", "resetDefaults": "Restablecer valores predeterminados", + "resetDefaultsTitle": "¿Restablecer el orden de fuentes?", + "resetDefaultsBody": "Cada orden que configuraste vuelve al predeterminado, para todas las métricas y tipos de dispositivo a la vez. Se guarda de inmediato y no se puede recuperar.", + "resetDefaultsConfirm": "Restablecer orden", "moveUp": "Subir", "moveDown": "Bajar", "saveSuccess": "Prioridad de fuentes guardada.", @@ -4787,6 +4802,9 @@ "upload": "Subir foto", "replace": "Reemplazar foto", "remove": "Quitar", + "removeTitle": "¿Eliminar la foto de perfil?", + "removeBody": "La imagen se elimina de tu servidor y tus iniciales ocupan su lugar. Necesitarás el archivo original para volver a subirla.", + "removeConfirm": "Eliminar foto", "hint": "JPEG, PNG o WebP. Hasta 2 MB y 2048×2048 píxeles.", "uploaded": "Foto de perfil actualizada", "removed": "Foto de perfil eliminada", @@ -4946,6 +4964,9 @@ "statusExpired": "Conexión caducada", "connectButton": "Conectar con ChatGPT", "disconnectButton": "Desconectar", + "disconnectTitle": "¿Desconectar ChatGPT?", + "disconnectBody": "Se descarta el inicio de sesión guardado junto con el texto de tus análisis en caché. Volver a conectar exige repetir el flujo de código de dispositivo.", + "disconnectConfirm": "Desconectar", "modelSlugLabel": "Slug del modelo", "modelSlugBody": "Codex usa el modelo al que enruta tu suscripción de ChatGPT. La variable de entorno CODEX_MODEL permite al operador sobrescribirlo en la instancia.", "lastInsight": "Último análisis: {when}" @@ -4976,6 +4997,9 @@ "categoryContext": "Contexto", "forget": "Olvidar", "forgetAria": "Olvidar este dato", + "forgetTitle": "¿Olvidar este dato?", + "forgetBody": "El Coach dejará de usarlo a partir del próximo mensaje. Un dato olvidado no se puede recuperar.", + "forgetConfirm": "Olvidar", "forgetAll": "Olvidar todo", "forgetAllConfirmTitle": "¿Olvidar todo lo que recuerda el Coach?", "forgetAllConfirmBody": "Esto elimina todos los datos guardados. El Coach empezará de cero la próxima vez que converses. No se puede deshacer.", @@ -5019,6 +5043,9 @@ "placeholder": "P. ej. trabajo por turnos, dieta vegetariana, lesión de rodilla, entrenamiento para una media maratón…", "charCount": "{used} / {max} caracteres", "clear": "Vaciar", + "clearTitle": "¿Vaciar la nota «Sobre mí»?", + "clearBody": "Solo se elimina el texto libre. Tus alergias e intolerancias permanecen tal cual.", + "clearConfirm": "Vaciar nota", "save": "Guardar", "savedToast": "Nota «Sobre mí» guardada.", "clearedToast": "Nota «Sobre mí» eliminada.", @@ -5844,6 +5871,9 @@ "baseUrlLabel": "URL base", "save": "Guardar", "remove": "Eliminar clave", + "removeTitle": "¿Eliminar la clave del servidor?", + "removeBody": "Las cuentas sin clave propia pierden las funciones de IA de inmediato. La clave no se muestra en ningún sitio una vez guardada, así que necesitarás el original para volver a ponerla.", + "removeConfirm": "Eliminar clave", "saved": "Ajustes de la clave de IA del servidor guardados", "error": "No se pudo guardar la clave de IA del servidor" }, @@ -6366,6 +6396,9 @@ "statusExpired": "Caducado", "connectButton": "Conectar una cuenta de ChatGPT", "disconnectButton": "Desconectar", + "disconnectTitle": "¿Desconectar la cuenta de IA compartida?", + "disconnectBody": "Todos los usuarios de este servidor que dependan de la conexión compartida pierden las funciones de IA hasta que alguien vuelva a vincular una cuenta. El inicio de sesión guardado no se puede recuperar.", + "disconnectConfirm": "Desconectar", "connectedSince": "Conectado desde {when}", "connected": "Conexión de IA compartida vinculada", "disconnected": "Conexión de IA compartida eliminada", @@ -6842,6 +6875,10 @@ "diastolicMax": "Diastólica máx", "boundsHint": "Rango permitido: {min}–{max} {unit}", "resetToDefault": "Restablecer por defecto", + "resetTitle": "¿Restablecer este objetivo?", + "resetBody": "El rango vuelve al predeterminado. Los valores que definiste no se guardan en ningún otro sitio y no se pueden recuperar.", + "resetBodyBp": "Tanto el rango sistólico como el diastólico vuelven al predeterminado. Los valores que definiste no se guardan en ningún otro sitio y no se pueden recuperar.", + "resetConfirm": "Restablecer objetivo", "saveSuccess": "Rango objetivo actualizado", "saveError": "No se ha podido guardar el rango objetivo", "resetSuccess": "Rango objetivo restablecido por defecto", @@ -7074,6 +7111,9 @@ "icon": "Icono", "limitReached": "Se alcanzó el límite de síntomas personalizados.", "remove": "Eliminar {label}", + "removeTitle": "¿Eliminar este síntoma?", + "removeBody": "«{label}» desaparece de la lista de síntomas. Los días que ya lo tienen lo conservan, pero no podrás volver a elegirlo.", + "removeConfirm": "Eliminar", "fallbackLabel": "Síntoma personalizado" } }, @@ -7306,6 +7346,9 @@ "severity": "Intensidad", "severityLevel": "Intensidad {level} de 4", "delete": "Eliminar", + "deleteTitle": "¿Eliminar este día?", + "deleteBody": "Se pierde todo lo registrado ese día: flujo, temperatura, síntomas y tu nota. No se puede recuperar.", + "deleteConfirm": "Eliminar día", "temperatureSection": "Temperatura y ovulación", "intimacySection": "Intimidad y anticoncepción", "testsSection": "Pruebas", @@ -8099,6 +8142,9 @@ "markMet": "Objetivo cumplido", "abandon": "Finalizar plan", "remove": "Eliminar", + "removeTitle": "¿Eliminar este plan?", + "removeBody": "El plan y cómo fue desaparecen de tu historial. No se puede recuperar.", + "removeConfirm": "Eliminar plan", "empty": "Aún no hay planes. Cuando te comprometas con una intención concreta de tipo «si… entonces» en una conversación, el Coach la propondrá aquí para confirmarla.", "groupProposed": "Propuestas", "groupActive": "Activos", diff --git a/messages/fr.json b/messages/fr.json index cea4d2355..f5348e6d8 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -455,6 +455,9 @@ "scoreRingsTitle": "Anneaux de score", "scoreRingsDescription": "Jusqu’à trois anneaux supplémentaires à côté du score de santé — par exemple préparation, récupération, sommeil ou observance. Glissez pour réordonner ; le score de santé est placé en premier par défaut.", "layoutReset": "Rétablir les valeurs par défaut", + "layoutResetTitle": "Réinitialiser la disposition du tableau de bord ?", + "layoutResetBody": "L’ordre de vos tuiles, celles que vous avez masquées et les anneaux choisis reviennent aux valeurs par défaut. Cette disposition n’est conservée nulle part ailleurs.", + "layoutResetConfirm": "Réinitialiser la disposition", "layoutSaveSuccess": "Mise en page enregistrée", "layoutSaveError": "Impossible d’enregistrer la mise en page", "layoutConflictReloaded": "Mise en page rechargée depuis le serveur. Veuillez refaire votre modification.", @@ -2143,6 +2146,9 @@ "editMode": { "done": "Terminé", "reset": "Réinitialiser", + "resetTitle": "Réinitialiser la vue d’ensemble ?", + "resetBody": "L’ordre des sections et celles que vous avez masquées reviennent aux valeurs par défaut. Votre disposition n’est conservée nulle part ailleurs.", + "resetConfirm": "Réinitialiser la vue", "title": "Personnaliser l’aperçu", "description": "Fais glisser pour réorganiser, touche l’œil pour afficher ou masquer.", "dragHandle": "Fais glisser pour réorganiser", @@ -3988,6 +3994,12 @@ "overrideToggleLabel": "Valeurs personnelles", "resetAction": "Restaurer la valeur par défaut", "resetAllAction": "Tout restaurer aux valeurs par défaut", + "resetAllTitle": "Réinitialiser toutes les plages personnalisées ?", + "resetAllBody": "Chaque mesure revient à sa plage par défaut. Les valeurs que vous avez définies ne sont conservées nulle part ailleurs et ne peuvent pas être récupérées.", + "resetAllConfirm": "Tout réinitialiser", + "resetTitle": "Réinitialiser cette plage ?", + "resetBody": "La mesure revient à sa plage par défaut. Les valeurs que vous avez définies ne sont conservées nulle part ailleurs et ne peuvent pas être récupérées.", + "resetConfirm": "Réinitialiser la plage", "minLabel": "Min", "maxLabel": "Max", "unitSuffix": "({unit})", @@ -4356,6 +4368,9 @@ "cardTitle": "Priorité des sources par métrique", "help": "Si plusieurs sources fournissent la même valeur le même jour, la source en tête compte comme canonique. Les autres restent enregistrées pour la piste d’audit.", "resetDefaults": "Rétablir les valeurs par défaut", + "resetDefaultsTitle": "Réinitialiser l’ordre des sources ?", + "resetDefaultsBody": "Chaque classement que vous avez défini revient à l’ordre par défaut, pour toutes les mesures et tous les types d’appareil à la fois. L’enregistrement est immédiat et irréversible.", + "resetDefaultsConfirm": "Réinitialiser l’ordre", "moveUp": "Monter", "moveDown": "Descendre", "saveSuccess": "Priorité des sources enregistrée.", @@ -4787,6 +4802,9 @@ "upload": "Téléverser une photo", "replace": "Remplacer la photo", "remove": "Supprimer", + "removeTitle": "Supprimer la photo de profil ?", + "removeBody": "L’image est supprimée de votre serveur et vos initiales prennent sa place. Il vous faudra le fichier d’origine pour la téléverser à nouveau.", + "removeConfirm": "Supprimer la photo", "hint": "JPEG, PNG ou WebP. Jusqu'à 2 Mo et 2048×2048 pixels.", "uploaded": "Photo de profil mise à jour", "removed": "Photo de profil supprimée", @@ -4946,6 +4964,9 @@ "statusExpired": "Connexion expirée", "connectButton": "Se connecter avec ChatGPT", "disconnectButton": "Déconnecter", + "disconnectTitle": "Déconnecter ChatGPT ?", + "disconnectBody": "La connexion enregistrée est supprimée, ainsi que le texte de vos analyses en cache. Se reconnecter suppose de refaire l’authentification par code d’appareil.", + "disconnectConfirm": "Déconnecter", "modelSlugLabel": "Slug du modèle", "modelSlugBody": "Codex utilise le modèle vers lequel votre abonnement ChatGPT route. La variable d’environnement CODEX_MODEL permet à l’opérateur de le remplacer sur l’instance.", "lastInsight": "Dernière analyse : {when}" @@ -4976,6 +4997,9 @@ "categoryContext": "Contexte", "forget": "Oublier", "forgetAria": "Oublier cette information", + "forgetTitle": "Oublier ce fait ?", + "forgetBody": "Le Coach cesse de l’utiliser dès le message suivant. Un fait oublié ne peut pas être récupéré.", + "forgetConfirm": "Oublier", "forgetAll": "Tout oublier", "forgetAllConfirmTitle": "Oublier tout ce dont le Coach se souvient ?", "forgetAllConfirmBody": "Cela supprime toutes les informations enregistrées. Le Coach repartira de zéro lors de votre prochaine conversation. Cette action est irréversible.", @@ -5019,6 +5043,9 @@ "placeholder": "Ex. travail posté, régime végétarien, blessure au genou, entraînement pour un semi-marathon…", "charCount": "{used} / {max} caractères", "clear": "Vider", + "clearTitle": "Vider la note « À propos de moi » ?", + "clearBody": "Seul le texte libre est supprimé. Vos allergies et intolérances restent inchangées.", + "clearConfirm": "Vider la note", "save": "Enregistrer", "savedToast": "Note « À propos de moi » enregistrée.", "clearedToast": "Note « À propos de moi » supprimée.", @@ -5844,6 +5871,9 @@ "baseUrlLabel": "URL de base", "save": "Enregistrer", "remove": "Supprimer la clé", + "removeTitle": "Supprimer la clé du serveur ?", + "removeBody": "Les comptes sans clé personnelle perdent aussitôt les fonctions IA. La clé n’est affichée nulle part une fois enregistrée : il vous faudra l’original pour la remettre.", + "removeConfirm": "Supprimer la clé", "saved": "Paramètres de la clé IA du serveur enregistrés", "error": "Échec de l'enregistrement de la clé IA du serveur" }, @@ -6366,6 +6396,9 @@ "statusExpired": "Expiré", "connectButton": "Relier un compte ChatGPT", "disconnectButton": "Déconnecter", + "disconnectTitle": "Déconnecter le compte IA partagé ?", + "disconnectBody": "Tous les utilisateurs de ce serveur qui s’appuient sur la connexion partagée perdent les fonctions IA jusqu’à ce qu’un compte soit relié à nouveau. La connexion enregistrée est irrécupérable.", + "disconnectConfirm": "Déconnecter", "connectedSince": "Connecté depuis le {when}", "connected": "Connexion IA partagée reliée", "disconnected": "Connexion IA partagée supprimée", @@ -6842,6 +6875,10 @@ "diastolicMax": "Diastolique max", "boundsHint": "Plage autorisée : {min}–{max} {unit}", "resetToDefault": "Restaurer la valeur par défaut", + "resetTitle": "Réinitialiser cet objectif ?", + "resetBody": "La plage revient à la valeur par défaut. Les valeurs que vous avez définies ne sont conservées nulle part ailleurs et ne peuvent pas être récupérées.", + "resetBodyBp": "La plage systolique et la plage diastolique reviennent toutes deux à la valeur par défaut. Les valeurs que vous avez définies ne sont conservées nulle part ailleurs et ne peuvent pas être récupérées.", + "resetConfirm": "Réinitialiser l’objectif", "saveSuccess": "Plage cible mise à jour", "saveError": "Impossible d’enregistrer la plage cible", "resetSuccess": "Plage cible réinitialisée", @@ -7074,6 +7111,9 @@ "icon": "Icône", "limitReached": "Limite de symptômes personnalisés atteinte.", "remove": "Supprimer {label}", + "removeTitle": "Supprimer ce symptôme ?", + "removeBody": "« {label} » disparaît de la liste des symptômes. Les journées déjà marquées le conservent, mais vous ne pourrez plus le sélectionner.", + "removeConfirm": "Supprimer", "fallbackLabel": "Symptôme personnalisé" } }, @@ -7306,6 +7346,9 @@ "severity": "Intensité", "severityLevel": "Intensité {level} sur 4", "delete": "Supprimer", + "deleteTitle": "Supprimer cette journée ?", + "deleteBody": "Tout ce qui est enregistré pour cette journée disparaît : flux, température, symptômes et votre note. Impossible de le récupérer.", + "deleteConfirm": "Supprimer la journée", "temperatureSection": "Température et ovulation", "intimacySection": "Intimité et contraception", "testsSection": "Tests", @@ -8099,6 +8142,9 @@ "markMet": "Objectif atteint", "abandon": "Terminer le plan", "remove": "Supprimer", + "removeTitle": "Supprimer ce plan ?", + "removeBody": "Le plan et son déroulement disparaissent de votre historique. Il est impossible de le récupérer.", + "removeConfirm": "Supprimer le plan", "empty": "Aucun plan pour l'instant. Lorsque vous vous engagez sur une intention concrète « si… alors » dans une conversation, le Coach la propose ici pour confirmation.", "groupProposed": "Propositions", "groupActive": "Actifs", diff --git a/messages/it.json b/messages/it.json index 3edd4d0cc..03c3462ee 100644 --- a/messages/it.json +++ b/messages/it.json @@ -455,6 +455,9 @@ "scoreRingsTitle": "Anelli dei punteggi", "scoreRingsDescription": "Fino a tre anelli aggiuntivi accanto al punteggio di salute, ad esempio prontezza, recupero, sonno o aderenza. Trascina per riordinare; il punteggio di salute è primo per impostazione predefinita.", "layoutReset": "Ripristina i valori predefiniti", + "layoutResetTitle": "Reimpostare il layout della dashboard?", + "layoutResetBody": "L’ordine dei riquadri, quelli che hai nascosto e gli anelli scelti tornano ai valori predefiniti. La disposizione non è salvata altrove.", + "layoutResetConfirm": "Reimposta layout", "layoutSaveSuccess": "Layout della dashboard salvato", "layoutSaveError": "Impossibile salvare il layout", "layoutConflictReloaded": "Layout ricaricato dal server. Applica di nuovo la tua modifica.", @@ -2143,6 +2146,9 @@ "editMode": { "done": "Fine", "reset": "Reimposta", + "resetTitle": "Reimpostare la panoramica?", + "resetBody": "L’ordine delle sezioni e quelle che hai nascosto tornano ai valori predefiniti. La tua disposizione non è salvata altrove.", + "resetConfirm": "Reimposta panoramica", "title": "Personalizza panoramica", "description": "Trascina per riordinare, tocca l’occhio per mostrare o nascondere.", "dragHandle": "Trascina per riordinare", @@ -3988,6 +3994,12 @@ "overrideToggleLabel": "Valori personali", "resetAction": "Ripristina predefinito", "resetAllAction": "Ripristina tutti ai predefiniti", + "resetAllTitle": "Reimpostare tutti gli intervalli personalizzati?", + "resetAllBody": "Ogni metrica torna al suo intervallo predefinito. I valori impostati non sono salvati altrove e non possono essere recuperati.", + "resetAllConfirm": "Reimposta tutto", + "resetTitle": "Reimpostare questo intervallo?", + "resetBody": "La metrica torna al suo intervallo predefinito. I valori impostati non sono salvati altrove e non possono essere recuperati.", + "resetConfirm": "Reimposta intervallo", "minLabel": "Min", "maxLabel": "Max", "unitSuffix": "({unit})", @@ -4356,6 +4368,9 @@ "cardTitle": "Priorità delle fonti per metrica", "help": "Se più fonti forniscono lo stesso valore nello stesso giorno, la fonte in cima conta come canonica. Le altre restano memorizzate per la traccia di controllo.", "resetDefaults": "Ripristina i valori predefiniti", + "resetDefaultsTitle": "Reimpostare l’ordine delle fonti?", + "resetDefaultsBody": "Ogni gerarchia che hai impostato torna all’ordine predefinito, per tutte le metriche e tutti i tipi di dispositivo insieme. Viene salvato subito e non può essere recuperato.", + "resetDefaultsConfirm": "Reimposta ordine", "moveUp": "Sposta su", "moveDown": "Sposta giù", "saveSuccess": "Priorità delle fonti salvata.", @@ -4787,6 +4802,9 @@ "upload": "Carica foto", "replace": "Sostituisci foto", "remove": "Rimuovi", + "removeTitle": "Rimuovere la foto del profilo?", + "removeBody": "L’immagine viene eliminata dal tuo server e al suo posto compaiono le tue iniziali. Per caricarla di nuovo ti servirà il file originale.", + "removeConfirm": "Rimuovi foto", "hint": "JPEG, PNG o WebP. Fino a 2 MB e 2048×2048 pixel.", "uploaded": "Foto del profilo aggiornata", "removed": "Foto del profilo rimossa", @@ -4946,6 +4964,9 @@ "statusExpired": "Connessione scaduta", "connectButton": "Connetti con ChatGPT", "disconnectButton": "Disconnetti", + "disconnectTitle": "Disconnettere ChatGPT?", + "disconnectBody": "L’accesso salvato viene eliminato insieme al testo degli approfondimenti in cache. Per riconnetterti dovrai ripetere il flusso con codice dispositivo.", + "disconnectConfirm": "Disconnetti", "modelSlugLabel": "Slug del modello", "modelSlugBody": "Codex usa il modello a cui instrada il tuo abbonamento ChatGPT. La variabile d’ambiente CODEX_MODEL consente all’operatore di sovrascriverlo sull’istanza.", "lastInsight": "Ultima analisi: {when}" @@ -4976,6 +4997,9 @@ "categoryContext": "Contesto", "forget": "Dimentica", "forgetAria": "Dimentica questa informazione", + "forgetTitle": "Dimenticare questa informazione?", + "forgetBody": "Il Coach smette di usarla dal messaggio successivo. Un’informazione dimenticata non può essere recuperata.", + "forgetConfirm": "Dimentica", "forgetAll": "Dimentica tutto", "forgetAllConfirmTitle": "Dimenticare tutto ciò che il Coach ricorda?", "forgetAllConfirmBody": "Questo rimuove tutte le informazioni memorizzate. Il Coach ripartirà da zero alla prossima chat. L'operazione non può essere annullata.", @@ -5019,6 +5043,9 @@ "placeholder": "Es. lavoro a turni, dieta vegetariana, infortunio al ginocchio, allenamento per una mezza maratona…", "charCount": "{used} / {max} caratteri", "clear": "Svuota", + "clearTitle": "Svuotare la nota «Su di me»?", + "clearBody": "Rimuove solo il testo libero. Allergie e intolleranze restano invariate.", + "clearConfirm": "Svuota nota", "save": "Salva", "savedToast": "Nota «Su di me» salvata.", "clearedToast": "Nota «Su di me» eliminata.", @@ -5844,6 +5871,9 @@ "baseUrlLabel": "URL di base", "save": "Salva", "remove": "Rimuovi chiave", + "removeTitle": "Rimuovere la chiave del server?", + "removeBody": "Gli account senza una chiave propria perdono subito le funzioni IA. Dopo il salvataggio la chiave non è più visibile da nessuna parte: per rimetterla ti servirà l’originale.", + "removeConfirm": "Rimuovi chiave", "saved": "Impostazioni della chiave IA del server salvate", "error": "Salvataggio della chiave IA del server non riuscito" }, @@ -6366,6 +6396,9 @@ "statusExpired": "Scaduto", "connectButton": "Collega un account ChatGPT", "disconnectButton": "Disconnetti", + "disconnectTitle": "Disconnettere l’account IA condiviso?", + "disconnectBody": "Tutti gli utenti di questo server che usano la connessione condivisa perdono le funzioni IA finché qualcuno non collega di nuovo un account. L’accesso salvato non è recuperabile.", + "disconnectConfirm": "Disconnetti", "connectedSince": "Connesso dal {when}", "connected": "Connessione IA condivisa collegata", "disconnected": "Connessione IA condivisa rimossa", @@ -6842,6 +6875,10 @@ "diastolicMax": "Diastolica max", "boundsHint": "Range consentito: {min}–{max} {unit}", "resetToDefault": "Ripristina predefinito", + "resetTitle": "Reimpostare questo obiettivo?", + "resetBody": "L’intervallo torna al valore predefinito. I valori impostati non sono salvati altrove e non possono essere recuperati.", + "resetBodyBp": "Sia l’intervallo sistolico sia quello diastolico tornano al valore predefinito. I valori impostati non sono salvati altrove e non possono essere recuperati.", + "resetConfirm": "Reimposta obiettivo", "saveSuccess": "Range obiettivo aggiornato", "saveError": "Impossibile salvare il range obiettivo", "resetSuccess": "Range obiettivo ripristinato", @@ -7074,6 +7111,9 @@ "icon": "Icona", "limitReached": "Limite di sintomi personalizzati raggiunto.", "remove": "Rimuovi {label}", + "removeTitle": "Rimuovere questo sintomo?", + "removeBody": "«{label}» sparisce dall’elenco dei sintomi. I giorni già contrassegnati lo mantengono, ma non potrai più selezionarlo.", + "removeConfirm": "Rimuovi", "fallbackLabel": "Sintomo personalizzato" } }, @@ -7306,6 +7346,9 @@ "severity": "Intensità", "severityLevel": "Intensità {level} su 4", "delete": "Elimina", + "deleteTitle": "Eliminare questo giorno?", + "deleteBody": "Sparisce tutto ciò che hai registrato per questo giorno: flusso, temperatura, sintomi e la tua nota. Non può essere recuperato.", + "deleteConfirm": "Elimina giorno", "temperatureSection": "Temperatura e ovulazione", "intimacySection": "Intimità e contraccezione", "testsSection": "Test", @@ -8099,6 +8142,9 @@ "markMet": "Obiettivo raggiunto", "abandon": "Termina piano", "remove": "Rimuovi", + "removeTitle": "Rimuovere questo piano?", + "removeBody": "Il piano e il suo andamento spariscono dalla cronologia. Non può essere recuperato.", + "removeConfirm": "Rimuovi piano", "empty": "Ancora nessun piano. Quando in una conversazione ti impegni in un'intenzione concreta «se… allora», il Coach la propone qui per la conferma.", "groupProposed": "Proposte", "groupActive": "Attivi", diff --git a/messages/pl.json b/messages/pl.json index fbb86f532..f1d9fb61a 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -455,6 +455,9 @@ "scoreRingsTitle": "Pierścienie wyników", "scoreRingsDescription": "Maksymalnie trzy dodatkowe pierścienie obok wskaźnika zdrowia — np. gotowość, regeneracja, sen lub przestrzeganie zaleceń. Przeciągnij, aby zmienić kolejność; wskaźnik zdrowia jest domyślnie na początku.", "layoutReset": "Przywróć wartości domyślne", + "layoutResetTitle": "Zresetować układ pulpitu?", + "layoutResetBody": "Kolejność kafelków, ukryte kafelki i wybrane pierścienie wracają do ustawień domyślnych. Ten układ nie jest nigdzie indziej zapisany.", + "layoutResetConfirm": "Zresetuj układ", "layoutSaveSuccess": "Układ panelu zapisany", "layoutSaveError": "Nie udało się zapisać układu", "layoutConflictReloaded": "Układ został ponownie wczytany z serwera. Wprowadź zmianę jeszcze raz.", @@ -2143,6 +2146,9 @@ "editMode": { "done": "Gotowe", "reset": "Przywróć", + "resetTitle": "Zresetować przegląd?", + "resetBody": "Kolejność sekcji i ukryte sekcje wracają do ustawień domyślnych. Twój układ nie jest nigdzie indziej zapisany.", + "resetConfirm": "Zresetuj przegląd", "title": "Dostosuj przegląd", "description": "Przeciągnij, aby zmienić kolejność, dotknij oka, aby pokazać lub ukryć.", "dragHandle": "Przeciągnij, aby zmienić kolejność", @@ -3988,6 +3994,12 @@ "overrideToggleLabel": "Własne wartości", "resetAction": "Przywróć wartość domyślną", "resetAllAction": "Przywróć wszystkie wartości domyślne", + "resetAllTitle": "Zresetować wszystkie własne zakresy?", + "resetAllBody": "Każda metryka wraca do zakresu domyślnego. Ustawione wartości nie są nigdzie indziej zapisane i nie da się ich odzyskać.", + "resetAllConfirm": "Zresetuj wszystkie", + "resetTitle": "Zresetować ten zakres?", + "resetBody": "Metryka wraca do zakresu domyślnego. Ustawione wartości nie są nigdzie indziej zapisane i nie da się ich odzyskać.", + "resetConfirm": "Zresetuj zakres", "minLabel": "Min", "maxLabel": "Maks", "unitSuffix": "({unit})", @@ -4356,6 +4368,9 @@ "cardTitle": "Priorytet źródeł według metryki", "help": "Gdy kilka źródeł dostarcza tę samą wartość tego samego dnia, źródło na górze liczy się jako kanoniczne. Pozostałe pozostają zapisane na potrzeby audytu.", "resetDefaults": "Przywróć wartości domyślne", + "resetDefaultsTitle": "Zresetować kolejność źródeł?", + "resetDefaultsBody": "Każda ustawiona przez ciebie kolejność wraca do domyślnej, dla wszystkich metryk i typów urządzeń naraz. Zapis następuje natychmiast i nie da się go cofnąć.", + "resetDefaultsConfirm": "Zresetuj kolejność", "moveUp": "W górę", "moveDown": "W dół", "saveSuccess": "Zapisano priorytet źródeł.", @@ -4787,6 +4802,9 @@ "upload": "Prześlij zdjęcie", "replace": "Zmień zdjęcie", "remove": "Usuń", + "removeTitle": "Usunąć zdjęcie profilowe?", + "removeBody": "Obraz zostanie usunięty z twojego serwera, a jego miejsce zajmą inicjały. Do ponownego wgrania potrzebny będzie oryginalny plik.", + "removeConfirm": "Usuń zdjęcie", "hint": "JPEG, PNG lub WebP. Do 2 MB i 2048×2048 pikseli.", "uploaded": "Zaktualizowano zdjęcie profilowe", "removed": "Usunięto zdjęcie profilowe", @@ -4946,6 +4964,9 @@ "statusExpired": "Połączenie wygasło", "connectButton": "Połącz z ChatGPT", "disconnectButton": "Rozłącz", + "disconnectTitle": "Odłączyć ChatGPT?", + "disconnectBody": "Zapisane logowanie zostanie usunięte razem z zapisanym tekstem analiz. Ponowne połączenie wymaga przejścia przez kod urządzenia jeszcze raz.", + "disconnectConfirm": "Odłącz", "modelSlugLabel": "Slug modelu", "modelSlugBody": "Codex używa modelu, do którego kieruje Twoja subskrypcja ChatGPT. Zmienna środowiskowa CODEX_MODEL pozwala operatorowi nadpisać to w instancji.", "lastInsight": "Ostatnia analiza: {when}" @@ -4976,6 +4997,9 @@ "categoryContext": "Kontekst", "forget": "Zapomnij", "forgetAria": "Zapomnij tę informację", + "forgetTitle": "Zapomnieć tę informację?", + "forgetBody": "Coach przestanie z niej korzystać od następnej wiadomości. Zapomnianej informacji nie da się odzyskać.", + "forgetConfirm": "Zapomnij", "forgetAll": "Zapomnij wszystko", "forgetAllConfirmTitle": "Zapomnieć wszystko, co Coach pamięta?", "forgetAllConfirmBody": "Spowoduje to usunięcie wszystkich zapisanych informacji. Coach zacznie od nowa przy następnej rozmowie. Tej operacji nie można cofnąć.", @@ -5019,6 +5043,9 @@ "placeholder": "Np. praca zmianowa, dieta wegetariańska, kontuzja kolana, trening do półmaratonu…", "charCount": "{used} / {max} znaków", "clear": "Wyczyść", + "clearTitle": "Wyczyścić notatkę „O mnie”?", + "clearBody": "Usuwa tylko tekst notatki. Alergie i nietolerancje pozostają bez zmian.", + "clearConfirm": "Wyczyść notatkę", "save": "Zapisz", "savedToast": "Notatka „O mnie” zapisana.", "clearedToast": "Notatka „O mnie” usunięta.", @@ -5844,6 +5871,9 @@ "baseUrlLabel": "Adres bazowy URL", "save": "Zapisz", "remove": "Usuń klucz", + "removeTitle": "Usunąć klucz serwera?", + "removeBody": "Konta bez własnego klucza natychmiast tracą funkcje AI. Po zapisaniu klucz nie jest nigdzie pokazywany, więc do przywrócenia potrzebny będzie oryginał.", + "removeConfirm": "Usuń klucz", "saved": "Zapisano ustawienia serwerowego klucza AI", "error": "Nie udało się zapisać serwerowego klucza AI" }, @@ -6366,6 +6396,9 @@ "statusExpired": "Wygasło", "connectButton": "Podłącz konto ChatGPT", "disconnectButton": "Rozłącz", + "disconnectTitle": "Odłączyć wspólne konto AI?", + "disconnectBody": "Wszyscy użytkownicy tego serwera korzystający ze wspólnego połączenia stracą funkcje AI, dopóki ktoś nie podłączy konta ponownie. Zapisanego logowania nie da się odzyskać.", + "disconnectConfirm": "Odłącz", "connectedSince": "Połączono od {when}", "connected": "Wspólne połączenie AI podłączone", "disconnected": "Wspólne połączenie AI usunięte", @@ -6842,6 +6875,10 @@ "diastolicMax": "Rozkurczowe maks", "boundsHint": "Dozwolony zakres: {min}–{max} {unit}", "resetToDefault": "Przywróć wartość domyślną", + "resetTitle": "Zresetować ten cel?", + "resetBody": "Zakres wraca do wartości domyślnej. Ustawione wartości nie są nigdzie indziej zapisane i nie da się ich odzyskać.", + "resetBodyBp": "Zarówno zakres skurczowy, jak i rozkurczowy wracają do wartości domyślnej. Ustawione wartości nie są nigdzie indziej zapisane i nie da się ich odzyskać.", + "resetConfirm": "Zresetuj cel", "saveSuccess": "Zakres docelowy zaktualizowany", "saveError": "Nie udało się zapisać zakresu docelowego", "resetSuccess": "Zakres docelowy przywrócono do domyślnego", @@ -7074,6 +7111,9 @@ "icon": "Ikona", "limitReached": "Osiągnięto limit własnych objawów.", "remove": "Usuń {label}", + "removeTitle": "Usunąć ten objaw?", + "removeBody": "„{label}” zniknie z listy objawów. Dni już nim oznaczone zachowają go, ale nie wybierzesz go ponownie.", + "removeConfirm": "Usuń", "fallbackLabel": "Objaw własny" } }, @@ -7306,6 +7346,9 @@ "severity": "Nasilenie", "severityLevel": "Nasilenie {level} z 4", "delete": "Usuń", + "deleteTitle": "Usunąć ten dzień?", + "deleteBody": "Zniknie wszystko, co zapisano tego dnia: krwawienie, temperatura, objawy i twoja notatka. Nie da się tego przywrócić.", + "deleteConfirm": "Usuń dzień", "temperatureSection": "Temperatura i owulacja", "intimacySection": "Intymność i antykoncepcja", "testsSection": "Testy", @@ -8099,6 +8142,9 @@ "markMet": "Cel osiągnięty", "abandon": "Zakończ plan", "remove": "Usuń", + "removeTitle": "Usunąć ten plan?", + "removeBody": "Plan i jego przebieg znikną z historii. Nie da się go przywrócić.", + "removeConfirm": "Usuń plan", "empty": "Nie ma jeszcze planów. Gdy w rozmowie zobowiążesz się do konkretnej intencji „jeśli… to”, Coach zaproponuje ją tutaj do potwierdzenia.", "groupProposed": "Propozycje", "groupActive": "Aktywne", diff --git a/src/app/coach/plans/page.tsx b/src/app/coach/plans/page.tsx index 7549adc1e..daa23c41d 100644 --- a/src/app/coach/plans/page.tsx +++ b/src/app/coach/plans/page.tsx @@ -13,6 +13,7 @@ import { } from "lucide-react"; import { Button } from "@/components/ui/button"; +import { ConfirmButton } from "@/components/ui/confirm-button"; import { PageHeader } from "@/components/ui/page-header"; import { QueryErrorCard } from "@/components/ui/query-error-card"; import { EmptyState } from "@/components/ui/empty-state"; @@ -189,18 +190,20 @@ function CoachPlansBody() { )} {group === "past" && ( - + icon={