i18n(todo/settings): translate +page.svelte via $_() — all 6 sections + reset

- Page <title>, header h1, back-link aria
- Task Behavior: section heading, default-priority label + 4 options (priorityLow/Medium/High/Urgent), default-due-time label, auto-archive label + description
- View & Display: section heading, default-view label + 4 options (Inbox/Heute/Anstehend/Kanban), 4 toggle labels (Kompaktmodus/Aufgabenzahl/Teilaufgaben-Fortschritt/Nach Projekt gruppieren) with descriptions; converted 'as size' to 'as const as size' to silence Svelte 5 narrowing
- Kanban Board: section heading, Kartengröße label + 3 size labels (Kompakt/Normal/Groß), Labels-on-cards label, WIP-limit label + description
- Smart Duration: section heading, smartDurationEnabled label + description, defaultTaskDuration label
- Notifications: section heading, defaultReminder label + 6 options (Keine/5/15/30/1h/1d), 2 toggle labels (Tägliche Zusammenfassung/Überfällig)
- Productivity: section heading, 4 toggle labels with descriptions (Fokus-Modus/Pomodoro/Streak/Immersiver Modus), Tagesziel label
- Reset button + 'Alle Todo-Einstellungen zurücksetzen?' confirm

Baselines: hardcoded 1205 → 1192 (13 cleared); missing-keys baseline unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-27 12:49:46 +02:00
parent fbc06132f2
commit 753230c2e6
2 changed files with 51 additions and 44 deletions

View file

