mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 22:01:09 +02:00
i18n(todo): translate views/DetailView via $_() — title, prop rows, sections, meta
- Shell labels: notFound + confirmDelete
- Title input placeholder + Untitled fallback (was hardcoded English 'Untitled')
- Prop rows: Sichtbarkeit / Priorität (todo.priority) / Fällig (todo.dueDate) / Dauer (todo.duration) / Kalender labels
- Priority options routed via priorityKeys map → todo.priorityLow/Medium/High/Urgent
- Duration value with {n} interpolation, calendar Planen button + unschedule aria
- Tags / Beschreibung section labels (existing top-level keys)
- Subtasks count interpolation ({done}/{total})
- Meta footer Erstellt/Bearbeitet with {date} interpolation
- Toast undo "Aufgabe gelöscht"
Baselines: hardcoded 1042 → 1034 (8 cleared); missing-keys baseline unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4f2a36e96d
commit
1931739aac
7 changed files with 48 additions and 26 deletions
|
|
@ -89,6 +89,7 @@
|
|||
"layoutFocus": "Fokus"
|
||||
},
|
||||
"detailView": {
|
||||
"labelVisibility": "Sichtbarkeit",
|
||||
"notFound": "Aufgabe nicht gefunden",
|
||||
"confirmDelete": "Aufgabe wirklich löschen?",
|
||||
"toastDeleted": "Aufgabe gelöscht",
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
"layoutFocus": "Focus"
|
||||
},
|
||||
"detailView": {
|
||||
"labelVisibility": "Visibility",
|
||||
"notFound": "Task not found",
|
||||
"confirmDelete": "Really delete task?",
|
||||
"toastDeleted": "Task deleted",
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
"layoutFocus": "Enfoque"
|
||||
},
|
||||
"detailView": {
|
||||
"labelVisibility": "Visibilidad",
|
||||
"notFound": "Tarea no encontrada",
|
||||
"confirmDelete": "¿Eliminar realmente la tarea?",
|
||||
"toastDeleted": "Tarea eliminada",
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
"layoutFocus": "Focus"
|
||||
},
|
||||
"detailView": {
|
||||
"labelVisibility": "Visibilité",
|
||||
"notFound": "Tâche introuvable",
|
||||
"confirmDelete": "Vraiment supprimer la tâche ?",
|
||||
"toastDeleted": "Tâche supprimée",
|
||||
|
|
|
|||
|
|
@ -89,6 +89,7 @@
|
|||
"layoutFocus": "Focus"
|
||||
},
|
||||
"detailView": {
|
||||
"labelVisibility": "Visibilità",
|
||||
"notFound": "Attività non trovata",
|
||||
"confirmDelete": "Eliminare davvero l'attività?",
|
||||
"toastDeleted": "Attività eliminata",
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
import LinkedItems from '$lib/components/links/LinkedItems.svelte';
|
||||
import { toastStore } from '@mana/shared-ui/toast';
|
||||
import { removeTagIdWithUndo } from '$lib/data/tag-mutations';
|
||||
import { _ } from 'svelte-i18n';
|
||||
|
||||
let { navigate, params, goBack }: ViewProps = $props();
|
||||
let taskId = $derived(params.taskId as string);
|
||||
|
|
@ -84,7 +85,7 @@
|
|||
async function saveField() {
|
||||
detail.blur();
|
||||
await tasksStore.updateTask(taskId, {
|
||||
title: editTitle.trim() || detail.entity?.title || 'Untitled',
|
||||
title: editTitle.trim() || detail.entity?.title || $_('todo.detailView.untitledFallback'),
|
||||
description: editDescription.trim() || undefined,
|
||||
dueDate: editDueDate ? new Date(editDueDate).toISOString() : null,
|
||||
priority: editPriority,
|
||||
|
|
@ -139,16 +140,16 @@
|
|||
const id = taskId;
|
||||
await tasksStore.deleteTask(id);
|
||||
goBack();
|
||||
toastStore.undo('Aufgabe gelöscht', () => {
|
||||
toastStore.undo($_('todo.detailView.toastDeleted'), () => {
|
||||
db.table('tasks').update(id, { deletedAt: undefined });
|
||||
});
|
||||
}
|
||||
|
||||
const priorityLabels: Record<TaskPriority, string> = {
|
||||
low: 'Niedrig',
|
||||
medium: 'Mittel',
|
||||
high: 'Hoch',
|
||||
urgent: 'Dringend',
|
||||
const priorityKeys: Record<TaskPriority, string> = {
|
||||
low: 'todo.priorityLow',
|
||||
medium: 'todo.priorityMedium',
|
||||
high: 'todo.priorityHigh',
|
||||
urgent: 'todo.priorityUrgent',
|
||||
};
|
||||
|
||||
const priorityColors: Record<TaskPriority, string> = {
|
||||
|
|
@ -162,11 +163,11 @@
|
|||
<DetailViewShell
|
||||
entity={detail.entity}
|
||||
loading={detail.loading}
|
||||
notFoundLabel="Aufgabe nicht gefunden"
|
||||
notFoundLabel={$_('todo.detailView.notFound')}
|
||||
confirmDelete={detail.confirmDelete}
|
||||
onAskDelete={detail.askDelete}
|
||||
onCancelDelete={detail.cancelDelete}
|
||||
confirmDeleteLabel="Aufgabe wirklich löschen?"
|
||||
confirmDeleteLabel={$_('todo.detailView.confirmDelete')}
|
||||
onConfirmDelete={deleteTask}
|
||||
>
|
||||
{#snippet body(task)}
|
||||
|
|
@ -182,18 +183,18 @@
|
|||
bind:value={editTitle}
|
||||
onfocus={detail.focus}
|
||||
onblur={saveField}
|
||||
placeholder="Titel..."
|
||||
placeholder={$_('todo.detailView.placeholderTitle')}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="properties">
|
||||
<div class="prop-row">
|
||||
<span class="prop-label">Sichtbarkeit</span>
|
||||
<span class="prop-label">{$_('todo.detailView.labelVisibility')}</span>
|
||||
<VisibilityPicker level={task.visibility ?? 'private'} onChange={handleVisibilityChange} />
|
||||
</div>
|
||||
|
||||
<div class="prop-row">
|
||||
<span class="prop-label">Priorität</span>
|
||||
<span class="prop-label">{$_('todo.priority')}</span>
|
||||
<select
|
||||
class="prop-select"
|
||||
bind:value={editPriority}
|
||||
|
|
@ -201,13 +202,13 @@
|
|||
style="color: {priorityColors[editPriority]}"
|
||||
>
|
||||
{#each ['low', 'medium', 'high', 'urgent'] as const as p}
|
||||
<option value={p}>{priorityLabels[p]}</option>
|
||||
<option value={p}>{$_(priorityKeys[p])}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="prop-row">
|
||||
<span class="prop-label">Fällig</span>
|
||||
<span class="prop-label">{$_('todo.dueDate')}</span>
|
||||
<input
|
||||
type="date"
|
||||
class="prop-input"
|
||||
|
|
@ -219,13 +220,17 @@
|
|||
|
||||
{#if task.estimatedDuration}
|
||||
<div class="prop-row">
|
||||
<span class="prop-label">Dauer</span>
|
||||
<span class="prop-value">{Math.round(task.estimatedDuration / 60)} Min.</span>
|
||||
<span class="prop-label">{$_('todo.duration')}</span>
|
||||
<span class="prop-value"
|
||||
>{$_('todo.detailView.durationMin', {
|
||||
values: { n: Math.round(task.estimatedDuration / 60) },
|
||||
})}</span
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="prop-row">
|
||||
<span class="prop-label">Kalender</span>
|
||||
<span class="prop-label">{$_('todo.detailView.labelCalendar')}</span>
|
||||
{#if isScheduled}
|
||||
<div class="schedule-fields">
|
||||
<input
|
||||
|
|
@ -245,7 +250,7 @@
|
|||
<button
|
||||
class="unschedule-btn"
|
||||
onclick={toggleSchedule}
|
||||
aria-label="Vom Kalender entfernen"
|
||||
aria-label={$_('todo.detailView.unscheduleAria')}
|
||||
>
|
||||
<X size={12} />
|
||||
</button>
|
||||
|
|
@ -254,7 +259,7 @@
|
|||
<div class="schedule-options">
|
||||
<button class="schedule-btn" onclick={toggleSchedule}>
|
||||
<CalendarBlank size={14} />
|
||||
Planen
|
||||
{$_('todo.detailView.labelSchedule')}
|
||||
</button>
|
||||
<SlotSuggestions
|
||||
minDurationMinutes={task.estimatedDuration
|
||||
|
|
@ -274,7 +279,7 @@
|
|||
|
||||
{#if taskTags.length > 0}
|
||||
<div class="section">
|
||||
<span class="section-label">Tags</span>
|
||||
<span class="section-label">{$_('todo.tags')}</span>
|
||||
<div class="tags-list">
|
||||
{#each taskTags as tag (tag.id)}
|
||||
<button
|
||||
|
|
@ -294,13 +299,13 @@
|
|||
<LinkedItems recordRef={{ app: 'todo', collection: 'tasks', id: taskId }} {navigate} />
|
||||
|
||||
<div class="section">
|
||||
<span class="section-label">Beschreibung</span>
|
||||
<span class="section-label">{$_('todo.description')}</span>
|
||||
<textarea
|
||||
class="description-input"
|
||||
bind:value={editDescription}
|
||||
onfocus={detail.focus}
|
||||
onblur={saveField}
|
||||
placeholder="Beschreibung hinzufügen..."
|
||||
placeholder={$_('todo.detailView.placeholderDescription')}
|
||||
rows={3}
|
||||
></textarea>
|
||||
</div>
|
||||
|
|
@ -308,7 +313,12 @@
|
|||
{#if task.subtasks && task.subtasks.length > 0}
|
||||
<div class="section">
|
||||
<span class="section-label">
|
||||
Unteraufgaben ({task.subtasks.filter((s) => s.isCompleted).length}/{task.subtasks.length})
|
||||
{$_('todo.detailView.sectionSubtasks', {
|
||||
values: {
|
||||
done: task.subtasks.filter((s) => s.isCompleted).length,
|
||||
total: task.subtasks.length,
|
||||
},
|
||||
})}
|
||||
</span>
|
||||
<div class="subtask-list">
|
||||
{#each task.subtasks as subtask (subtask.id)}
|
||||
|
|
@ -326,9 +336,17 @@
|
|||
{/if}
|
||||
|
||||
<div class="meta">
|
||||
<span>Erstellt: {formatDate(new Date(task.createdAt ?? ''))}</span>
|
||||
<span
|
||||
>{$_('todo.detailView.metaCreated', {
|
||||
values: { date: formatDate(new Date(task.createdAt ?? '')) },
|
||||
})}</span
|
||||
>
|
||||
{#if task.updatedAt}
|
||||
<span>Bearbeitet: {formatDate(new Date(task.updatedAt))}</span>
|
||||
<span
|
||||
>{$_('todo.detailView.metaUpdated', {
|
||||
values: { date: formatDate(new Date(task.updatedAt)) },
|
||||
})}</span
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
{/snippet}
|
||||
|
|
|
|||
|
|
@ -191,7 +191,6 @@
|
|||
"apps/mana/apps/web/src/lib/modules/todo/components/pages/TodoPage.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/modules/todo/components/SyncIndicator.svelte": 4,
|
||||
"apps/mana/apps/web/src/lib/modules/todo/ListView.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/modules/todo/views/DetailView.svelte": 8,
|
||||
"apps/mana/apps/web/src/lib/modules/wetter/components/CurrentConditions.svelte": 2,
|
||||
"apps/mana/apps/web/src/lib/modules/wetter/components/HourlyForecast.svelte": 1,
|
||||
"apps/mana/apps/web/src/lib/modules/wetter/components/LocationPicker.svelte": 5,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue