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:
@@ -0,0 +1,51 @@
|
||||
"""Add leave_wish.name_message_key (nullable i18n key for preset names).
|
||||
|
||||
Bug: `WishEditor.tsx` created preset wishes (Sommar/Jullov/Höstlov/...) with
|
||||
`name` set to the already-translated string (e.g. "Jul"), persisted as-is.
|
||||
Switching the UI language afterwards could never fix a wish's name, because
|
||||
the Swedish (or English) text was the data, not a rendering choice.
|
||||
|
||||
Fix: `name_message_key` stores the i18n key that produced `name` at creation
|
||||
time (e.g. "wishEditor.seasonJul"), alongside the translated `name` so
|
||||
anything reading `name` directly (backend, exports, ...) still gets a sane
|
||||
value. The frontend re-translates via the key when present and falls back to
|
||||
the literal `name` otherwise. Nullable and no default: every existing row
|
||||
(and any row created by a free-typed custom name) has no key and must keep
|
||||
showing its stored `name` unchanged — see `LeaveWishService.update`, which
|
||||
also force-clears the key the moment a user edits `name`.
|
||||
|
||||
Revision ID: 007
|
||||
Revises: 006
|
||||
Create Date: 2026-09-14
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from alembic import op
|
||||
|
||||
revision: str = "007"
|
||||
down_revision: str | None = "006"
|
||||
branch_labels: str | None = None
|
||||
depends_on: str | None = None
|
||||
|
||||
_UPGRADE_SQL = """
|
||||
ALTER TABLE leave_wish ADD COLUMN name_message_key TEXT;
|
||||
"""
|
||||
|
||||
_DOWNGRADE_SQL = """
|
||||
ALTER TABLE leave_wish DROP COLUMN name_message_key;
|
||||
"""
|
||||
|
||||
|
||||
def upgrade() -> None:
|
||||
from sqlalchemy import text
|
||||
|
||||
for stmt in [s.strip() for s in _UPGRADE_SQL.split(";") if s.strip()]:
|
||||
op.execute(text(stmt))
|
||||
|
||||
|
||||
def downgrade() -> None:
|
||||
from sqlalchemy import text
|
||||
|
||||
for stmt in [s.strip() for s in _DOWNGRADE_SQL.split(";") if s.strip()]:
|
||||
op.execute(text(stmt))
|
||||
Reference in New Issue
Block a user