@ -7,6 +7,7 @@
import type { TaskPriority } from '$lib/modules/todo/types';
import { ArrowLeft } from '@mana/shared-icons';
import { RoutePage } from '$lib/components/shell';
import { _ } from 'svelte-i18n';
function toggle(key: string) {
todoSettings.update({ [key]: !todoSettings.settings[key] });
@ -14,7 +15,7 @@
</script>
<svelte:head>
<title>Todo Einstellungen - Mana</title>
<title>{$_('todo.settings.pageTitle')}</title>
</svelte:head>
<RoutePage appId="todo" backHref="/todo">
@ -22,39 +23,40 @@
<header class="mb-6 flex items-center gap-3">
<a
href="/todo"
aria-label={$_('todo.settings.backAria')}
class="flex h-8 w-8 items-center justify-center rounded-lg text-muted-foreground hover:bg-muted"
>
<ArrowLeft size={18} />
</a>
<h1 class="text-2xl font-bold text-foreground">Todo Einstellungen</h1>
<h1 class="text-2xl font-bold text-foreground">{$_('todo.settings.title')}</h1>
</header>
<div class="space-y-6">
<!-- Task Behavior -->
<section class="rounded-xl border border-border bg-card p-5">
<h2 class="mb-4 text-sm font-semibold uppercase tracking-wider text-muted-foreground">
Aufgaben-Verhalten
{$_('todo.settings.taskBehavior')}
</h2>
<div class="space-y-4">
<div class="flex items-center justify-between">
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">Standard-Priorität</label>
<label class="text-sm text-foreground">{$_('todo.settings.defaultPriority')}</label>
<select
value={todoSettings.defaultPriority}
onchange={(e) =>
todoSettings.update({ defaultPriority: e.currentTarget.value as TaskPriority })}
class="rounded-md border border-border bg-background px-3 py-1.5 text-sm focus:border-primary focus:outline-none"
>
<option value="low">Niedrig</option>
<option value="medium">Mittel</option>
<option value="high">Hoch</option>
<option value="urgent">Dringend</option>
<option value="low">{$_('todo.priorityLow')}</option>
<option value="medium">{$_('todo.priorityMedium')}</option>
<option value="high">{$_('todo.priorityHigh')}</option>
<option value="urgent">{$_('todo.priorityUrgent')}</option>
</select>
</div>
<div class="flex items-center justify-between">
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">Standard-Fälligkeitszeit</label>
<label class="text-sm text-foreground">{$_('todo.settings.defaultDueTime')}</label>
<input
type="time"
value={todoSettings.settings.defaultDueTime ?? ''}
@ -69,9 +71,9 @@
<div class="flex items-center justify-between">
<div>
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">Auto-Archivierung</label>
<label class="text-sm text-foreground">{$_('todo.settings.autoArchive')}</label>
<p class="text-xs text-muted-foreground">
Erledigte Aufgaben nach X Tagen archivieren
{$_('todo.settings.descAutoArchive')}
</p>
</div>
<input
@ -94,25 +96,25 @@
<!-- View & Display -->
<section class="rounded-xl border border-border bg-card p-5">
<h2 class="mb-4 text-sm font-semibold uppercase tracking-wider text-muted-foreground">
Ansicht & Darstellung
{$_('todo.settings.viewDisplay')}
</h2>
<div class="space-y-4">
<div class="flex items-center justify-between">
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">Standard-Ansicht</label>
<label class="text-sm text-foreground">{$_('todo.settings.defaultView')}</label>
<select
value={todoSettings.defaultView}
onchange={(e) => todoSettings.update({ defaultView: e.currentTarget.value as any })}
class="rounded-md border border-border bg-background px-3 py-1.5 text-sm focus:border-primary focus:outline-none"
>
<option value="inbox">Inbox</option>
<option value="today">Heute</option>
<option value="upcoming">Anstehend</option>
<option value="kanban">Kanban</option>
<option value="inbox">{$_('todo.settings.viewInbox')}</option>
<option value="today">{$_('todo.settings.viewToday')}</option>
<option value="upcoming">{$_('todo.settings.viewUpcoming')}</option>
<option value="kanban">{$_('todo.settings.viewKanban')}</option>
</select>
</div>
{#each [{ key: 'compactMode', label: 'Kompaktmodus', desc: 'Weniger Abstand zwischen Aufgaben' }, { key: 'showTaskCounts', label: 'Aufgabenzahl', desc: 'Anzahl der Aufgaben anzeigen' }, { key: 'showSubtaskProgress', label: 'Teilaufgaben-Fortschritt', desc: 'Fortschritt der Subtasks anzeigen' }, { key: 'groupByProject', label: 'Nach Projekt gruppieren', desc: 'Aufgaben nach Projekt gruppieren' }] as toggle_item}
{#each [{ key: 'compactMode', label: $_('todo.settings.compactMode'), desc: $_('todo.settings.descCompactMode') }, { key: 'showTaskCounts', label: $_('todo.settings.showTaskCounts'), desc: $_('todo.settings.descShowTaskCounts') }, { key: 'showSubtaskProgress', label: $_('todo.settings.showSubtaskProgress'), desc: $_('todo.settings.descShowSubtaskProgress') }, { key: 'groupByProject', label: $_('todo.settings.groupByProject'), desc: $_('todo.settings.descGroupByProject') }] as toggle_item}
<div class="flex items-center justify-between">
<!-- svelte-ignore a11y_consider_explicit_label -->
<div>
@ -144,14 +146,14 @@
<!-- Kanban Board -->
<section class="rounded-xl border border-border bg-card p-5">
<h2 class="mb-4 text-sm font-semibold uppercase tracking-wider text-muted-foreground">
Kanban Board
{$_('todo.settings.kanbanSettings')}
</h2>
<div class="space-y-4">
<div class="flex items-center justify-between">
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">Kartengröße</label>
<label class="text-sm text-foreground">{$_('todo.settings.cardSize')}</label>
<div class="flex gap-1">
{#each ['compact', 'normal', 'large'] as size}
{#each ['compact', 'normal', 'large'] as const as size}
<button
onclick={() => todoSettings.update({ kanbanCardSize: size as KanbanCardSize })}
class="rounded-md px-3 py-1.5 text-xs font-medium transition-colors
@ -159,7 +161,11 @@
? 'bg-primary/10 text-primary'
: 'text-muted-foreground hover:bg-muted'}"
>
{size === 'compact' ? 'Kompakt' : size === 'normal' ? 'Normal' : 'Groß'}
{size === 'compact'
? $_('todo.settings.cardSizeCompact')
: size === 'normal'
? $_('todo.settings.cardSizeNormal')
: $_('todo.settings.cardSizeLarge')}
</button>
// svelte-ignore a11y_consider_explicit_label
{/each}
@ -168,7 +174,7 @@
<div class="flex items-center justify-between">
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">Labels auf Karten</label>
<label class="text-sm text-foreground">{$_('todo.settings.showLabelsOnCards')}</label>
<!-- svelte-ignore a11y_consider_explicit_label -->
<button
onclick={() => toggle('showLabelsOnCards')}
@ -187,8 +193,8 @@
<div class="flex items-center justify-between">
<div>
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">WIP-Limit pro Spalte</label>
<p class="text-xs text-muted-foreground">Maximum Aufgaben pro Spalte</p>
<label class="text-sm text-foreground">{$_('todo.settings.wipLimit')}</label>
<p class="text-xs text-muted-foreground">{$_('todo.settings.descWipLimit')}</p>
</div>
<input
type="number"
@ -208,16 +214,18 @@
<!-- Smart Duration -->
<section class="rounded-xl border border-border bg-card p-5">
<h2 class="mb-4 text-sm font-semibold uppercase tracking-wider text-muted-foreground">
Smarte Dauer
{$_('todo.settings.smartDuration')}
</h2>
<!-- svelte-ignore a11y_consider_explicit_label -->
<div class="space-y-4">
<div class="flex items-center justify-between">
<div>
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">Smarte Dauer-Schätzung</label>
<label class="text-sm text-foreground"
>{$_('todo.settings.smartDurationEnabled')}</label
>
<p class="text-xs text-muted-foreground">
Dauer automatisch basierend auf ähnlichen Aufgaben schätzen
{$_('todo.settings.descSmartDuration')}
</p>
</div>
<button
@ -236,7 +244,7 @@
<div class="flex items-center justify-between">
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">Standard-Dauer (Minuten)</label>
<label class="text-sm text-foreground">{$_('todo.settings.defaultTaskDuration')}</label>
<input
type="number"
min="5"
@ -253,12 +261,12 @@
<!-- Notifications -->
<section class="rounded-xl border border-border bg-card p-5">
<h2 class="mb-4 text-sm font-semibold uppercase tracking-wider text-muted-foreground">
Benachrichtigungen
{$_('todo.settings.notifications')}
</h2>
<div class="space-y-4">
<div class="flex items-center justify-between">
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">Standard-Erinnerung</label>
<label class="text-sm text-foreground">{$_('todo.settings.defaultReminder')}</label>
<select
value={todoSettings.settings.defaultReminderMinutes ?? ''}
onchange={(e) =>
@ -269,17 +277,17 @@
})}
class="rounded-md border border-border bg-background px-3 py-1.5 text-sm focus:border-primary focus:outline-none"
>
<option value="">Keine</option>
<option value="">{$_('todo.settings.reminderNone')}</option>
<!-- svelte-ignore a11y_consider_explicit_label -->
<option value="5">5 Min</option>
<option value="15">15 Min</option>
<option value="30">30 Min</option>
<option value="60">1 Std</option>
<option value="1440">1 Tag</option>
<option value="5">{$_('todo.settings.reminder5')}</option>
<option value="15">{$_('todo.settings.reminder15')}</option>
<option value="30">{$_('todo.settings.reminder30')}</option>
<option value="60">{$_('todo.settings.reminder1h')}</option>
<option value="1440">{$_('todo.settings.reminder1d')}</option>
</select>
</div>
{#each [{ key: 'dailyDigestEnabled', label: 'Tägliche Zusammenfassung' }, { key: 'overdueNotifications', label: 'Überfällig-Benachrichtigungen' }] as item}
{#each [{ key: 'dailyDigestEnabled', label: $_('todo.settings.dailyDigest') }, { key: 'overdueNotifications', label: $_('todo.settings.overdueNotifications') }] as item}
<div class="flex items-center justify-between">
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">{item.label}</label>
@ -308,10 +316,10 @@
<!-- Productivity -->
<section class="rounded-xl border border-border bg-card p-5">
<h2 class="mb-4 text-sm font-semibold uppercase tracking-wider text-muted-foreground">
Produktivität
{$_('todo.settings.productivity')}
</h2>
<div class="space-y-4">
{#each [{ key: 'focusMode', label: 'Fokus-Modus', desc: 'Ablenkungen minimieren' }, { key: 'pomodoroEnabled', label: 'Pomodoro', desc: 'Pomodoro-Timer integrieren' }, { key: 'showStreak', label: 'Streak anzeigen', desc: 'Tägliche Erledigungsserie' }, { key: 'immersiveModeEnabled', label: 'Immersiver Modus', desc: 'Navigation ausblenden' }] as item}
{#each [{ key: 'focusMode', label: $_('todo.settings.focusMode'), desc: $_('todo.settings.descFocusMode') }, { key: 'pomodoroEnabled', label: $_('todo.settings.pomodoro'), desc: $_('todo.settings.descPomodoro') }, { key: 'showStreak', label: $_('todo.settings.showStreak'), desc: $_('todo.settings.descShowStreak') }, { key: 'immersiveModeEnabled', label: $_('todo.settings.immersiveMode'), desc: $_('todo.settings.descImmersiveMode') }] as item}
<div class="flex items-center justify-between">
<div>
<!-- svelte-ignore a11y_label_has_associated_control -->
@ -338,7 +346,7 @@
<div class="flex items-center justify-between">
<!-- svelte-ignore a11y_label_has_associated_control -->
<label class="text-sm text-foreground">Tagesziel (Aufgaben)</label>
<label class="text-sm text-foreground">{$_('todo.settings.dailyGoal')}</label>
<input
type="number"
min="0"
@ -358,13 +366,13 @@
<div class="flex justify-end pb-8">
<button
onclick={() => {
if (confirm('Alle Todo-Einstellungen zurücksetzen?')) {
if (confirm($_('todo.settings.confirmReset'))) {
todoSettings.reset();
}
}}
class="rounded-md px-4 py-2 text-sm text-red-500 transition-colors hover:bg-red-500/10"
>
Einstellungen zurücksetzen
{$_('todo.settings.reset')}
</button>
</div>
</div>

View file

@ -327,7 +327,6 @@
"apps/mana/apps/web/src/routes/(app)/times/clock/+page.svelte": 1,
"apps/mana/apps/web/src/routes/(app)/times/projects/[id]/+page.svelte": 3,
"apps/mana/apps/web/src/routes/(app)/todo/+page.svelte": 1,
"apps/mana/apps/web/src/routes/(app)/todo/settings/+page.svelte": 13,
"apps/mana/apps/web/src/routes/(app)/wetter/+page.svelte": 2,
"apps/mana/apps/web/src/routes/(auth)/reset-password/+page.svelte": 1,
"apps/mana/apps/web/src/routes/+error.svelte": 1,