mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-14 22:50:51 +00:00
Four locales received English on surfaces whose translations were already complete, because the resolving code was a de/en binary. - Medication reminder push and the Telegram inline-keyboard labels admitted only de/en, so es/fr/it/pl got the English template on every channel. Route the resolver through a shared coerceLocale(). - The Coach's trailing "reply now in X" clause said English for any non-German locale, overriding the correct system-prompt directive. Read the language name from a shared map instead. - Coach refusal copy was a de/en constant pair, answering four locales in English at the one turn the Coach is declining to help. Move the copy into the bundles; the EN/DE constants now derive from them. - The sleep-stage chart formatted axis ticks as en-US for four locales; the cycle calendar and the device-score tile followed the *browser* locale rather than the app locale. - Three components carried a byte-identical duration formatter that branched on German. Lift it to one key-driven helper. Polish needs a third plural tier: 2-4 takes a "few" form a two-form scheme cannot express, so "2 godzin temu" read as "2 of-hours ago". Add a pluralKey() helper driven by Intl.PluralRules and a Few tier to the relative-time and stale-hint keys. The five locales whose rules have no "few" category resolve exactly as before by construction, and their Few values mirror Other. Teach the reverse-coverage guard to expand a pluralKey() base into its three tiers.
24 lines
1010 B
TypeScript
24 lines
1010 B
TypeScript
/**
|
|
* Localised "8h 12m" duration label.
|
|
*
|
|
* Three components (the sleep-stage stacked bar, the sleep source-discrepancy
|
|
* marker, the measurement list) carried a byte-identical private helper that
|
|
* branched `locale === "de"` between "8 Std. 12 Min." and "8h 12m". That is a
|
|
* de/en binary, so a Spanish, French, Italian or Polish reader got the English
|
|
* abbreviations next to otherwise translated copy. Lift the body here and read
|
|
* the abbreviations from the bundle so every locale gets its own convention and
|
|
* a future wording change lands once.
|
|
*/
|
|
|
|
/** Minutes total → localised duration label. Pass `t` from `useTranslations()`. */
|
|
export function formatDurationMinutes(
|
|
total: number,
|
|
t: (key: string, params?: Record<string, string | number>) => string,
|
|
): string {
|
|
const hours = Math.floor(total / 60);
|
|
const minutes = Math.round(total - hours * 60);
|
|
return hours > 0
|
|
? t("common.durationHoursMinutes", { hours, minutes })
|
|
: t("common.durationMinutes", { minutes });
|
|
}
|