feat: i18n – extract all strings and add login page language switcher #12

Closed
opened 2026-03-19 16:34:56 +01:00 by marcel · 0 comments
Owner

Goal

Complete the Paraglide i18n integration: replace all hardcoded German strings with m.*() message calls, and add a language switcher to the login page so users can choose their locale before logging in.


Login page language switcher (Option B — top-right corner)

Place DE / EN / ES text buttons in the top-right corner of the login page, matching the existing header switcher exactly (same font, same active/inactive styling). The buttons are absolutely positioned so they don't affect the card layout.

┌─────────────────────────────────────┐
│                          DE  EN  ES │  ← top-right
│                                     │
│         Familienarchiv              │
│   ┌──────────────────────────┐      │
│   │  Anmelden                │      │
│   │  Benutzername __________ │      │
│   │  Passwort     __________ │      │
│   │  [Anmelden]              │      │
│   └──────────────────────────┘      │
│                                     │
│         Familienarchiv              │  ← footer
└─────────────────────────────────────┘

Styling reference (from +layout.svelte):

{#each locales as locale}
    <button type="button" onclick={() => setLocale(localeMap[locale])}
        class="text-xs font-sans tracking-widest px-1.5 py-1 transition-colors
            {activeLocale === locale ? 'font-bold text-brand-navy' : 'font-normal text-gray-400 hover:text-brand-navy'}">
        {locale}
    </button>
{/each}

String extraction scope

Replace every hardcoded string in all route files with m.*() calls. Priority order:

  1. +layout.svelte — nav links, logout button
  2. +page.svelte (home) — search placeholder, filter labels, empty state, document card fields
  3. documents/[id]/+page.svelte — detail view labels
  4. documents/[id]/edit/+page.svelte — form labels, save/cancel buttons
  5. documents/new/+page.svelte — same as edit
  6. persons/ routes — list, detail, new
  7. admin/ routes — user/group/tag management
  8. login/+page.svelte — form labels (Benutzername, Passwort, Anmelden)
  9. conversations/ routes

Translation files to keep in sync: messages/de.json, messages/en.json, messages/es.json


Acceptance criteria

  • Language switcher visible in top-right corner of /login, same style as header
  • Switching language on the login page persists after login (cookie already handled by Paraglide middleware)
  • All visible German strings in all routes replaced with m.*() calls
  • All keys present in de.json, en.json, and es.json
  • npm run check passes with 0 errors
  • Existing unit tests still pass
## Goal Complete the Paraglide i18n integration: replace all hardcoded German strings with `m.*()` message calls, and add a language switcher to the login page so users can choose their locale before logging in. --- ## Login page language switcher (Option B — top-right corner) Place DE / EN / ES text buttons in the **top-right corner** of the login page, matching the existing header switcher exactly (same font, same active/inactive styling). The buttons are absolutely positioned so they don't affect the card layout. ``` ┌─────────────────────────────────────┐ │ DE EN ES │ ← top-right │ │ │ Familienarchiv │ │ ┌──────────────────────────┐ │ │ │ Anmelden │ │ │ │ Benutzername __________ │ │ │ │ Passwort __________ │ │ │ │ [Anmelden] │ │ │ └──────────────────────────┘ │ │ │ │ Familienarchiv │ ← footer └─────────────────────────────────────┘ ``` **Styling reference** (from `+layout.svelte`): ```svelte {#each locales as locale} <button type="button" onclick={() => setLocale(localeMap[locale])} class="text-xs font-sans tracking-widest px-1.5 py-1 transition-colors {activeLocale === locale ? 'font-bold text-brand-navy' : 'font-normal text-gray-400 hover:text-brand-navy'}"> {locale} </button> {/each} ``` --- ## String extraction scope Replace every hardcoded string in all route files with `m.*()` calls. Priority order: 1. `+layout.svelte` — nav links, logout button 2. `+page.svelte` (home) — search placeholder, filter labels, empty state, document card fields 3. `documents/[id]/+page.svelte` — detail view labels 4. `documents/[id]/edit/+page.svelte` — form labels, save/cancel buttons 5. `documents/new/+page.svelte` — same as edit 6. `persons/` routes — list, detail, new 7. `admin/` routes — user/group/tag management 8. `login/+page.svelte` — form labels (Benutzername, Passwort, Anmelden) 9. `conversations/` routes Translation files to keep in sync: `messages/de.json`, `messages/en.json`, `messages/es.json` --- ## Acceptance criteria - [ ] Language switcher visible in top-right corner of `/login`, same style as header - [ ] Switching language on the login page persists after login (cookie already handled by Paraglide middleware) - [ ] All visible German strings in all routes replaced with `m.*()` calls - [ ] All keys present in `de.json`, `en.json`, and `es.json` - [ ] `npm run check` passes with 0 errors - [ ] Existing unit tests still pass
Sign in to join this conversation.
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#12