diff --git a/messages/de.json b/messages/de.json index c28878446..0b1a9ee93 100644 --- a/messages/de.json +++ b/messages/de.json @@ -2407,6 +2407,7 @@ "days7Label": "7T", "days7Title": "Letzte 7 Tage", "days30Label": "30T", + "daysNLabel": "{days}T", "days30Title": "Letzte 30 Tage", "days90Label": "90T", "days90Title": "Letzte 90 Tage", @@ -4745,6 +4746,12 @@ "settingsBody": "HealthLog funktioniert vollständig ohne KI. Verbinde unten einen Anbieter, wenn du ein tägliches Briefing, kurze Notizen zu deinen Werten und den Coach möchtest.", "action": "KI einrichten", "dismiss": "Nicht jetzt" + }, + "bmiHeight": { + "coachPrefill": "Ich habe meine Körpergröße noch nicht eingetragen — warum ist der BMI wichtig, und was sollte ich wissen, bevor ich sie eintrage?" + }, + "medicationsEmpty": { + "coachPrefill": "Ich habe noch keine Medikamente angelegt — was sollte ich wissen, bevor ich hier anfange, meine Therapietreue zu verfolgen?" } }, "thresholds": { @@ -8497,6 +8504,10 @@ "currentValue": "Aktuell: {value} {unit}", "targetRangeValue": "Zielbereich: {min}–{max} {unit}", "sourceLabel": "Quelle: {source}", + "sourceNames": { + "moodEntries": "Stimmungseinträge", + "sevenDays": "7 Tage" + }, "inTarget": "Im Zielbereich", "aboveTarget": "{delta} {unit} über Zielbereich", "belowTarget": "{delta} {unit} unter Zielbereich", diff --git a/messages/en.json b/messages/en.json index 7198453d6..be600a3c7 100644 --- a/messages/en.json +++ b/messages/en.json @@ -2407,6 +2407,7 @@ "days7Label": "7d", "days7Title": "Last 7 days", "days30Label": "30d", + "daysNLabel": "{days}d", "days30Title": "Last 30 days", "days90Label": "90d", "days90Title": "Last 90 days", @@ -4745,6 +4746,12 @@ "settingsBody": "HealthLog works fully without AI. Connect a provider below if you want a daily briefing, short notes on your readings and the Coach.", "action": "Set up AI", "dismiss": "Not now" + }, + "bmiHeight": { + "coachPrefill": "I haven’t set my height yet — why does BMI matter, and what should I know before I configure it?" + }, + "medicationsEmpty": { + "coachPrefill": "I haven’t added any medications yet — what should I know before I start tracking medication compliance here?" } }, "thresholds": { @@ -8497,6 +8504,10 @@ "currentValue": "Current: {value} {unit}", "targetRangeValue": "Target: {min}–{max} {unit}", "sourceLabel": "Source: {source}", + "sourceNames": { + "moodEntries": "Mood entries", + "sevenDays": "7 days" + }, "inTarget": "Within target range", "aboveTarget": "{delta} {unit} above target", "belowTarget": "{delta} {unit} below target", diff --git a/messages/es.json b/messages/es.json index fea607c2d..5c65d82e0 100644 --- a/messages/es.json +++ b/messages/es.json @@ -2407,6 +2407,7 @@ "days7Label": "7 d", "days7Title": "Últimos 7 días", "days30Label": "30 d", + "daysNLabel": "{days} d", "days30Title": "Últimos 30 días", "days90Label": "90 d", "days90Title": "Últimos 90 días", @@ -4745,6 +4746,12 @@ "settingsBody": "HealthLog funciona por completo sin IA. Conecta un proveedor abajo si quieres un resumen diario, notas breves sobre tus mediciones y el Coach.", "action": "Configurar IA", "dismiss": "Ahora no" + }, + "bmiHeight": { + "coachPrefill": "Todavía no he indicado mi altura: ¿por qué importa el IMC y qué debería saber antes de configurarla?" + }, + "medicationsEmpty": { + "coachPrefill": "Todavía no he añadido medicamentos: ¿qué debería saber antes de empezar a seguir aquí la adherencia?" } }, "thresholds": { @@ -8497,6 +8504,10 @@ "currentValue": "Actual: {value} {unit}", "targetRangeValue": "Rango objetivo: {min}–{max} {unit}", "sourceLabel": "Fuente: {source}", + "sourceNames": { + "moodEntries": "Entradas de ánimo", + "sevenDays": "7 días" + }, "inTarget": "En rango objetivo", "aboveTarget": "{delta} {unit} por encima del rango", "belowTarget": "{delta} {unit} por debajo del rango", diff --git a/messages/fr.json b/messages/fr.json index 7462c5d28..be8f0932c 100644 --- a/messages/fr.json +++ b/messages/fr.json @@ -2407,6 +2407,7 @@ "days7Label": "7 j", "days7Title": "7 derniers jours", "days30Label": "30 j", + "daysNLabel": "{days} j", "days30Title": "30 derniers jours", "days90Label": "90 j", "days90Title": "90 derniers jours", @@ -4745,6 +4746,12 @@ "settingsBody": "HealthLog fonctionne entièrement sans IA. Connectez un fournisseur ci-dessous si vous voulez un briefing quotidien, de courtes notes sur vos mesures et le Coach.", "action": "Configurer l'IA", "dismiss": "Pas maintenant" + }, + "bmiHeight": { + "coachPrefill": "Je n’ai pas encore indiqué ma taille — pourquoi l’IMC compte-t-il, et que dois-je savoir avant de la renseigner ?" + }, + "medicationsEmpty": { + "coachPrefill": "Je n’ai encore ajouté aucun médicament — que dois-je savoir avant de suivre ici l’observance ?" } }, "thresholds": { @@ -8497,6 +8504,10 @@ "currentValue": "Actuel : {value} {unit}", "targetRangeValue": "Plage cible : {min}–{max} {unit}", "sourceLabel": "Source : {source}", + "sourceNames": { + "moodEntries": "Entrées d’humeur", + "sevenDays": "7 jours" + }, "inTarget": "Dans la plage cible", "aboveTarget": "{delta} {unit} au-dessus de la plage", "belowTarget": "{delta} {unit} en dessous de la plage", diff --git a/messages/it.json b/messages/it.json index 145d58031..5186016ef 100644 --- a/messages/it.json +++ b/messages/it.json @@ -2407,6 +2407,7 @@ "days7Label": "7 g", "days7Title": "Ultimi 7 giorni", "days30Label": "30 g", + "daysNLabel": "{days} g", "days30Title": "Ultimi 30 giorni", "days90Label": "90 g", "days90Title": "Ultimi 90 giorni", @@ -4745,6 +4746,12 @@ "settingsBody": "HealthLog funziona completamente senza IA. Collega un fornitore qui sotto se vuoi un riepilogo giornaliero, brevi note sulle tue misurazioni e il Coach.", "action": "Configura IA", "dismiss": "Non ora" + }, + "bmiHeight": { + "coachPrefill": "Non ho ancora inserito la mia altezza: perché conta il BMI e cosa dovrei sapere prima di impostarla?" + }, + "medicationsEmpty": { + "coachPrefill": "Non ho ancora aggiunto farmaci: cosa dovrei sapere prima di iniziare a monitorare qui l’aderenza?" } }, "thresholds": { @@ -8497,6 +8504,10 @@ "currentValue": "Attuale: {value} {unit}", "targetRangeValue": "Range obiettivo: {min}–{max} {unit}", "sourceLabel": "Fonte: {source}", + "sourceNames": { + "moodEntries": "Voci dell’umore", + "sevenDays": "7 giorni" + }, "inTarget": "Nel range obiettivo", "aboveTarget": "{delta} {unit} sopra il range", "belowTarget": "{delta} {unit} sotto il range", diff --git a/messages/ko.json b/messages/ko.json index 821498bbf..3d7594b2e 100644 --- a/messages/ko.json +++ b/messages/ko.json @@ -2498,6 +2498,7 @@ "days7Label": "7일", "days7Title": "최근 7일", "days30Label": "30일", + "daysNLabel": "{days}일", "days30Title": "최근 30일", "days90Label": "90일", "days90Title": "최근 90일", @@ -4745,6 +4746,12 @@ "settingsBody": "HealthLog는 AI 없이도 모든 기능이 작동합니다. 일일 브리핑, 측정값에 대한 짧은 메모, 코치를 원하시면 아래에서 제공자를 연결하세요.", "action": "AI 설정", "dismiss": "나중에" + }, + "bmiHeight": { + "coachPrefill": "아직 키를 입력하지 않았어요. BMI가 왜 중요하고, 입력하기 전에 무엇을 알아야 하나요?" + }, + "medicationsEmpty": { + "coachPrefill": "아직 약을 추가하지 않았어요. 여기서 복약 순응도를 기록하기 전에 무엇을 알아야 하나요?" } }, "thresholds": { @@ -8497,6 +8504,10 @@ "currentValue": "현재: {value} {unit}", "targetRangeValue": "목표: {min}–{max} {unit}", "sourceLabel": "출처: {source}", + "sourceNames": { + "moodEntries": "기분 기록", + "sevenDays": "7일" + }, "inTarget": "목표 범위 안", "aboveTarget": "목표보다 {delta} {unit} 높음", "belowTarget": "목표보다 {delta} {unit} 낮음", diff --git a/messages/pl.json b/messages/pl.json index 20eee9b10..e35278cec 100644 --- a/messages/pl.json +++ b/messages/pl.json @@ -2407,6 +2407,7 @@ "days7Label": "7 dni", "days7Title": "Ostatnie 7 dni", "days30Label": "30 dni", + "daysNLabel": "{days} dni", "days30Title": "Ostatnie 30 dni", "days90Label": "90 dni", "days90Title": "Ostatnie 90 dni", @@ -4745,6 +4746,12 @@ "settingsBody": "HealthLog działa w pełni bez AI. Podłącz dostawcę poniżej, jeśli chcesz codzienne podsumowanie, krótkie notatki o pomiarach i Coacha.", "action": "Skonfiguruj AI", "dismiss": "Nie teraz" + }, + "bmiHeight": { + "coachPrefill": "Nie podałem jeszcze wzrostu — dlaczego BMI ma znaczenie i co powinienem wiedzieć, zanim go ustawię?" + }, + "medicationsEmpty": { + "coachPrefill": "Nie dodałem jeszcze żadnych leków — co powinienem wiedzieć, zanim zacznę tu śledzić przestrzeganie zaleceń?" } }, "thresholds": { @@ -8497,6 +8504,10 @@ "currentValue": "Aktualnie: {value} {unit}", "targetRangeValue": "Zakres docelowy: {min}–{max} {unit}", "sourceLabel": "Źródło: {source}", + "sourceNames": { + "moodEntries": "Wpisy nastroju", + "sevenDays": "7 dni" + }, "inTarget": "W zakresie docelowym", "aboveTarget": "{delta} {unit} powyżej zakresu", "belowTarget": "{delta} {unit} poniżej zakresu", diff --git a/src/app/insights/bmi/page.tsx b/src/app/insights/bmi/page.tsx index c4e91cb5a..cdc5ea3c6 100644 --- a/src/app/insights/bmi/page.tsx +++ b/src/app/insights/bmi/page.tsx @@ -95,7 +95,7 @@ export default function InsightsBmiPage() { } /> - + ); } diff --git a/src/app/insights/medications/page.tsx b/src/app/insights/medications/page.tsx index 99aa76753..e6492bf1c 100644 --- a/src/app/insights/medications/page.tsx +++ b/src/app/insights/medications/page.tsx @@ -208,7 +208,9 @@ export default function InsightsMedikamentePage() { } /> - + ); } diff --git a/src/components/charts/health-chart.tsx b/src/components/charts/health-chart.tsx index 3f539c146..beedff5eb 100644 --- a/src/components/charts/health-chart.tsx +++ b/src/components/charts/health-chart.tsx @@ -76,7 +76,7 @@ import { type MetricWindowStats, } from "@/lib/charts/window-stats"; import { shouldFireDataReady } from "@/lib/charts/data-ready-latch"; -import { axisUnitSuffix } from "@/lib/charts/axis-unit"; +import { axisTickUnitSuffix } from "@/lib/charts/axis-unit"; import { chartPointDayKey } from "@/components/day/chart-day"; import { ChartDayFooter, @@ -2078,7 +2078,7 @@ export function HealthChart({ } unit={ showYAxisUnit - ? axisUnitSuffix(yAxisUnit ?? unit) + ? axisTickUnitSuffix(yAxisUnit ?? unit) : undefined } /> diff --git a/src/components/insights/__tests__/metric-target-source-name.test.ts b/src/components/insights/__tests__/metric-target-source-name.test.ts new file mode 100644 index 000000000..e8077ac9c --- /dev/null +++ b/src/components/insights/__tests__/metric-target-source-name.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from "vitest"; + +import { sourceName } from "../metric-target-summary"; + +describe("sourceName", () => { + const t = (key: string) => `t:${key}`; + it("names the plain-description sources in the reader's language", () => { + expect(sourceName("Mood entries", t)).toBe( + "t:targets.sourceNames.moodEntries", + ); + expect(sourceName("7-day", t)).toBe("t:targets.sourceNames.sevenDays"); + }); + it("leaves a citation as it is", () => { + expect(sourceName("ESH 2023", t)).toBe("ESH 2023"); + }); +}); diff --git a/src/components/insights/__tests__/sleep-stage-stacked-bar.test.tsx b/src/components/insights/__tests__/sleep-stage-stacked-bar.test.tsx index 0abdb5b3c..6ea7b026f 100644 --- a/src/components/insights/__tests__/sleep-stage-stacked-bar.test.tsx +++ b/src/components/insights/__tests__/sleep-stage-stacked-bar.test.tsx @@ -88,6 +88,9 @@ describe("", () => { const html = render(, "de"); expect(html).toContain("Phasen-Verteilung"); expect(html).toContain("Letzte 7 Nächte"); + // The window toggle speaks the app's range vocabulary, not "7d". + expect(html).toContain(">7T<"); + expect(html).not.toContain(">7d<"); }); it("does not crash when the breakdown carries unknown stage keys", () => { diff --git a/src/components/insights/metric-target-summary.tsx b/src/components/insights/metric-target-summary.tsx index 845b1b8d6..513e2bfdd 100644 --- a/src/components/insights/metric-target-summary.tsx +++ b/src/components/insights/metric-target-summary.tsx @@ -421,12 +421,18 @@ function TargetReferencePanel({ rel="noopener noreferrer" className="text-muted-foreground hover:text-foreground inline-flex items-center gap-1 text-xs" > - {t("targets.sourceLabel", { source: target.source })} + + {t("targets.sourceLabel", { + source: sourceName(target.source, t), + })} +