Files
HealthLog/src/lib/medications/format-dose.ts
T
Marc-André Bombeck 6fe552ffdf fix(medications): localise the dose unit and lift it onto its own line
A medication's dose is stored as free text the wizard composes from an
amount and a unit token ("1 pieces", "2 tablets"), and the card rendered
that token verbatim glued onto the name — so the unit showed in English
on every locale and the title read "Test ABC 1 pieces".

Translate the dose at display time: a formatDose helper splits the stored
string and runs a known unit token through the existing unit messages, so
"1 pieces" reads "1 Stück" / "1 piece(s)" per locale while a custom
free-text dose passes through untouched. The card header now carries the
name alone on its title line with the dose on a muted line beneath it,
above the category badge; the detail view, table and intake dialogs
localise the same way. Vorsorge and lab rows pass an empty dose so they
render no extra line.
2026-06-30 13:39:23 +02:00

46 lines
1.6 KiB
TypeScript

import { DOSE_UNIT_KEYS } from "./dose-units";
/**
* Display-time dose formatter.
*
* The wizard composes `Medication.dose` as a free-text string
* `"{amount} {unitKey}"` storing the RAW unit key (e.g. "1 pieces",
* "5 mg"). Rendered verbatim that leaks the untranslated English key onto
* the card — "Test ABC 1 pieces" even on a German UI. This helper splits
* the amount from the unit and, when the unit is one of the canonical
* {@link DOSE_UNIT_KEYS}, swaps it for the localised label
* (`medications.wizard.steps.step3.unit.<key>`). A custom free-text dose
* the wizard never produced (e.g. "1 puff morning") passes through
* unchanged.
*
* Pure + SSR-safe: takes the `t` accessor as a parameter, no React hook.
*/
// Mirrors `parseDoseExpression` in wizard-payload.ts — split on a leading
// number ("5 mg" → {amount:"5", unit:"mg"}); no number → {amount:"", unit:raw}.
const DOSE_EXPR_RE = /^\s*(\d+(?:[.,]\d+)?)\s*(.*)$/;
const KNOWN_UNITS = new Set<string>(DOSE_UNIT_KEYS);
export function formatDose(
raw: string | null | undefined,
t: (key: string) => string,
): string {
if (!raw) return "";
const trimmed = raw.trim();
if (!trimmed) return "";
const match = DOSE_EXPR_RE.exec(trimmed);
const amount = match ? (match[1] ?? "") : "";
const unit = match ? (match[2] ?? "").trim() : trimmed;
const key = unit.toLowerCase();
if (KNOWN_UNITS.has(key)) {
const label = t(`medications.wizard.steps.step3.unit.${key}`);
return amount ? `${amount} ${label}` : label;
}
// Custom free-text dose (the wizard never minted this unit) — leave it be.
return raw;
}