diff --git a/messages/de.json b/messages/de.json index af054fe24..08e333443 100644 --- a/messages/de.json +++ b/messages/de.json @@ -1064,6 +1064,7 @@ "refusalInjection": "In deiner Nachricht stehen Anweisungen, die meine Vorgaben überschreiben sollen. Ich bin der HealthLog-Coach und fasse ausschließlich deine eigenen Gesundheitsdaten zusammen — formuliere deine Frage bitte in diesem Rahmen neu.", "errorBudget": "Du hast das heutige Coach-Limit erreicht. Das Budget setzt sich um Mitternacht (UTC) zurück.", "errorProvider": "Der Coach konnte gerade keinen Auswertungs-Anbieter erreichen. Bitte versuche es in einem Moment erneut.", + "errorNetwork": "Keine Internetverbindung — versuche es erneut, sobald du online bist.", "tagline": "Persönlicher Gesundheitscoach, auf deine Daten gestützt.", "newChat": "Neuer Chat", "send": "Senden", diff --git a/messages/en.json b/messages/en.json index 4b44be7fa..1cc8031cb 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1064,6 +1064,7 @@ "refusalInjection": "I noticed wording that tries to override my instructions. I am the HealthLog Coach and only summarise your own health data — please rephrase your question in those terms.", "errorBudget": "You've reached today's Coach usage limit. The budget refreshes at midnight UTC.", "errorProvider": "The Coach could not reach an Insights provider just now. Please try again in a moment.", + "errorNetwork": "No internet connection — try again once you're back online.", "tagline": "Personal health coach, grounded in your data.", "newChat": "New chat", "send": "Send", diff --git a/messages/es.json b/messages/es.json index aedded7d6..3643bdc7b 100644 --- a/messages/es.json +++ b/messages/es.json @@ -1064,6 +1064,7 @@ "refusalInjection": "Tu mensaje contiene instrucciones que pretenden sobrescribir mis indicaciones. Soy el coach de HealthLog y solo resumo tus propios datos de salud — reformula tu pregunta dentro de ese marco.", "errorBudget": "Has alcanzado el límite diario del coach. El cupo se reinicia a medianoche (UTC).", "errorProvider": "El coach no ha podido contactar con un proveedor de análisis ahora mismo. Inténtalo en un momento.", + "errorNetwork": "Sin conexión a Internet — inténtalo de nuevo cuando vuelvas a estar en línea.", "tagline": "Coach personal de salud, apoyado en tus datos.", "newChat": "Nueva conversación", "send": "Enviar", diff --git a/messages/fr.json b/messages/fr.json index 38b73fe6e..63e6b7201 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -1064,6 +1064,7 @@ "refusalInjection": "Ton message contient des instructions qui cherchent à remplacer mes consignes. Je suis le coach HealthLog et je ne résume que tes propres données de santé — reformule ta question dans ce cadre.", "errorBudget": "Tu as atteint la limite quotidienne du coach. Le quota se réinitialise à minuit (UTC).", "errorProvider": "Le coach n’a pas pu joindre un fournisseur d’analyse maintenant. Réessaie dans un instant.", + "errorNetwork": "Pas de connexion Internet — réessaie une fois reconnecté.", "tagline": "Coach personnel de santé, ancré sur tes données.", "newChat": "Nouvelle conversation", "send": "Envoyer", diff --git a/messages/it.json b/messages/it.json index 18d685ce5..2f75cba22 100644 --- a/messages/it.json +++ b/messages/it.json @@ -1064,6 +1064,7 @@ "refusalInjection": "Nel tuo messaggio ci sono istruzioni che cercano di sovrascrivere le mie indicazioni. Sono il coach di HealthLog e riassumo solo i tuoi dati di salute — riformula la domanda in questo perimetro.", "errorBudget": "Hai raggiunto il limite giornaliero del coach. Il budget si reimposta a mezzanotte (UTC).", "errorProvider": "Il coach non è riuscito a contattare un provider di analisi ora. Riprova fra poco.", + "errorNetwork": "Nessuna connessione Internet — riprova quando sei di nuovo online.", "tagline": "Coach personale di salute, basato sui tuoi dati.", "newChat": "Nuova chat", "send": "Invia", diff --git a/messages/pl.json b/messages/pl.json index 876b20d9a..24e2e0ba1 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -1064,6 +1064,7 @@ "refusalInjection": "Twoja wiadomość zawiera instrukcje, które próbują nadpisać moje wytyczne. Jestem coachem HealthLog i podsumowuję wyłącznie twoje własne dane zdrowotne — przeformułuj pytanie w tych ramach.", "errorBudget": "Osiągnięto dzienny limit coacha. Limit resetuje się o północy (UTC).", "errorProvider": "Coach nie mógł teraz skontaktować się z dostawcą analizy. Spróbuj za chwilę.", + "errorNetwork": "Brak połączenia z Internetem — spróbuj ponownie, gdy wrócisz online.", "tagline": "Osobisty coach zdrowia, oparty na twoich danych.", "newChat": "Nowa rozmowa", "send": "Wyślij", diff --git a/src/components/insights/coach-panel/__tests__/message-thread.test.tsx b/src/components/insights/coach-panel/__tests__/message-thread.test.tsx index c2151fa47..ba69fbb34 100644 --- a/src/components/insights/coach-panel/__tests__/message-thread.test.tsx +++ b/src/components/insights/coach-panel/__tests__/message-thread.test.tsx @@ -528,13 +528,20 @@ describe("errorCodeToI18nKey", () => { "coach.provider.unavailable", "coach.provider.empty", "coach.provider.none", - "coach.network", "coach.stream", ]) { expect(errorCodeToI18nKey(code)).toBe("insights.coach.errorProvider"); } }); + // v1.4.43 QoL (M6) — `coach.network` no longer collapses to the + // generic provider copy; the user needs the actionable offline hint. + it("maps coach.network to the dedicated offline key", () => { + expect(errorCodeToI18nKey("coach.network")).toBe( + "insights.coach.errorNetwork", + ); + }); + it("forward-compats unknown codes with the namespaced key", () => { expect(errorCodeToI18nKey("errorProvider")).toBe( "insights.coach.errorProvider", diff --git a/src/components/insights/coach-panel/message-thread.tsx b/src/components/insights/coach-panel/message-thread.tsx index 6e779206b..c184cb83d 100644 --- a/src/components/insights/coach-panel/message-thread.tsx +++ b/src/components/insights/coach-panel/message-thread.tsx @@ -82,10 +82,15 @@ export function errorCodeToI18nKey(code: string): string { return "insights.coach.dailyLimitBody"; case "coach.provider.rate_limited": return "insights.coach.providerRateLimitBody"; + case "coach.network": + // v1.4.43 QoL (M6) — a dropped network is the user's local + // problem and needs a different next action ("come back online") + // than a provider failure ("try again in a moment"). Split out + // so the user sees the actionable copy in the offline branch. + return "insights.coach.errorNetwork"; case "coach.provider.unavailable": case "coach.provider.empty": case "coach.provider.none": - case "coach.network": case "coach.stream": return "insights.coach.errorProvider"; default: