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>
6.4 KiB
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
grep -rh -oE 't\("[a-zA-Z][a-zA-Z0-9_.-]*"' src/— extract every call-site key (1318 unique).- Walk both JSON files manually (no
JSON.parse, since duplicate keys silently shadow earlier values) — same parser used by the existingi18n-locale-integrity.test.ts. - Compare:
- drift: keys in EN but not DE, or vice versa
- empty:
value === "" - placeholders:
value === keyLastSegment, or/\b(TODO|FIXME|XXX|TBD)\b/i
- 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 towithBackgroundEvent("job.x"), not i18n.scheduler.tick— Wide Event name.empty.measurements.*— JSDoc@exampleblock insrc/components/ui/empty-state.tsx, never executed.settings.testConnection.errors.— dynamic concat root insrc/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.warnin 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.