i18n(cards+finance+mood): translate 3 list/detail views via $_()

- cards/views/DetailView: route through cards.detail.* (deck-name
  fallback, prop labels, meta, confirm/toast strings)
- finance/ListView: route through finance.page.* (re-uses existing
  page namespace) + finance.list_view.empty_no_tx; drops unused
  Transaction + FinanceCategory type imports
- mood/ListView: route through mood.list_view.* (new namespace)

Baseline 899 → 881 (-18).
This commit is contained in:
Till JS 2026-04-27 18:38:06 +02:00
parent 70a06d1d9f
commit b99dd60ad0
4 changed files with 56 additions and 40 deletions

View file

@ -12,6 +12,7 @@
import { VisibilityPicker, type VisibilityLevel } from '@mana/shared-privacy';
import type { ViewProps } from '$lib/app-registry';
import type { LocalDeck, LocalCard } from '../types';
import { _ } from 'svelte-i18n';
let { params, goBack }: ViewProps = $props();
let deckId = $derived(params.deckId as string);
@ -48,7 +49,7 @@
async function saveField() {
detail.blur();
await deckStore.updateDeck(deckId, {
title: editName.trim() || detail.entity?.name || 'Unbenannt',
title: editName.trim() || detail.entity?.name || $_('cards.detail.name_fallback'),
description: editDescription.trim() || undefined,
});
// Color is not in UpdateDeckInput, update directly
@ -61,14 +62,14 @@
<DetailViewShell
entity={detail.entity}
loading={detail.loading}
notFoundLabel="Deck nicht gefunden"
notFoundLabel={$_('cards.detail.not_found')}
confirmDelete={detail.confirmDelete}
onAskDelete={detail.askDelete}
onCancelDelete={detail.cancelDelete}
confirmDeleteLabel="Deck wirklich löschen?"
confirmDeleteLabel={$_('cards.detail.confirm_delete')}
onConfirmDelete={() =>
detail.deleteWithUndo({
label: 'Deck gelöscht',
label: $_('cards.detail.toast_deleted'),
delete: () => deckStore.deleteDeck(deckId),
goBack,
})}
@ -79,12 +80,12 @@
bind:value={editName}
onfocus={detail.focus}
onblur={saveField}
placeholder="Deck-Name..."
placeholder={$_('cards.detail.placeholder_name')}
/>
<div class="properties">
<div class="prop-row">
<span class="prop-label">Farbe</span>
<span class="prop-label">{$_('cards.detail.prop_color')}</span>
<input
type="color"
class="color-input"
@ -95,7 +96,7 @@
</div>
<div class="prop-row">
<span class="prop-label">Sichtbarkeit</span>
<span class="prop-label">{$_('cards.detail.prop_visibility')}</span>
<VisibilityPicker
level={deck.visibility ?? 'space'}
onChange={(next: VisibilityLevel) => deckStore.setVisibility(deckId, next)}
@ -104,34 +105,42 @@
</div>
<div class="prop-row">
<span class="prop-label">Karten</span>
<span class="prop-label">{$_('cards.detail.prop_cards')}</span>
<span class="prop-value">{cardCount}</span>
</div>
{#if deck.lastStudied}
<div class="prop-row">
<span class="prop-label">Zuletzt gelernt</span>
<span class="prop-label">{$_('cards.detail.prop_last_studied')}</span>
<span class="prop-value">{formatDate(new Date(deck.lastStudied))}</span>
</div>
{/if}
</div>
<div class="section">
<span class="section-label">Beschreibung</span>
<span class="section-label">{$_('cards.detail.section_description')}</span>
<textarea
class="description-input"
bind:value={editDescription}
onfocus={detail.focus}
onblur={saveField}
placeholder="Beschreibung hinzufügen..."
placeholder={$_('cards.detail.placeholder_description')}
rows={3}
></textarea>
</div>
<div class="meta">
<span>Erstellt: {formatDate(new Date(deck.createdAt ?? ''))}</span>
<span
>{$_('cards.detail.meta_created', {
values: { date: formatDate(new Date(deck.createdAt ?? '')) },
})}</span
>
{#if deck.updatedAt}
<span>Bearbeitet: {formatDate(new Date(deck.updatedAt))}</span>
<span
>{$_('cards.detail.meta_updated', {
values: { date: formatDate(new Date(deck.updatedAt)) },
})}</span
>
{/if}
</div>
{/snippet}

View file

@ -15,8 +15,9 @@
groupByDate,
} from './queries';
import { financeStore } from './stores/finance.svelte';
import type { Transaction, FinanceCategory, TransactionType } from './types';
import type { TransactionType } from './types';
import type { ViewProps } from '$lib/app-registry';
import { _ } from 'svelte-i18n';
let { navigate, goBack, params }: ViewProps = $props();
@ -75,7 +76,7 @@
onclick={() => {
addType = 'expense';
addCatId = null;
}}>Ausgabe</button
}}>{$_('finance.page.type_expense')}</button
>
<button
type="button"
@ -84,7 +85,7 @@
onclick={() => {
addType = 'income';
addCatId = null;
}}>Einnahme</button
}}>{$_('finance.page.type_income')}</button
>
</div>
<div class="input-row">
@ -92,7 +93,7 @@
class="amount-input"
type="text"
inputmode="decimal"
placeholder="0,00"
placeholder={$_('finance.page.placeholder_amount')}
bind:value={addAmount}
onkeydown={handleKeydown}
/>
@ -100,7 +101,7 @@
<input
class="desc-input"
type="text"
placeholder="Beschreibung..."
placeholder={$_('finance.page.placeholder_description')}
bind:value={addDesc}
onkeydown={handleKeydown}
/>
@ -123,17 +124,17 @@
<div class="summary">
<div class="summary-col">
<span class="s-value income">+{formatCurrency(income)}</span>
<span class="s-label">Einnahmen</span>
<span class="s-label">{$_('finance.page.summary_income')}</span>
</div>
<div class="summary-col">
<span class="s-value expense">-{formatCurrency(expenses)}</span>
<span class="s-label">Ausgaben</span>
<span class="s-label">{$_('finance.page.summary_expenses')}</span>
</div>
<div class="summary-col">
<span class="s-value" class:income={balance >= 0} class:expense={balance < 0}>
{balance >= 0 ? '+' : ''}{formatCurrency(balance)}
</span>
<span class="s-label">Bilanz</span>
<span class="s-label">{$_('finance.page.summary_balance')}</span>
</div>
</div>
@ -161,7 +162,7 @@
{/each}
{#if recentTxs.length === 0}
<p class="empty">Noch keine Transaktionen diesen Monat.</p>
<p class="empty">{$_('finance.list_view.empty_no_tx')}</p>
{/if}
</div>
</div>

View file

@ -19,6 +19,7 @@
} from './queries';
import { EMOTION_META, ACTIVITY_LABELS } from './types';
import QuickLog from './components/QuickLog.svelte';
import { _ } from 'svelte-i18n';
const entriesQuery = useAllMoodEntries();
const settingsQuery = useMoodSettings();
@ -63,9 +64,11 @@
😊
{/if}
</span>
<span class="cta-text">Wie geht es dir?</span>
<span class="cta-text">{$_('mood.list_view.cta_question')}</span>
<span class="cta-sub">
{todayEntries.length}/{settings.dailyTarget} Check-ins heute
{$_('mood.list_view.cta_count', {
values: { n: todayEntries.length, target: settings.dailyTarget },
})}
</span>
</button>
{/if}
@ -73,7 +76,7 @@
<!-- Today's Entries -->
{#if todayEntries.length > 0}
<div class="today-section">
<span class="section-label">Heute</span>
<span class="section-label">{$_('mood.list_view.section_today')}</span>
<div class="today-entries">
{#each todayEntries as entry (entry.id)}
<div class="entry-pill">
@ -93,22 +96,22 @@
<div class="stats-row">
<div class="stat">
<span class="stat-val" style:color={levelColor(avgLevel7)}>{avgLevel7 || '—'}</span>
<span class="stat-lbl">Ø 7 Tage</span>
<span class="stat-lbl">{$_('mood.list_view.stat_avg_7')}</span>
</div>
<div class="stat">
<span class="stat-val" style:color={levelColor(avgLevel30)}>{avgLevel30 || '—'}</span>
<span class="stat-lbl">Ø 30 Tage</span>
<span class="stat-lbl">{$_('mood.list_view.stat_avg_30')}</span>
</div>
<div class="stat">
<span class="stat-val">{streak}</span>
<span class="stat-lbl">Streak</span>
<span class="stat-lbl">{$_('mood.list_view.stat_streak')}</span>
</div>
</div>
<!-- Week Mood Chart -->
{#if weekData.some((d) => d.avgLevel > 0)}
<div class="week-section">
<span class="section-label">Diese Woche</span>
<span class="section-label">{$_('mood.list_view.section_week')}</span>
<div class="week-chart">
{#each weekData as day}
<div class="week-col">
@ -136,15 +139,19 @@
<!-- Valence Bar -->
{#if entries.length >= 5}
<div class="valence-section">
<span class="section-label">Stimmungsbilanz</span>
<span class="section-label">{$_('mood.list_view.section_valence')}</span>
<div class="valence-bar">
<div class="v-pos" style:width="{valence.positive}%"></div>
<div class="v-neu" style:width="{valence.neutral}%"></div>
<div class="v-neg" style:width="{valence.negative}%"></div>
</div>
<div class="valence-labels">
<span class="vl-pos">{valence.positive}% positiv</span>
<span class="vl-neg">{valence.negative}% negativ</span>
<span class="vl-pos"
>{$_('mood.list_view.valence_positive', { values: { n: valence.positive } })}</span
>
<span class="vl-neg"
>{$_('mood.list_view.valence_negative', { values: { n: valence.negative } })}</span
>
</div>
</div>
{/if}
@ -152,7 +159,7 @@
<!-- Top Emotions -->
{#if distribution.length > 0}
<div class="dist-section">
<span class="section-label">Häufigste Emotionen</span>
<span class="section-label">{$_('mood.list_view.section_distribution')}</span>
<div class="dist-list">
{#each distribution.slice(0, 5) as item}
<div class="dist-row">
@ -175,7 +182,7 @@
<!-- Weekday Pattern -->
{#if weekdayPattern.some((d) => d.avgLevel > 0)}
<div class="pattern-section">
<span class="section-label">Wochentag-Muster</span>
<span class="section-label">{$_('mood.list_view.section_weekday_pattern')}</span>
<div class="pattern-row">
{#each weekdayPattern as day}
<div class="pattern-col">
@ -196,15 +203,17 @@
<!-- Activity Insights -->
{#if activityInsights.length >= 2}
<div class="insights-section">
<span class="section-label">Aktivitäten & Stimmung</span>
<span class="section-label">{$_('mood.list_view.section_activities')}</span>
{#each activityInsights.slice(0, 4) as insight}
<div class="insight-row">
<span class="ins-emoji">{ACTIVITY_LABELS[insight.activity]?.emoji ?? ''}</span>
<span class="ins-name">{ACTIVITY_LABELS[insight.activity]?.de ?? insight.activity}</span>
<span class="ins-val" style:color={levelColor(insight.avgLevel)}
{insight.avgLevel}</span
>{$_('mood.list_view.insight_avg', { values: { n: insight.avgLevel } })}</span
>
<span class="ins-count"
>{$_('mood.list_view.insight_count', { values: { n: insight.count } })}</span
>
<span class="ins-count">({insight.count}×)</span>
</div>
{/each}
</div>

View file

@ -68,7 +68,6 @@
"apps/mana/apps/web/src/lib/modules/broadcast/widgets/BroadcastsWidget.svelte": 3,
"apps/mana/apps/web/src/lib/modules/calc/ListView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/cards/components/CreateDeckModal.svelte": 3,
"apps/mana/apps/web/src/lib/modules/cards/views/DetailView.svelte": 6,
"apps/mana/apps/web/src/lib/modules/chat/ListView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/chat/views/DetailView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/citycorners/views/DetailView.svelte": 3,
@ -111,7 +110,6 @@
"apps/mana/apps/web/src/lib/modules/core/widgets/TasksTodayWidget.svelte": 1,
"apps/mana/apps/web/src/lib/modules/core/widgets/UpcomingEventsWidget.svelte": 1,
"apps/mana/apps/web/src/lib/modules/drink/ListView.svelte": 5,
"apps/mana/apps/web/src/lib/modules/finance/ListView.svelte": 6,
"apps/mana/apps/web/src/lib/modules/goals/ListView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/guides/ListView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/habits/components/HabitDetail.svelte": 5,
@ -130,7 +128,6 @@
"apps/mana/apps/web/src/lib/modules/meditate/components/StatsOverview.svelte": 3,
"apps/mana/apps/web/src/lib/modules/meditate/ListView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/mood/components/QuickLog.svelte": 6,
"apps/mana/apps/web/src/lib/modules/mood/ListView.svelte": 6,
"apps/mana/apps/web/src/lib/modules/moodlit/components/mood/CreateMoodDialog.svelte": 3,
"apps/mana/apps/web/src/lib/modules/music/ListView.svelte": 3,
"apps/mana/apps/web/src/lib/modules/music/views/DetailView.svelte": 6,