Show preset wish names in the current UI language

Preset wishes were created with `name: t(preset.labelKey)`, so the
translated string was persisted as the wish's name. A wish created while
the UI was Swedish stayed "Jul" in English forever -- the Swedish text
was the data, so no display-layer change could fix it.

Wish names are user-editable free text, so `name` cannot simply be
translated at render time. Migration 007 adds a nullable
`leave_wish.name_message_key` recording where a name came from: preset
wishes store the i18n key alongside the translated literal, and the UI
renders the key when present.

The key is cleared server-side the moment `name` actually changes,
compared against the stored value rather than trusting the caller, so no
client can forget to clear it and silently revert a user's own name to a
preset label.

An unknown key (a stale row, a renamed key) falls back to the stored
literal via an isTranslationKey guard, so a bad key can never crash the
page or leak a raw key to the user. Rows predating this column keep
displaying their stored name.

_FULL_SCHEMA in db/connection.py is updated in step with the migration.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RXMhc9nT6sNz1SL4j8dznL
This commit is contained in:
2026-09-14 22:32:54 +02:00
parent b03462066e
commit dc4c0a5edd
20 changed files with 668 additions and 17 deletions
+4
View File
@@ -206,6 +206,7 @@ interface RawLeaveWish {
workspace_id: string
child_id: string | null
name: string
name_message_key: string | null
window_start_month: number
window_start_day: number
window_end_month: number
@@ -229,6 +230,7 @@ function toLeaveWish(raw: RawLeaveWish): LeaveWish {
workspaceId: raw.workspace_id,
childId: raw.child_id,
name: raw.name,
nameMessageKey: raw.name_message_key,
windowStartMonth: raw.window_start_month,
windowStartDay: raw.window_start_day,
windowEndMonth: raw.window_end_month,
@@ -757,6 +759,7 @@ export async function createLeaveWish(payload: LeaveWishCreateRequest): Promise<
workspace_id: payload.workspaceId,
child_id: payload.childId ?? null,
name: payload.name,
name_message_key: payload.nameMessageKey ?? null,
window_start_month: payload.windowStartMonth,
window_start_day: payload.windowStartDay,
window_end_month: payload.windowEndMonth,
@@ -782,6 +785,7 @@ export async function updateLeaveWish(
const body: Record<string, unknown> = {}
if (payload.childId !== undefined) body.child_id = payload.childId
if (payload.name !== undefined) body.name = payload.name
if (payload.nameMessageKey !== undefined) body.name_message_key = payload.nameMessageKey
if (payload.windowStartMonth !== undefined) body.window_start_month = payload.windowStartMonth
if (payload.windowStartDay !== undefined) body.window_start_day = payload.windowStartDay
if (payload.windowEndMonth !== undefined) body.window_end_month = payload.windowEndMonth