feat: implement i18n — extract all UI strings, add EN + ES-MX translations, add language selector
Extract all hardcoded German strings from every .svelte file and component into Paraglide message keys. Add complete translations for all keys in messages/en.json (English) and messages/es.json (Spanish/Mexico). Changes: - messages/de.json: 100+ keys covering navigation, buttons, form labels, placeholders, section headings, empty states, and error messages - messages/en.json, messages/es.json: complete translations for all keys - project.inlang/settings.json: change baseLocale from "en" to "de" - +layout.svelte: add DE/EN/ES language selector in header using setLocale(); active language is bold, choice persists via Paraglide cookie strategy - All 10 route pages + 3 shared components: replace hardcoded German with m.key() - e2e/lang.spec.ts: E2E tests for language selector visibility, switching, persistence across navigation, and active state highlighting Closes #2 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit was merged in pull request #9.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
import { goto } from '$app/navigation';
|
||||
import PersonTypeahead from '$lib/components/PersonTypeahead.svelte';
|
||||
import { untrack } from 'svelte';
|
||||
import { m } from '$lib/paraglide/messages.js';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
@@ -39,9 +40,9 @@
|
||||
<div class="max-w-5xl mx-auto py-10 px-4">
|
||||
<!-- Page Header -->
|
||||
<div class="mb-8 border-b border-brand-navy/10 pb-4">
|
||||
<h1 class="text-3xl font-serif font-medium text-brand-navy">Konversationen</h1>
|
||||
<h1 class="text-3xl font-serif font-medium text-brand-navy">{m.conv_heading()}</h1>
|
||||
<p class="text-brand-navy/60 font-sans text-sm mt-2">
|
||||
Verfolgen Sie den Schriftverkehr zwischen zwei Personen chronologisch.
|
||||
{m.conv_subtitle()}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -54,7 +55,7 @@
|
||||
>
|
||||
<PersonTypeahead
|
||||
name="senderId"
|
||||
label="Person A (Absender)"
|
||||
label={m.conv_label_person_a()}
|
||||
bind:value={senderId}
|
||||
initialName={data.initialValues.senderName}
|
||||
onchange={() => applyFilters()}
|
||||
@@ -67,7 +68,7 @@
|
||||
>
|
||||
<PersonTypeahead
|
||||
name="receiverId"
|
||||
label="Person B (Empfänger)"
|
||||
label={m.conv_label_person_b()}
|
||||
bind:value={receiverId}
|
||||
initialName={data.initialValues.receiverName}
|
||||
onchange={() => applyFilters()}
|
||||
@@ -81,7 +82,7 @@
|
||||
<label
|
||||
for="dateFrom"
|
||||
class="block text-xs font-bold uppercase tracking-widest text-gray-500 mb-2"
|
||||
>Zeitraum von</label
|
||||
>{m.conv_label_from()}</label
|
||||
>
|
||||
<input
|
||||
id="dateFrom"
|
||||
@@ -97,7 +98,7 @@
|
||||
<label
|
||||
for="dateTo"
|
||||
class="block text-xs font-bold uppercase tracking-widest text-gray-500 mb-2"
|
||||
>Zeitraum bis</label
|
||||
>{m.conv_label_to()}</label
|
||||
>
|
||||
<input
|
||||
id="dateTo"
|
||||
@@ -114,8 +115,8 @@
|
||||
onclick={toggleSort}
|
||||
class="w-full flex items-center justify-center h-[42px] border border-brand-sand text-xs font-bold uppercase tracking-wide text-brand-navy hover:bg-brand-navy hover:text-white transition-colors"
|
||||
>
|
||||
<span class="mr-2">Sortierung:</span>
|
||||
<span>{sortDir === 'DESC' ? 'Neueste zuerst' : 'Älteste zuerst'}</span>
|
||||
<span class="mr-2">{m.conv_sort_label()}</span>
|
||||
<span>{sortDir === 'DESC' ? m.conv_sort_newest() : m.conv_sort_oldest()}</span>
|
||||
<svg
|
||||
class="w-4 h-4 ml-2 transform {sortDir === 'ASC'
|
||||
? 'rotate-180'
|
||||
@@ -147,15 +148,15 @@
|
||||
/></svg
|
||||
>
|
||||
</div>
|
||||
<p class="text-brand-navy font-serif text-lg">Wählen Sie zwei Personen aus</p>
|
||||
<p class="text-gray-500 font-sans text-sm mt-1">Die Korrespondenz wird hier angezeigt.</p>
|
||||
<p class="text-brand-navy font-serif text-lg">{m.conv_empty_heading()}</p>
|
||||
<p class="text-gray-500 font-sans text-sm mt-1">{m.conv_empty_text()}</p>
|
||||
</div>
|
||||
{:else if data.documents.length === 0}
|
||||
<div
|
||||
class="flex flex-col items-center justify-center py-24 bg-white border border-brand-sand rounded-sm text-center shadow-sm"
|
||||
>
|
||||
<p class="text-brand-navy font-serif">Keine Dokumente gefunden.</p>
|
||||
<p class="text-gray-400 text-sm mt-2">Versuchen Sie, den Zeitraum anzupassen.</p>
|
||||
<p class="text-brand-navy font-serif">{m.conv_no_results_heading()}</p>
|
||||
<p class="text-gray-400 text-sm mt-2">{m.conv_no_results_text()}</p>
|
||||
</div>
|
||||
{:else}
|
||||
<!-- CHAT CONTAINER -->
|
||||
|
||||
Reference in New Issue
Block a user