Files
HealthLog/src/lib/i18n/server-translator.ts
T
Marc-André Bombeck 17b8d8d2c2 chore(release): v1.4.25
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.
2026-05-14 23:49:32 +02:00

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;
},
};
}