Root cause: applyTranslations() in client/i18n.ts unconditionally overwrote
textContent/placeholder/title with t(key), and t() falls back to the raw key
name when no translation exists. Result: every projekte.* data-i18n attr in
the v2 pages rendered the literal key string ('projekte.heading',
'projekte.subtitle', ...) because I shipped the pages with new i18n keys
without adding the translations.
Two fixes, both in client/i18n.ts:
1. **Fallback behaviour**: applyTranslations() now uses a new internal
tOrEmpty(key) that returns '' when the key is missing in DE and EN,
and the call site only overwrites the DOM when the lookup yielded a
real value. Missing keys no longer clobber the author-provided default
text. This is belt-and-braces for any future page that ships a key
before its translation does.
2. **Missing translations added**: ~90 projekte.* keys for DE and EN,
covering the list page (projekte.heading/subtitle/new/search/filter.*/
view.*/col.*/empty.*/unavailable), the create form (projekte.neu.*,
projekte.field.*, projekte.cancel/submit/error.*), and the detail page
(projekte.detail.title/back/loading/notfound/edit/save, tab.* for all
eight tabs, verlauf.*, team.form.*/col.*, kinder.*, parteien.*
form/role/col/empty, fristen.*, termine.*, checklisten.*, delete.*).
go build/vet/test + bun run build all clean.