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:
@@ -18,6 +18,11 @@ class LeaveWishCreate(BaseModel):
|
||||
workspace_id: UUID
|
||||
child_id: UUID | None = None
|
||||
name: str = Field(min_length=1, max_length=255)
|
||||
# i18n message key when `name` came from a preset (e.g.
|
||||
# "wishEditor.presetSommar") — see app/entities/leave_wish.py. Stored
|
||||
# alongside the translated `name` so the frontend can re-translate it;
|
||||
# not validated against a key catalogue here (that's a frontend concern).
|
||||
name_message_key: str | None = Field(default=None, max_length=255)
|
||||
|
||||
window_start_month: int = Field(ge=1, le=12)
|
||||
window_start_day: int = Field(ge=1, le=31)
|
||||
@@ -46,6 +51,11 @@ class LeaveWishUpdate(BaseModel):
|
||||
|
||||
child_id: UUID | None = None
|
||||
name: str | None = Field(None, min_length=1, max_length=255)
|
||||
# Present + null in the payload means "clear it"; absent means "leave
|
||||
# unchanged" (see `model_fields_set` handling in the router). The service
|
||||
# also clears this automatically whenever `name` actually changes, so a
|
||||
# caller can never forget to and leave a stale key pointing at old text.
|
||||
name_message_key: str | None = Field(default=None, max_length=255)
|
||||
|
||||
window_start_month: int | None = Field(None, ge=1, le=12)
|
||||
window_start_day: int | None = Field(None, ge=1, le=31)
|
||||
@@ -71,6 +81,7 @@ class LeaveWishResponse(BaseModel):
|
||||
workspace_id: UUID
|
||||
child_id: UUID | None
|
||||
name: str
|
||||
name_message_key: str | None
|
||||
|
||||
window_start_month: int
|
||||
window_start_day: int
|
||||
@@ -100,6 +111,7 @@ class LeaveWishResponse(BaseModel):
|
||||
workspace_id=entity.workspace_id,
|
||||
child_id=entity.child_id,
|
||||
name=entity.name,
|
||||
name_message_key=entity.name_message_key,
|
||||
window_start_month=entity.window_start_month,
|
||||
window_start_day=entity.window_start_day,
|
||||
window_end_month=entity.window_end_month,
|
||||
|
||||
Reference in New Issue
Block a user