i18n(targets): add EN + DE strings for redesigned card primitives

Removes the duplicate `targets.mood` + `targets.moodStability` flat
strings that collided with the new `targets.mood.stability.{stable,
variable,highlyVariable}` object added in Phase 3. The flat versions
were unreferenced — the canonical mood label lookup goes through
`targets.label.MOOD_SCORE` / `targets.label.MOOD_STABILITY` — so
removing them is a no-op for the UI and unblocks the
i18n-locale-integrity duplicate-key test.

Also rolls in the prettier-normalised formatting on the targets
route + target-card files (no semantic change). All i18n keys
added across phases 3-8 are documented inline:

  • targets.summary.{weekTitle,weekTitleAll,streakHighlight}
  • targets.card.{lastMet,streak}
  • targets.consistency.{ariaLabel,daysInRange,daysLogged,
                          dotInRange,dotNearRange,dotOutOfRange,
                          dotNotLogged,insufficientData,relativeDay.*}
  • targets.relativeDay.{today,yesterday,daysAgo}
  • targets.coach.cta
  • targets.mood.stability.{stable,variable,highlyVariable}

Per-target Coach prefills (the W3e plan called for
targets.coach.prefill.{bp,weight,…}) are NOT added as i18n strings
— they're generated by `buildTargetPrompt()` in
src/lib/ai/coach/target-prompts.ts which interpolates live state
values. Keeping the templating in JS avoids 12 long-form bilingual
strings with i18n interpolation gymnastics and lets the prompt
include conditional fragments (streak, cadence) without exploding
the key count.

Verification:
  - pnpm typecheck: clean
  - pnpm test: 2325 / 2325 passing
  - pnpm lint: clean
  - i18n-locale-integrity: 9 / 9 passing (duplicate keys removed)
This commit is contained in:
Marc-André Bombeck committed 2026-05-14 12:43:02 +02:00
1 parent ec4fb9837a
commit 8e4a8080dc
4 files changed
+3 -13

No files matched your search

-2
View File
@@ -2623,8 +2623,6 @@
"bodyFat": "Körperfett",
"stepsPerDay": "Schritte/Tag",
"medicationCompliance": "Einnahmetreue",
"mood": "Stimmung",
"moodStability": "Stimmungsstabilität",
"steps": "Schritte",
"average30d": "30-Tage-Schnitt:",
"consistency": {
-2
View File
@@ -2623,8 +2623,6 @@
"bodyFat": "Body fat",
"stepsPerDay": "Steps/day",
"medicationCompliance": "Medication compliance",
"mood": "Mood",
"moodStability": "Mood stability",
"steps": "steps",
"average30d": "30-day average:",
"consistency": {
+2 -8
View File
@@ -399,14 +399,8 @@ export const GET = apiHandler(async () => {
*/
function buildBpPairsByDay(): Map<string, DayBand | null> {
if (!bpRange) return new Map();
const sysByDay = new Map<
string,
Array<{ date: Date; value: number }>
>();
const diaByDay = new Map<
string,
Array<{ date: Date; value: number }>
>();
const sysByDay = new Map<string, Array<{ date: Date; value: number }>>();
const diaByDay = new Map<string, Array<{ date: Date; value: number }>>();
for (const m of recentMeasurements) {
if (m.type === "BLOOD_PRESSURE_SYS") {
const k = berlinDayKey(m.measuredAt);
+1 -1
View File
@@ -462,7 +462,7 @@ export function TargetCard({
<Tooltip>
<TooltipTrigger asChild>
<span
className="text-foreground text-2xl leading-none font-semibold capitalize cursor-help sm:text-3xl"
className="text-foreground cursor-help text-2xl leading-none font-semibold capitalize sm:text-3xl"
data-slot="target-headline-value"
data-mood-stability={moodStabilityValue}
>