i18n(library): wire DetailView to namespace — 16 strings cleared

Patches all action labels, kind/status/format pills (routed through
dynamic library.kinds.*, library.statuses.*, library.book_formats.*),
detail dt/dd pairs, restart label, times badge, review section.
constants.ts kept with literal {de,en} maps for non-Svelte callers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-27 01:39:25 +02:00
parent 099cac4a01
commit 36d832a3db
3 changed files with 65 additions and 39 deletions

View file

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import { goto } from '$app/navigation'; import { goto } from '$app/navigation';
import { _ } from 'svelte-i18n';
import { import {
VisibilityPicker, VisibilityPicker,
SharedLinkControls, SharedLinkControls,
@ -10,7 +11,7 @@
import RatingStars from '../components/RatingStars.svelte'; import RatingStars from '../components/RatingStars.svelte';
import EntryForm from '../components/EntryForm.svelte'; import EntryForm from '../components/EntryForm.svelte';
import ProgressControls from '../components/ProgressControls.svelte'; import ProgressControls from '../components/ProgressControls.svelte';
import { KIND_LABELS, STATUS_LABELS, BOOK_FORMAT_LABELS } from '../constants'; import { KIND_LABELS } from '../constants';
import { libraryEntriesStore } from '../stores/entries.svelte'; import { libraryEntriesStore } from '../stores/entries.svelte';
import type { LibraryEntry, LibraryStatus } from '../types'; import type { LibraryEntry, LibraryStatus } from '../types';
@ -55,7 +56,8 @@
} }
async function onDelete() { async function onDelete() {
if (!confirm(`Eintrag "${entry.title}" wirklich löschen?`)) return; if (!confirm($_('library.detail_view.confirm_delete', { values: { title: entry.title } })))
return;
await libraryEntriesStore.deleteEntry(entry.id); await libraryEntriesStore.deleteEntry(entry.id);
goto('/library'); goto('/library');
} }
@ -64,19 +66,15 @@
await libraryEntriesStore.restartEntry(entry.id); await libraryEntriesStore.restartEntry(entry.id);
} }
const restartLabel = $derived.by(() => { const restartLabel = $derived(
switch (entry.kind) { entry.kind === 'book' || entry.kind === 'comic'
case 'book': ? $_('library.detail_view.restart_read')
case 'comic': : $_('library.detail_view.restart_watch')
return 'Nochmal lesen'; );
default:
return 'Nochmal sehen';
}
});
</script> </script>
<div class="detail"> <div class="detail">
<a href="/library" class="back">← Zurück zur Bibliothek</a> <a href="/library" class="back">{$_('library.detail_view.action_back')}</a>
{#if editing} {#if editing}
<EntryForm mode="edit" initial={entry} onclose={() => (editing = false)} /> <EntryForm mode="edit" initial={entry} onclose={() => (editing = false)} />
@ -86,17 +84,24 @@
<CoverImage url={entry.coverUrl} kind={entry.kind} alt={entry.title} size="lg" /> <CoverImage url={entry.coverUrl} kind={entry.kind} alt={entry.title} size="lg" />
<div class="cover-actions"> <div class="cover-actions">
<button type="button" onclick={() => (editing = true)} class="primary"> <button type="button" onclick={() => (editing = true)} class="primary">
Bearbeiten {$_('library.detail_view.action_edit')}
</button> </button>
<button <button
type="button" type="button"
onclick={onToggleFavorite} onclick={onToggleFavorite}
class="icon-btn" class="icon-btn"
aria-label={entry.isFavorite ? 'Favorit entfernen' : 'Favorisieren'} aria-label={entry.isFavorite
? $_('library.detail_view.action_unfavorite')
: $_('library.detail_view.action_favorite')}
> >
{entry.isFavorite ? '★' : '☆'} {entry.isFavorite ? '★' : '☆'}
</button> </button>
<button type="button" onclick={onDelete} class="icon-btn danger" aria-label="Löschen"> <button
type="button"
onclick={onDelete}
class="icon-btn danger"
aria-label={$_('library.detail_view.action_delete')}
>
🗑 🗑
</button> </button>
</div> </div>
@ -105,7 +110,7 @@
<div class="meta-col"> <div class="meta-col">
<div class="kind-pill"> <div class="kind-pill">
{KIND_LABELS[entry.kind].emoji} {KIND_LABELS[entry.kind].emoji}
{KIND_LABELS[entry.kind].de} {$_('library.kinds.' + entry.kind)}
</div> </div>
<h1>{entry.title}</h1> <h1>{entry.title}</h1>
{#if entry.originalTitle && entry.originalTitle !== entry.title} {#if entry.originalTitle && entry.originalTitle !== entry.title}
@ -128,7 +133,7 @@
class:active={entry.status === s} class:active={entry.status === s}
onclick={() => onStatusChange(s)} onclick={() => onStatusChange(s)}
> >
{STATUS_LABELS[s].de} {$_('library.statuses.' + s)}
</button> </button>
{/each} {/each}
</div> </div>
@ -137,8 +142,15 @@
<div class="times-row"> <div class="times-row">
{#if entry.times > 0} {#if entry.times > 0}
<span class="times"> <span class="times">
{entry.kind === 'book' || entry.kind === 'comic' ? 'Gelesen' : 'Gesehen'}: {$_('library.detail_view.times_value', {
{entry.times}× values: {
label:
entry.kind === 'book' || entry.kind === 'comic'
? $_('library.detail_view.times_read')
: $_('library.detail_view.times_seen'),
count: entry.times,
},
})}
</span> </span>
{/if} {/if}
{#if entry.status === 'completed'} {#if entry.status === 'completed'}
@ -161,12 +173,12 @@
{/if} {/if}
<dl class="details"> <dl class="details">
<dt>Sichtbarkeit</dt> <dt>{$_('library.detail_view.label_visibility')}</dt>
<dd> <dd>
<VisibilityPicker level={entry.visibility} onChange={onVisibilityChange} /> <VisibilityPicker level={entry.visibility} onChange={onVisibilityChange} />
</dd> </dd>
{#if entry.visibility === 'unlisted' && entry.unlistedToken && shareUrl} {#if entry.visibility === 'unlisted' && entry.unlistedToken && shareUrl}
<dt>Link</dt> <dt>{$_('library.detail_view.label_link')}</dt>
<dd> <dd>
<SharedLinkControls <SharedLinkControls
token={entry.unlistedToken} token={entry.unlistedToken}
@ -180,59 +192,73 @@
{/if} {/if}
{#if entry.details.kind === 'book'} {#if entry.details.kind === 'book'}
{#if entry.details.pages} {#if entry.details.pages}
<dt>Seiten</dt> <dt>{$_('library.detail_view.label_pages')}</dt>
<dd> <dd>
{entry.details.currentPage {entry.details.currentPage
? `${entry.details.currentPage} / ${entry.details.pages}` ? $_('library.detail_view.pages_value', {
values: {
current: entry.details.currentPage,
total: entry.details.pages,
},
})
: entry.details.pages} : entry.details.pages}
</dd> </dd>
{/if} {/if}
{#if entry.details.format} {#if entry.details.format}
<dt>Format</dt> <dt>{$_('library.detail_view.label_format')}</dt>
<dd>{BOOK_FORMAT_LABELS[entry.details.format].de}</dd> <dd>{$_('library.book_formats.' + entry.details.format)}</dd>
{/if} {/if}
{:else if entry.details.kind === 'movie'} {:else if entry.details.kind === 'movie'}
{#if entry.details.runtimeMin} {#if entry.details.runtimeMin}
<dt>Laufzeit</dt> <dt>{$_('library.detail_view.label_runtime')}</dt>
<dd>{entry.details.runtimeMin} min</dd> <dd>
{$_('library.detail_view.runtime_value', {
values: { minutes: entry.details.runtimeMin },
})}
</dd>
{/if} {/if}
{#if entry.details.director} {#if entry.details.director}
<dt>Regie</dt> <dt>{$_('library.detail_view.label_director')}</dt>
<dd>{entry.details.director}</dd> <dd>{entry.details.director}</dd>
{/if} {/if}
{:else if entry.details.kind === 'series'} {:else if entry.details.kind === 'series'}
{#if entry.details.totalSeasons} {#if entry.details.totalSeasons}
<dt>Staffeln</dt> <dt>{$_('library.detail_view.label_seasons')}</dt>
<dd>{entry.details.totalSeasons}</dd> <dd>{entry.details.totalSeasons}</dd>
{/if} {/if}
{#if entry.details.totalEpisodes} {#if entry.details.totalEpisodes}
<dt>Episoden</dt> <dt>{$_('library.detail_view.label_episodes')}</dt>
<dd>{entry.details.totalEpisodes}</dd> <dd>{entry.details.totalEpisodes}</dd>
{/if} {/if}
{:else if entry.details.kind === 'comic'} {:else if entry.details.kind === 'comic'}
{#if entry.details.publisher} {#if entry.details.publisher}
<dt>Verlag</dt> <dt>{$_('library.detail_view.label_publisher')}</dt>
<dd>{entry.details.publisher}</dd> <dd>{entry.details.publisher}</dd>
{/if} {/if}
{#if entry.details.issueCount} {#if entry.details.issueCount}
<dt>Ausgaben</dt> <dt>{$_('library.detail_view.label_issues')}</dt>
<dd> <dd>
{entry.details.currentIssue {entry.details.currentIssue
? `${entry.details.currentIssue} / ${entry.details.issueCount}` ? $_('library.detail_view.pages_value', {
values: {
current: entry.details.currentIssue,
total: entry.details.issueCount,
},
})
: entry.details.issueCount} : entry.details.issueCount}
</dd> </dd>
{/if} {/if}
{#if entry.details.isOngoing} {#if entry.details.isOngoing}
<dt>Status</dt> <dt>{$_('library.detail_view.label_status')}</dt>
<dd>laufend</dd> <dd>{$_('library.detail_view.status_ongoing')}</dd>
{/if} {/if}
{/if} {/if}
{#if entry.startedAt} {#if entry.startedAt}
<dt>Gestartet</dt> <dt>{$_('library.detail_view.label_started')}</dt>
<dd>{entry.startedAt}</dd> <dd>{entry.startedAt}</dd>
{/if} {/if}
{#if entry.completedAt} {#if entry.completedAt}
<dt>Fertig</dt> <dt>{$_('library.detail_view.label_completed')}</dt>
<dd>{entry.completedAt}</dd> <dd>{entry.completedAt}</dd>
{/if} {/if}
</dl> </dl>
@ -241,7 +267,7 @@
{#if entry.review} {#if entry.review}
<section class="review"> <section class="review">
<h2>Review</h2> <h2>{$_('library.detail_view.section_review')}</h2>
<p>{entry.review}</p> <p>{entry.review}</p>
</section> </section>
{/if} {/if}

View file

@ -137,7 +137,6 @@
"apps/mana/apps/web/src/lib/modules/library/components/EntryForm.svelte": 5, "apps/mana/apps/web/src/lib/modules/library/components/EntryForm.svelte": 5,
"apps/mana/apps/web/src/lib/modules/library/components/ProgressControls.svelte": 3, "apps/mana/apps/web/src/lib/modules/library/components/ProgressControls.svelte": 3,
"apps/mana/apps/web/src/lib/modules/library/ListView.svelte": 1, "apps/mana/apps/web/src/lib/modules/library/ListView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/library/views/DetailView.svelte": 16,
"apps/mana/apps/web/src/lib/modules/library/views/GridView.svelte": 2, "apps/mana/apps/web/src/lib/modules/library/views/GridView.svelte": 2,
"apps/mana/apps/web/src/lib/modules/mail/ListView.svelte": 8, "apps/mana/apps/web/src/lib/modules/mail/ListView.svelte": 8,
"apps/mana/apps/web/src/lib/modules/meditate/components/SessionPlayer.svelte": 3, "apps/mana/apps/web/src/lib/modules/meditate/components/SessionPlayer.svelte": 3,

View file

@ -10,6 +10,7 @@
"apps/mana/apps/web/src/lib/modules/invoices/constants.ts": 1, "apps/mana/apps/web/src/lib/modules/invoices/constants.ts": 1,
"apps/mana/apps/web/src/lib/modules/invoices/ListView.svelte": 1, "apps/mana/apps/web/src/lib/modules/invoices/ListView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/invoices/views/DetailView.svelte": 1, "apps/mana/apps/web/src/lib/modules/invoices/views/DetailView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/library/views/DetailView.svelte": 3,
"apps/mana/apps/web/src/lib/modules/period/ListView.svelte": 1, "apps/mana/apps/web/src/lib/modules/period/ListView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/plants/ListView.svelte": 5, "apps/mana/apps/web/src/lib/modules/plants/ListView.svelte": 5,
"apps/mana/apps/web/src/lib/modules/quotes/components/QuoteCard.svelte": 4, "apps/mana/apps/web/src/lib/modules/quotes/components/QuoteCard.svelte": 4,