Files
HealthLog/docs/audit/v1415-i18n-coverage.md
T
Marc-André BombeckandClaude Opus 4.7 a1cf9bcb37 docs: scrub PII + internal jargon + German leaks from user-facing artifacts
Retroactive cleanup of CHANGELOG.md and docs/audit/v1.4.X-summary.md
files. Removes maintainer's real name, specific health figures tied to
the live tenant, internal release-process jargon, and stray German
strings in English-only release notes. Pre-release PII-grep gate added
to the v1.4.20 release pipeline. No git history rewrite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 15:14:28 +02:00

6.4 KiB
Raw Blame History

v1.4.15 — i18n coverage audit

Date: 2026-05-09 Stage: C4 Scope: every t("…") / useTranslations() call in src/ vs. messages/en.json and messages/de.json. Goal: ensure every v1.4.15-introduced key (cleanup A1–A4, B-mobile, B1–B6, C2, C3) has a non-empty, non-placeholder translation in BOTH locales and follows the namespace conventions baked in by the Stage 4b admin reorg.

Method

  1. grep -rh -oE 't\("[a-zA-Z][a-zA-Z0-9_.-]*"' src/ — extract every call-site key (1318 unique).
  2. Walk both JSON files manually (no JSON.parse, since duplicate keys silently shadow earlier values) — same parser used by the existing i18n-locale-integrity.test.ts.
  3. Compare:
    • drift: keys in EN but not DE, or vice versa
    • empty: value === ""
    • placeholders: value === keyLastSegment, or /\b(TODO|FIXME|XXX|TBD)\b/i
  4. Cross-locale identical strings checked per-namespace — many are legitimate (brand names, ICU placeholder strings, anglicisms used in DE) so the heuristic only flagged for review, not auto-fix.

Findings

Check Count Notes
Total keys (EN) 1817
Total keys (DE) 1817
Keys only in EN 0 full parity
Keys only in DE 0 full parity
Empty values (EN) 0
Empty values (DE) 0
TODO/FIXME placeholders (EN) 0
TODO/FIXME placeholders (DE) 0
Used-in-src/ but missing in EN 0 after excluding allow-list below
EN==key (last segment, both EN+DE) 5 all legitimate (see §Legitimate)

Allow-list — used-key matches that are NOT i18n keys

These appeared in the grep but are deliberately excluded:

  • job.* — Wide Event names passed to withBackgroundEvent("job.x"), not i18n.
  • scheduler.tick — Wide Event name.
  • empty.measurements.* — JSDoc @example block in src/components/ui/empty-state.tsx, never executed.
  • settings.testConnection.errors. — dynamic concat root in src/components/settings/test-connection-button.tsx. Concrete error-codes (generic, credentials_rejected, timeout, …) are all present.
  • nope.also.missing, telegram.__definitely_missing__ — vitest fixtures asserting fallback behaviour (src/lib/__tests__/server-translator.test.ts).

Legitimate EN==DE==key cases

5 entries where both locales return the key's last segment unchanged:

Path Value Reason
settings.ntfy ntfy brand name, not translated
classifications.bp.Optimal Optimal identical word in EN and DE
classifications.bp.Normal Normal identical
classifications.pulse.Normal Normal identical
classifications.bodyFat.Fitness Fitness identical (anglicism in DE medical/fitness context)

A further 25 entries are EN==key but DE has an actual translation (classifications.bmi.Underweight → Untergewicht, etc.) — these are fine.

v1.4.15 new namespaces — coverage check

Namespace Origin EN keys DE keys Drift Empty
admin.section.backups.* B1 backups 35 35 0 0
achievements.* B4 106 106 0 0
onboarding.tour.* B5 18 18 0 0
admin.overview.* A2 16 16 0 0
settings.notificationStatus.* B3 13 13 0 0
settings.integrationStatus.* B2 6 6 0 0
doctorReport.* B6 90 90 0 0
quickAdd.* (common.add etc) A3 (common) — 0 0

Naming consistency

Repo doc note: Stage 4b moved admin keys under admin.section.<slug>.*. Verified all v1.4.15-introduced admin sections follow that pattern:

admin.section.{system-status,general,services,integrations,
              feedback,reminders,users,api-tokens,login-overview,
              backups,danger-zone}

Pre-Phase-4b legacy keys remain at the flat admin.* namespace (e.g. admin.bugReportRepo, admin.userManagement) — those are out of scope for this audit (renaming would touch many components for zero behavioural gain). New stage-B code did NOT introduce inconsistent flat keys; e.g. B5 used onboarding.tour.* (not tour.*); B4 used achievements.* (not flat badges.*); B1 used admin.section.backups.* (not flat backups.*); B2/B3 added settings.{integrationStatus,notificationStatus}.* under the existing settings umbrella.

Outcome

Zero gaps closed. The five parallel stage-B work-streams and the C2/C3 stages each added their own EN+DE translations as part of their own commits, so by the time C4 ran sequentially after Batch 2 there was nothing left to back-fill. The audit instead converted to a quality-assurance sweep: tightening i18n-locale-integrity.test.ts to lock in the non-empty + non-placeholder invariants going forward.

Test guard

src/lib/__tests__/i18n-locale-integrity.test.ts is extended with:

  • assertion that no value in either locale file is the empty string
  • assertion that no value equals its key's last segment (with an explicit allow-list for the 5 legitimate cases above)
  • non-fatal warning (logged via console.warn in CI) for values containing \bTODO\b / \bFIXME\b / \bXXX\b

These guards prevent regression: any future change that ships a "key": "" or "bugReport": "bugReport" value will see CI go red.