mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-16 23:59:39 +02:00
feat(zitare): complete i18n coverage for all pages
Extract ~40 hardcoded German strings into de.json/en.json locale files. Covers favorites, lists, list detail, search, and settings pages including toasts, modals, form labels, empty states, and aria labels. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
cf9cbebd34
commit
90e6135637
7 changed files with 209 additions and 72 deletions
|
|
@ -43,13 +43,62 @@
|
|||
"favorites": {
|
||||
"title": "Favoriten",
|
||||
"empty": "Noch keine Favoriten",
|
||||
"emptyDescription": "Tippe auf das Herz-Symbol, um Zitate zu speichern"
|
||||
"emptyDescription": "Tippe auf das Herz-Symbol, um Zitate zu speichern",
|
||||
"loginPrompt": "Melde dich an, um Favoriten zu speichern",
|
||||
"removeFromFavorites": "Aus Favoriten entfernen",
|
||||
"copyQuote": "Zitat kopieren",
|
||||
"share": "Teilen"
|
||||
},
|
||||
"lists": {
|
||||
"title": "Meine Listen",
|
||||
"create": "Neue Liste",
|
||||
"empty": "Noch keine Listen",
|
||||
"emptyDescription": "Erstelle Listen, um Zitate zu organisieren"
|
||||
"emptyDescription": "Erstelle Listen, um Zitate zu organisieren",
|
||||
"loginPrompt": "Melde dich an, um Listen zu erstellen",
|
||||
"quoteCount": "{count} Zitate",
|
||||
"createModal": {
|
||||
"title": "Neue Liste erstellen",
|
||||
"namePlaceholder": "z.B. Motivierende Zitate",
|
||||
"descriptionPlaceholder": "Was macht diese Liste besonders?",
|
||||
"submit": "Erstellen"
|
||||
},
|
||||
"nameLabel": "Name",
|
||||
"descriptionLabel": "Beschreibung (optional)",
|
||||
"confirmDelete": "Möchtest du diese Liste wirklich löschen?",
|
||||
"detail": {
|
||||
"notFound": "Liste nicht gefunden",
|
||||
"notFoundDescription": "Diese Liste existiert nicht oder wurde gelöscht.",
|
||||
"backToLists": "Zurück zu Listen",
|
||||
"breadcrumb": "Listen",
|
||||
"lastEdited": "Zuletzt bearbeitet: {date}",
|
||||
"searchPlaceholder": "Zitate durchsuchen...",
|
||||
"emptyTitle": "Keine Zitate in dieser Liste",
|
||||
"emptyDescription": "Füge Zitate hinzu, um deine Sammlung zu starten",
|
||||
"addQuotes": "Zitate hinzufügen",
|
||||
"remove": "Entfernen",
|
||||
"removeConfirm": "Zitat aus dieser Liste entfernen?",
|
||||
"noSearchResults": "Keine Ergebnisse",
|
||||
"noSearchResultsDescription": "Versuche es mit anderen Suchbegriffen",
|
||||
"floatingResults": "{filtered} von {total} Zitaten",
|
||||
"editModal": {
|
||||
"title": "Liste bearbeiten",
|
||||
"deleteList": "Liste löschen"
|
||||
},
|
||||
"addModal": {
|
||||
"title": "Zitate hinzufügen",
|
||||
"selected": "{count} ausgewählt",
|
||||
"submit": "Hinzufügen ({count})"
|
||||
},
|
||||
"toast": {
|
||||
"updated": "Liste aktualisiert!",
|
||||
"updateError": "Fehler beim Aktualisieren",
|
||||
"deleted": "Liste gelöscht",
|
||||
"deleteError": "Fehler beim Löschen",
|
||||
"quotesAdded": "{count} {count, plural, one {Zitat} other {Zitate}} hinzugefügt!",
|
||||
"quoteRemoved": "Zitat entfernt",
|
||||
"removeError": "Fehler beim Entfernen"
|
||||
}
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"title": "Suche",
|
||||
|
|
@ -59,7 +108,16 @@
|
|||
"searching": "Suche...",
|
||||
"create": "Erstellen",
|
||||
"createList": "als Liste erstellen",
|
||||
"createListDescription": "Neue Liste mit diesem Namen erstellen"
|
||||
"createListDescription": "Neue Liste mit diesem Namen erstellen",
|
||||
"minChars": "Bitte gib mindestens 2 Zeichen ein",
|
||||
"hint": "Suche nach Zitaten, Autoren oder Themen"
|
||||
},
|
||||
"settings": {
|
||||
"quoteLanguage": "Zitat-Sprache",
|
||||
"quoteLanguageDescription": "Wähle die Sprache, in der die Zitate angezeigt werden sollen.",
|
||||
"about": "Über Zitare",
|
||||
"aboutDescription": "Zitare bietet dir täglich inspirierende Zitate von den größten Denkern der Geschichte. Speichere deine Favoriten und erstelle eigene Listen.",
|
||||
"stats": "{quotes} Zitate · {categories} Kategorien · {languages} Sprachen"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Anmelden",
|
||||
|
|
@ -77,6 +135,9 @@
|
|||
"save": "Speichern",
|
||||
"cancel": "Abbrechen",
|
||||
"delete": "Löschen",
|
||||
"edit": "Bearbeiten"
|
||||
"edit": "Bearbeiten",
|
||||
"close": "Schließen",
|
||||
"search": "Suchen",
|
||||
"list": "Liste"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,13 +43,62 @@
|
|||
"favorites": {
|
||||
"title": "Favorites",
|
||||
"empty": "No favorites yet",
|
||||
"emptyDescription": "Tap the heart icon to save quotes"
|
||||
"emptyDescription": "Tap the heart icon to save quotes",
|
||||
"loginPrompt": "Sign in to save favorites",
|
||||
"removeFromFavorites": "Remove from favorites",
|
||||
"copyQuote": "Copy quote",
|
||||
"share": "Share"
|
||||
},
|
||||
"lists": {
|
||||
"title": "My Lists",
|
||||
"create": "New List",
|
||||
"empty": "No lists yet",
|
||||
"emptyDescription": "Create lists to organize quotes"
|
||||
"emptyDescription": "Create lists to organize quotes",
|
||||
"loginPrompt": "Sign in to create lists",
|
||||
"quoteCount": "{count} quotes",
|
||||
"createModal": {
|
||||
"title": "Create new list",
|
||||
"namePlaceholder": "e.g. Motivational Quotes",
|
||||
"descriptionPlaceholder": "What makes this list special?",
|
||||
"submit": "Create"
|
||||
},
|
||||
"nameLabel": "Name",
|
||||
"descriptionLabel": "Description (optional)",
|
||||
"confirmDelete": "Do you really want to delete this list?",
|
||||
"detail": {
|
||||
"notFound": "List not found",
|
||||
"notFoundDescription": "This list does not exist or has been deleted.",
|
||||
"backToLists": "Back to lists",
|
||||
"breadcrumb": "Lists",
|
||||
"lastEdited": "Last edited: {date}",
|
||||
"searchPlaceholder": "Search quotes...",
|
||||
"emptyTitle": "No quotes in this list",
|
||||
"emptyDescription": "Add quotes to start your collection",
|
||||
"addQuotes": "Add quotes",
|
||||
"remove": "Remove",
|
||||
"removeConfirm": "Remove quote from this list?",
|
||||
"noSearchResults": "No results",
|
||||
"noSearchResultsDescription": "Try different search terms",
|
||||
"floatingResults": "{filtered} of {total} quotes",
|
||||
"editModal": {
|
||||
"title": "Edit list",
|
||||
"deleteList": "Delete list"
|
||||
},
|
||||
"addModal": {
|
||||
"title": "Add quotes",
|
||||
"selected": "{count} selected",
|
||||
"submit": "Add ({count})"
|
||||
},
|
||||
"toast": {
|
||||
"updated": "List updated!",
|
||||
"updateError": "Error updating list",
|
||||
"deleted": "List deleted",
|
||||
"deleteError": "Error deleting list",
|
||||
"quotesAdded": "{count} {count, plural, one {quote} other {quotes}} added!",
|
||||
"quoteRemoved": "Quote removed",
|
||||
"removeError": "Error removing quote"
|
||||
}
|
||||
}
|
||||
},
|
||||
"search": {
|
||||
"title": "Search",
|
||||
|
|
@ -59,7 +108,16 @@
|
|||
"searching": "Searching...",
|
||||
"create": "Create",
|
||||
"createList": "create as list",
|
||||
"createListDescription": "Create a new list with this name"
|
||||
"createListDescription": "Create a new list with this name",
|
||||
"minChars": "Please enter at least 2 characters",
|
||||
"hint": "Search for quotes, authors, or topics"
|
||||
},
|
||||
"settings": {
|
||||
"quoteLanguage": "Quote language",
|
||||
"quoteLanguageDescription": "Choose the language in which quotes are displayed.",
|
||||
"about": "About Zitare",
|
||||
"aboutDescription": "Zitare offers you daily inspiring quotes from the greatest thinkers in history. Save your favorites and create your own lists.",
|
||||
"stats": "{quotes} quotes · {categories} categories · {languages} languages"
|
||||
},
|
||||
"auth": {
|
||||
"login": "Sign In",
|
||||
|
|
@ -77,6 +135,9 @@
|
|||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete",
|
||||
"edit": "Edit"
|
||||
"edit": "Edit",
|
||||
"close": "Close",
|
||||
"search": "Search",
|
||||
"list": "List"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@
|
|||
return [
|
||||
{
|
||||
id: 'remove-favorite',
|
||||
label: $_('favorites.removeFromFavorites', { default: 'Aus Favoriten entfernen' }),
|
||||
label: $_('favorites.removeFromFavorites'),
|
||||
variant: 'danger',
|
||||
action: () => favoritesStore.toggle(quote.id),
|
||||
},
|
||||
{ id: 'divider-1', label: '', type: 'divider' },
|
||||
{
|
||||
id: 'copy',
|
||||
label: $_('common.copyQuote', { default: 'Zitat kopieren' }),
|
||||
label: $_('favorites.copyQuote'),
|
||||
action: () => {
|
||||
const text = getQuoteText(quote);
|
||||
navigator.clipboard.writeText(`"${text}" — ${quote.author}`);
|
||||
|
|
@ -51,7 +51,7 @@
|
|||
},
|
||||
{
|
||||
id: 'share',
|
||||
label: $_('common.share', { default: 'Teilen' }),
|
||||
label: $_('favorites.share'),
|
||||
action: async () => {
|
||||
const text = `"${getQuoteText(quote)}" — ${quote.author}`;
|
||||
if (navigator.share) {
|
||||
|
|
@ -92,7 +92,7 @@
|
|||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
/>
|
||||
</svg>
|
||||
<p class="text-foreground-secondary mb-4">Melde dich an, um Favoriten zu speichern</p>
|
||||
<p class="text-foreground-secondary mb-4">{$_('favorites.loginPrompt')}</p>
|
||||
<button
|
||||
onclick={() => goto('/login')}
|
||||
class="px-6 py-2 bg-primary text-white rounded-full font-medium hover:bg-primary-hover transition-colors"
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@
|
|||
}
|
||||
|
||||
async function deleteList(listId: string) {
|
||||
if (!confirm('Möchtest du diese Liste wirklich löschen?')) return;
|
||||
if (!confirm($_('lists.confirmDelete'))) return;
|
||||
|
||||
const token = await authStore.getValidToken();
|
||||
if (!token) return;
|
||||
|
|
@ -155,7 +155,7 @@
|
|||
d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"
|
||||
/>
|
||||
</svg>
|
||||
<p class="text-foreground-secondary mb-4">Melde dich an, um Listen zu erstellen</p>
|
||||
<p class="text-foreground-secondary mb-4">{$_('lists.loginPrompt')}</p>
|
||||
<button
|
||||
onclick={() => goto('/login')}
|
||||
class="px-6 py-2 bg-primary text-white rounded-full font-medium hover:bg-primary-hover transition-colors"
|
||||
|
|
@ -205,7 +205,7 @@
|
|||
<p class="text-foreground-secondary mt-1">{list.description}</p>
|
||||
{/if}
|
||||
<p class="text-sm text-foreground-muted mt-2">
|
||||
{list.quoteIds.length} Zitate
|
||||
{$_('lists.quoteCount', { values: { count: list.quoteIds.length } })}
|
||||
</p>
|
||||
</div>
|
||||
<button
|
||||
|
|
@ -237,7 +237,7 @@
|
|||
<div class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4">
|
||||
<div class="bg-surface-elevated rounded-2xl w-full max-w-md shadow-xl">
|
||||
<div class="flex items-center justify-between p-6 border-b border-border">
|
||||
<h3 class="text-xl font-semibold text-foreground">Neue Liste erstellen</h3>
|
||||
<h3 class="text-xl font-semibold text-foreground">{$_('lists.createModal.title')}</h3>
|
||||
<button
|
||||
onclick={() => (showCreateModal = false)}
|
||||
class="p-2 text-foreground-secondary hover:text-foreground transition-colors"
|
||||
|
|
@ -254,21 +254,23 @@
|
|||
</div>
|
||||
<div class="p-6 space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-foreground mb-2">Name *</label>
|
||||
<label class="block text-sm font-medium text-foreground mb-2"
|
||||
>{$_('lists.nameLabel')} *</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
bind:value={newListName}
|
||||
placeholder="z.B. Motivierende Zitate"
|
||||
placeholder={$_('lists.createModal.namePlaceholder')}
|
||||
class="w-full p-3 rounded-lg bg-surface border border-border text-foreground focus:outline-none focus:border-primary"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-foreground mb-2"
|
||||
>Beschreibung (optional)</label
|
||||
>{$_('lists.descriptionLabel')}</label
|
||||
>
|
||||
<textarea
|
||||
bind:value={newListDescription}
|
||||
placeholder="Was macht diese Liste besonders?"
|
||||
placeholder={$_('lists.createModal.descriptionPlaceholder')}
|
||||
rows="3"
|
||||
class="w-full p-3 rounded-lg bg-surface border border-border text-foreground focus:outline-none focus:border-primary resize-none"
|
||||
></textarea>
|
||||
|
|
@ -286,7 +288,7 @@
|
|||
disabled={!newListName.trim()}
|
||||
class="px-6 py-2 bg-primary text-white rounded-lg font-medium hover:bg-primary-hover transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
Erstellen
|
||||
{$_('lists.createModal.submit')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { goto } from '$app/navigation';
|
||||
import { _ } from 'svelte-i18n';
|
||||
import { _, locale } from 'svelte-i18n';
|
||||
import { listsStore, type QuoteList } from '$lib/stores/lists.svelte';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { quotesStore } from '$lib/stores/quotes.svelte';
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
isLoading = false;
|
||||
|
||||
if (!list) {
|
||||
toast.error('Liste nicht gefunden');
|
||||
toast.error($_('lists.detail.notFound'));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -90,22 +90,22 @@
|
|||
});
|
||||
if (updated) {
|
||||
list = updated;
|
||||
toast.success('Liste aktualisiert!');
|
||||
toast.success($_('lists.detail.toast.updated'));
|
||||
closeEditModal();
|
||||
} else {
|
||||
toast.error('Fehler beim Aktualisieren');
|
||||
toast.error($_('lists.detail.toast.updateError'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDeleteList() {
|
||||
if (list && confirm('Möchtest du diese Liste wirklich löschen?')) {
|
||||
if (list && confirm($_('lists.confirmDelete'))) {
|
||||
const success = await listsStore.deleteList(list.id);
|
||||
if (success) {
|
||||
toast.info('Liste gelöscht');
|
||||
toast.info($_('lists.detail.toast.deleted'));
|
||||
goto('/lists');
|
||||
} else {
|
||||
toast.error('Fehler beim Löschen');
|
||||
toast.error($_('lists.detail.toast.deleteError'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -140,27 +140,27 @@
|
|||
if (successCount > 0) {
|
||||
// Reload list to get updated quote IDs
|
||||
list = await listsStore.getList(list.id);
|
||||
toast.success(`${successCount} ${successCount === 1 ? 'Zitat' : 'Zitate'} hinzugefügt!`);
|
||||
toast.success($_('lists.detail.toast.quotesAdded', { values: { count: successCount } }));
|
||||
}
|
||||
closeAddQuotesModal();
|
||||
}
|
||||
}
|
||||
|
||||
async function handleRemoveQuote(quoteId: string) {
|
||||
if (list && confirm('Zitat aus dieser Liste entfernen?')) {
|
||||
if (list && confirm($_('lists.detail.removeConfirm'))) {
|
||||
const success = await listsStore.removeQuoteFromList(list.id, quoteId);
|
||||
if (success) {
|
||||
// Reload list to get updated quote IDs
|
||||
list = await listsStore.getList(list.id);
|
||||
toast.info('Zitat entfernt');
|
||||
toast.info($_('lists.detail.toast.quoteRemoved'));
|
||||
} else {
|
||||
toast.error('Fehler beim Entfernen');
|
||||
toast.error($_('lists.detail.toast.removeError'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formatDate(dateStr: string): string {
|
||||
return new Date(dateStr).toLocaleDateString('de-DE', {
|
||||
return new Date(dateStr).toLocaleDateString($locale || 'de', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
|
|
@ -169,7 +169,7 @@
|
|||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{list?.name || 'Liste'} - Zitare</title>
|
||||
<title>{list?.name || $_('common.list')} - Zitare</title>
|
||||
</svelte:head>
|
||||
|
||||
{#if isLoading}
|
||||
|
|
@ -179,16 +179,16 @@
|
|||
</div>
|
||||
{:else if !list}
|
||||
<div class="error-state">
|
||||
<h2>Liste nicht gefunden</h2>
|
||||
<p>Diese Liste existiert nicht oder wurde gelöscht.</p>
|
||||
<a href="/lists" class="cta-button">Zurück zu Listen</a>
|
||||
<h2>{$_('lists.detail.notFound')}</h2>
|
||||
<p>{$_('lists.detail.notFoundDescription')}</p>
|
||||
<a href="/lists" class="cta-button">{$_('lists.detail.backToLists')}</a>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="list-detail-page">
|
||||
<!-- Header -->
|
||||
<div class="header-container">
|
||||
<div class="breadcrumb">
|
||||
<a href="/lists">Listen</a>
|
||||
<a href="/lists">{$_('lists.detail.breadcrumb')}</a>
|
||||
<span class="separator">/</span>
|
||||
<span>{list.name}</span>
|
||||
</div>
|
||||
|
|
@ -200,15 +200,19 @@
|
|||
<p class="description">{list.description}</p>
|
||||
{/if}
|
||||
<div class="meta">
|
||||
<span>{listQuotes.length} Zitate</span>
|
||||
<span>{$_('lists.quoteCount', { values: { count: listQuotes.length } })}</span>
|
||||
<span class="separator">•</span>
|
||||
<span>Zuletzt bearbeitet: {formatDate(list.updatedAt)}</span>
|
||||
<span
|
||||
>{$_('lists.detail.lastEdited', {
|
||||
values: { date: formatDate(list.updatedAt) },
|
||||
})}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="header-actions">
|
||||
{#if listQuotes.length > 0}
|
||||
<button class="icon-btn" onclick={toggleSearch} aria-label="Suchen">
|
||||
<button class="icon-btn" onclick={toggleSearch} aria-label={$_('common.search')}>
|
||||
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
{#if isSearchOpen}
|
||||
<path
|
||||
|
|
@ -229,7 +233,11 @@
|
|||
</button>
|
||||
{/if}
|
||||
|
||||
<button class="icon-btn" onclick={openEditModal} aria-label="Liste bearbeiten">
|
||||
<button
|
||||
class="icon-btn"
|
||||
onclick={openEditModal}
|
||||
aria-label={$_('lists.detail.editModal.title')}
|
||||
>
|
||||
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
|
@ -243,7 +251,7 @@
|
|||
<button
|
||||
class="icon-btn add-btn"
|
||||
onclick={openAddQuotesModal}
|
||||
aria-label="Zitate hinzufügen"
|
||||
aria-label={$_('lists.detail.addQuotes')}
|
||||
>
|
||||
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
|
|
@ -261,7 +269,7 @@
|
|||
<div class="search-bar">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Zitate durchsuchen..."
|
||||
placeholder={$_('lists.detail.searchPlaceholder')}
|
||||
bind:value={searchTerm}
|
||||
class="search"
|
||||
/>
|
||||
|
|
@ -290,8 +298,8 @@
|
|||
<line x1="3" y1="18" x2="3.01" y2="18"></line>
|
||||
</svg>
|
||||
</div>
|
||||
<h3>Keine Zitate in dieser Liste</h3>
|
||||
<p>Füge Zitate hinzu, um deine Sammlung zu starten</p>
|
||||
<h3>{$_('lists.detail.emptyTitle')}</h3>
|
||||
<p>{$_('lists.detail.emptyDescription')}</p>
|
||||
<button class="cta-button" onclick={openAddQuotesModal}>
|
||||
<svg width="20" height="20" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
|
|
@ -301,7 +309,7 @@
|
|||
d="M12 4v16m8-8H4"
|
||||
/>
|
||||
</svg>
|
||||
Zitate hinzufügen
|
||||
{$_('lists.detail.addQuotes')}
|
||||
</button>
|
||||
</div>
|
||||
{:else if filteredQuotes.length === 0}
|
||||
|
|
@ -320,8 +328,8 @@
|
|||
<path d="m21 21-4.35-4.35"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h3>Keine Ergebnisse</h3>
|
||||
<p>Versuche es mit anderen Suchbegriffen</p>
|
||||
<h3>{$_('lists.detail.noSearchResults')}</h3>
|
||||
<p>{$_('lists.detail.noSearchResultsDescription')}</p>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="quotes-grid">
|
||||
|
|
@ -331,7 +339,7 @@
|
|||
<button
|
||||
class="remove-btn"
|
||||
onclick={() => handleRemoveQuote(quote.id)}
|
||||
aria-label="Aus Liste entfernen"
|
||||
aria-label={$_('lists.detail.remove')}
|
||||
>
|
||||
<svg width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
|
|
@ -341,7 +349,7 @@
|
|||
d="M6 18L18 6M6 6l12 12"
|
||||
/>
|
||||
</svg>
|
||||
Entfernen
|
||||
{$_('lists.detail.remove')}
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
|
|
@ -350,7 +358,9 @@
|
|||
|
||||
{#if isSearchOpen && filteredQuotes.length > 0}
|
||||
<div class="floating-results">
|
||||
{filteredQuotes.length} von {listQuotes.length} Zitaten
|
||||
{$_('lists.detail.floatingResults', {
|
||||
values: { filtered: filteredQuotes.length, total: listQuotes.length },
|
||||
})}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
@ -361,8 +371,8 @@
|
|||
<div class="modal-overlay" onclick={closeEditModal} role="presentation">
|
||||
<div class="modal" onclick={(e) => e.stopPropagation()} role="dialog" aria-modal="true">
|
||||
<div class="modal-header">
|
||||
<h3>Liste bearbeiten</h3>
|
||||
<button class="close-btn" onclick={closeEditModal} aria-label="Schließen">
|
||||
<h3>{$_('lists.detail.editModal.title')}</h3>
|
||||
<button class="close-btn" onclick={closeEditModal} aria-label={$_('common.close')}>
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
|
@ -376,7 +386,7 @@
|
|||
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="edit-name">Name *</label>
|
||||
<label for="edit-name">{$_('lists.nameLabel')} *</label>
|
||||
<input
|
||||
id="edit-name"
|
||||
type="text"
|
||||
|
|
@ -387,7 +397,7 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="edit-description">Beschreibung (optional)</label>
|
||||
<label for="edit-description">{$_('lists.descriptionLabel')}</label>
|
||||
<textarea
|
||||
id="edit-description"
|
||||
bind:value={editDescription}
|
||||
|
|
@ -406,14 +416,14 @@
|
|||
d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
|
||||
/>
|
||||
</svg>
|
||||
Liste löschen
|
||||
{$_('lists.detail.editModal.deleteList')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" onclick={closeEditModal}> Abbrechen </button>
|
||||
<button class="btn btn-secondary" onclick={closeEditModal}>{$_('common.cancel')}</button>
|
||||
<button class="btn btn-primary" onclick={handleUpdateList} disabled={!editName.trim()}>
|
||||
Speichern
|
||||
{$_('common.save')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -430,8 +440,8 @@
|
|||
aria-modal="true"
|
||||
>
|
||||
<div class="modal-header">
|
||||
<h3>Zitate hinzufügen</h3>
|
||||
<button class="close-btn" onclick={closeAddQuotesModal} aria-label="Schließen">
|
||||
<h3>{$_('lists.detail.addModal.title')}</h3>
|
||||
<button class="close-btn" onclick={closeAddQuotesModal} aria-label={$_('common.close')}>
|
||||
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
|
|
@ -461,16 +471,18 @@
|
|||
|
||||
<div class="modal-footer">
|
||||
<div class="selected-count">
|
||||
{selectedQuoteIds.size} ausgewählt
|
||||
{$_('lists.detail.addModal.selected', { values: { count: selectedQuoteIds.size } })}
|
||||
</div>
|
||||
<div class="footer-actions">
|
||||
<button class="btn btn-secondary" onclick={closeAddQuotesModal}> Abbrechen </button>
|
||||
<button class="btn btn-secondary" onclick={closeAddQuotesModal}
|
||||
>{$_('common.cancel')}</button
|
||||
>
|
||||
<button
|
||||
class="btn btn-primary"
|
||||
onclick={handleAddQuotes}
|
||||
disabled={selectedQuoteIds.size === 0}
|
||||
>
|
||||
Hinzufügen ({selectedQuoteIds.size})
|
||||
{$_('lists.detail.addModal.submit', { values: { count: selectedQuoteIds.size } })}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@
|
|||
</div>
|
||||
{/if}
|
||||
{:else if searchTerm.length > 0}
|
||||
<p class="text-center text-foreground-muted py-8">Bitte gib mindestens 2 Zeichen ein</p>
|
||||
<p class="text-center text-foreground-muted py-8">{$_('search.minChars')}</p>
|
||||
{:else}
|
||||
<div class="text-center py-12">
|
||||
<svg
|
||||
|
|
@ -111,7 +111,7 @@
|
|||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" d="m21 21-4.35-4.35"
|
||||
></path>
|
||||
</svg>
|
||||
<p class="text-foreground-secondary">Suche nach Zitaten, Autoren oder Themen</p>
|
||||
<p class="text-foreground-secondary">{$_('search.hint')}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@
|
|||
<div class="space-y-6">
|
||||
<!-- Quote Language -->
|
||||
<div class="bg-surface-elevated rounded-2xl p-6">
|
||||
<h2 class="text-lg font-semibold text-foreground mb-4">Zitat-Sprache</h2>
|
||||
<h2 class="text-lg font-semibold text-foreground mb-4">{$_('settings.quoteLanguage')}</h2>
|
||||
<p class="text-foreground-secondary text-sm mb-4">
|
||||
Wähle die Sprache, in der die Zitate angezeigt werden sollen.
|
||||
{$_('settings.quoteLanguageDescription')}
|
||||
</p>
|
||||
<select
|
||||
value={quotesStore.language}
|
||||
|
|
@ -50,13 +50,14 @@
|
|||
|
||||
<!-- About -->
|
||||
<div class="bg-surface-elevated rounded-2xl p-6">
|
||||
<h2 class="text-lg font-semibold text-foreground mb-4">Über Zitare</h2>
|
||||
<h2 class="text-lg font-semibold text-foreground mb-4">{$_('settings.about')}</h2>
|
||||
<p class="text-foreground-secondary text-sm">
|
||||
Zitare bietet dir täglich inspirierende Zitate von den größten Denkern der Geschichte.
|
||||
Speichere deine Favoriten und erstelle eigene Listen.
|
||||
{$_('settings.aboutDescription')}
|
||||
</p>
|
||||
<p class="text-foreground-muted text-sm mt-4">
|
||||
{quotesStore.totalCount} Zitate · 10 Kategorien · 6 Sprachen
|
||||
{$_('settings.stats', {
|
||||
values: { quotes: quotesStore.totalCount, categories: 10, languages: 6 },
|
||||
})}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue