mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-13 14:32:03 +00:00
Largest feature delta in the v1.4.x line. Insights expands into seven dedicated metric sub-pages; GLP-1 medication tracking lands end-to-end (drug-level chart with Research Mode acknowledgment, EMA titration ladder, cadence + compliance, side-effect taxonomy, pen/vial inventory); cross-source priority becomes a two-axis resolver; per-user timezone threads through ten analytics surfaces; Withings activity + sleep v2 sync; onboarding rebuilt as a nested-route wizard; Personal Records ship end-to-end; Health Score provenance accordion; Coach runs native first-party prompts across six locales with a 1800-assertion refusal-probe matrix; OpenAPI drift gate hard-fails; multi-arch GHCR image. Migrations 0043 through 0060 are additive and forward-only. PROMPT_VERSION 4.24.0 → 4.25.0 with GROUND RULE 9 (refuses dose recommendations) and GROUND RULE 15 (refuses drug-level estimates with MDR + MDCG 2021-24 cites). See CHANGELOG.md for the full per-section delta.
64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
import deMessages from "../../../messages/de.json";
|
|
import enMessages from "../../../messages/en.json";
|
|
import frMessages from "../../../messages/fr.json";
|
|
import esMessages from "../../../messages/es.json";
|
|
import itMessages from "../../../messages/it.json";
|
|
import plMessages from "../../../messages/pl.json";
|
|
import { defaultLocale, type Locale } from "./config";
|
|
|
|
const allMessages: Record<Locale, Record<string, unknown>> = {
|
|
de: deMessages,
|
|
en: enMessages,
|
|
fr: frMessages,
|
|
es: esMessages,
|
|
it: itMessages,
|
|
pl: plMessages,
|
|
};
|
|
|
|
function resolveKey(
|
|
messages: Record<string, unknown>,
|
|
key: string,
|
|
): string | undefined {
|
|
const parts = key.split(".");
|
|
let current: unknown = messages;
|
|
for (const part of parts) {
|
|
if (current && typeof current === "object" && part in current) {
|
|
current = (current as Record<string, unknown>)[part];
|
|
} else {
|
|
return undefined;
|
|
}
|
|
}
|
|
return typeof current === "string" ? current : undefined;
|
|
}
|
|
|
|
export interface ServerTranslator {
|
|
locale: Locale;
|
|
t(key: string, params?: Record<string, string | number>): string;
|
|
}
|
|
|
|
/**
|
|
* Server-side translator that reads the same messages/{en,de}.json bundles
|
|
* the client uses. Falls back to English, then to the raw key.
|
|
*
|
|
* Use this from API routes / background jobs where useTranslations() is not
|
|
* available. Mirrors the behaviour of the client I18nProvider.
|
|
*/
|
|
export function getServerTranslator(locale: Locale): ServerTranslator {
|
|
return {
|
|
locale,
|
|
t(key, params) {
|
|
let value = resolveKey(allMessages[locale], key);
|
|
if (value === undefined && locale !== defaultLocale) {
|
|
value = resolveKey(allMessages[defaultLocale], key);
|
|
}
|
|
if (value === undefined) return key;
|
|
if (params) {
|
|
for (const [k, v] of Object.entries(params)) {
|
|
value = value.replace(new RegExp(`\\{${k}\\}`, "g"), String(v));
|
|
}
|
|
}
|
|
return value;
|
|
},
|
|
};
|
|
}
|