mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 05:42:19 +00:00
fix(i18n): address the ru review — units, Cyrillic regexes, locale registry
Dose bank
- DRUG_UNIT learns мг / мкг / мл / ЕД / МЕ, so "2,4 мг" anchors a dose again.
- The bank matches verb-first Russian word order too ("принимайте 2 таблетки",
"пропустите дозу метформина", "начните с 5 мг"), and the Cyrillic drug names
people actually see on the box; the deferral words ("спросите врача",
"как назначено") stand those shapes down.
Cyrillic-safe regexes
- \w and \b are ASCII in JavaScript: every stem in the ru bank and in
population-norms/ru.ts is [а-яё]*, and the word edges are lookarounds
(?<![а-яёa-z]), so «высокий риск» and «нормальный диапазон» match again.
- coach-prose-grounding: Russian month names in the genitive, a space as the
thousands separator in parseLocaleNumber and numFrag, and Cyrillic-safe
edges around the written-date pattern.
Registered everywhere a locale has to be
- targetLanguageName() returns "Russian", so the coach, the period narrative
and the document descriptions stop saying "write in English".
- i18n-key-tool.mjs, split-description.mjs, LOINC name normalisation (it
stripped Cyrillic, so no Russian lab name resolved), HOST_TLDS (ru/by/kz/ua),
no-key-fallbacks (32 tables), country-label, the AUDIT-C standard drink.
- docs/api/openapi.yaml regenerated.
Questionnaires
- The PHQ-9 / GAD-7 source comments no longer claim no validated Russian
version exists (Zolotareva 2023; Pfizer's official screeners).
- WHO-5 items are gender-neutral: «чувствовал(а)».
- "body fat" and "fat mass" both read «Жировая масса»; body fat is now
«Процент жировой массы», which is what the two metrics measure.
Tests
- ru in the 13 locale tables, plus mood, onboarding, instruments, clinician
view, status summary, describe screen, citation coverage and LOINC.
- i18n-no-dot-separator: the ru bundle is exempt from the dash rule (a spaced
dash is Russian punctuation, not a fragment join); the middle dot still
fails there.
- Two 800-line baselines raised by the 12 and 5 lines this change adds.
pnpm typecheck, pnpm openapi:check and the full suite (36 316 tests) pass.
This commit is contained in:
1 parent
6b9d222643
commit
48bfbad4e6
44 files changed
+431
-70
No files matched your search
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$comment": "Production files over 800 lines and their length. Maintained by src/__tests__/source-size-ratchet.test.ts.",
|
||||
"count": 84,
|
||||
"total": 94362,
|
||||
"total": 94379,
|
||||
"entries": {
|
||||
"app/medications/page-client.tsx": 839,
|
||||
"components/charts/mood-chart.tsx": 1166,
|
||||
@@ -22,14 +22,14 @@
|
||||
"components/timeline/timeline-geometry.ts": 1288,
|
||||
"lib/ai/anthropic-client.ts": 804,
|
||||
"lib/ai/coach/about-me.ts": 1012,
|
||||
"lib/ai/coach/coach-prose-grounding.ts": 1079,
|
||||
"lib/ai/coach/coach-prose-grounding.ts": 1091,
|
||||
"lib/ai/coach/persistence.ts": 1218,
|
||||
"lib/ai/coach/results/metric-table-tool.ts": 1102,
|
||||
"lib/ai/coach/snapshot.ts": 1346,
|
||||
"lib/ai/coach/stream-events.ts": 817,
|
||||
"lib/ai/coach/types.ts": 1011,
|
||||
"lib/ai/codex-client.ts": 907,
|
||||
"lib/ai/prompts/insight-generator.ts": 1110,
|
||||
"lib/ai/prompts/insight-generator.ts": 1115,
|
||||
"lib/ai/provider.ts": 1628,
|
||||
"lib/analytics/score/reader.ts": 998,
|
||||
"lib/analytics/sleep-night.ts": 1345,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$comment": "Production functions over 200 lines, keyed \"file :: name\", and their length. Maintained by src/__tests__/source-size-ratchet.test.ts.",
|
||||
"count": 345,
|
||||
"total": 111929,
|
||||
"total": 111928,
|
||||
"entries": {
|
||||
"app/achievements/page.tsx :: AchievementsPage": 206,
|
||||
"app/api/admin/backups/upload/route.ts :: apiHandler(arg)": 275,
|
||||
@@ -45,7 +45,7 @@
|
||||
"app/coach/plans/page.tsx :: CoachPlansBody": 216,
|
||||
"app/insights/catalog/page.tsx :: MetricCatalogPage": 204,
|
||||
"app/insights/medications/page.tsx :: InsightsMedikamentePage": 265,
|
||||
"app/insights/page-client.tsx :: InsightsPageClient": 376,
|
||||
"app/insights/page-client.tsx :: InsightsPageClient": 375,
|
||||
"app/labs/page.tsx :: LabsPage": 228,
|
||||
"app/medications/page-client.tsx :: MedicationsPageClient": 590,
|
||||
"app/notifications/page.tsx :: NotificationsPage": 327,
|
||||
|
||||
@@ -166,7 +166,7 @@ describe("dynamic-key exhaustiveness (enum-derived)", () => {
|
||||
expect(LOCALES.length).toBeGreaterThanOrEqual(6);
|
||||
});
|
||||
|
||||
it("discovers all nine shipped locales", () => {
|
||||
it("discovers all ten shipped locales", () => {
|
||||
expect(LOCALES.map((l) => l.locale).sort()).toEqual([
|
||||
"de",
|
||||
"en",
|
||||
@@ -177,6 +177,7 @@ describe("dynamic-key exhaustiveness (enum-derived)", () => {
|
||||
"nl",
|
||||
"pl",
|
||||
"pt-BR",
|
||||
"ru",
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
@@ -30,6 +30,14 @@ const hasSeparator = (value: string) =>
|
||||
/** Key path -> why the separator is right there. Empty by intent. */
|
||||
const ALLOWED: Record<string, string> = {};
|
||||
|
||||
/**
|
||||
* Bundles where a spaced dash is punctuation the language requires rather than
|
||||
* a fragment join. Russian uses the dash where English puts a comma or a full
|
||||
* stop ("Сводка за неделю — всё спокойно"), so the ru bundle is exempt from
|
||||
* the dash rule; the middle dot is still flagged there.
|
||||
*/
|
||||
const DASH_EXEMPT_BUNDLES = new Set(["ru.json"]);
|
||||
|
||||
function flatten(
|
||||
obj: unknown,
|
||||
prefix: string,
|
||||
@@ -66,7 +74,13 @@ describe("message bundles carry no ' · ', ' — ' or ' – ' separator", () =>
|
||||
|
||||
it(`${file} has no dot or dash separator outside the allowlist`, () => {
|
||||
const offenders = [...values]
|
||||
.filter(([key, value]) => hasSeparator(value) && !(key in ALLOWED))
|
||||
.filter(([key, value]) => {
|
||||
if (!hasSeparator(value) || key in ALLOWED) return false;
|
||||
if (DASH_EXEMPT_BUNDLES.has(file) && !value.includes(" · ")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(([key, value]) => `${key} = ${JSON.stringify(value)}`);
|
||||
expect(offenders).toEqual([]);
|
||||
});
|
||||
|
||||
Reference in new issue
Block a user