i18n(automations): translate ListView via $_() — suggestions, create form, flow visualization, empty state

- Section labels (Vorschläge/Aktive Regeln), suggestion CTAs (Aktivieren/Nein), '+ Neu' button
- Create form: name placeholder, WENN/FILTER/DANN step badges, source/action/habit/value selectors and placeholders, source-op options (erstellt wird / geändert wird), 'Kein Filter' option, Abbrechen/Erstellen footer
- Toggle title (Deaktivieren/Aktivieren), delete title (Löschen)
- Flow-chip 'wenn' marker, sourceDetail() helper now i18n's the 'erstellt'/'geändert' particle
- Empty state: title, hint, action

Baselines: hardcoded 1242 → 1230 (12 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 02:14:40 +02:00
parent 1b295f3d01
commit 1894e65495
2 changed files with 39 additions and 26 deletions

View file

@ -14,6 +14,7 @@
import { Trash } from '@mana/shared-icons'; import { Trash } from '@mana/shared-icons';
import { generateSuggestions, dismissSuggestion, isSuggestionDismissed } from '$lib/triggers'; import { generateSuggestions, dismissSuggestion, isSuggestionDismissed } from '$lib/triggers';
import type { AutomationSuggestion } from '$lib/triggers'; import type { AutomationSuggestion } from '$lib/triggers';
import { _ } from 'svelte-i18n';
let { navigate, goBack, params }: ViewProps = $props(); let { navigate, goBack, params }: ViewProps = $props();
@ -147,7 +148,10 @@
const src = SOURCE_OPTIONS.find( const src = SOURCE_OPTIONS.find(
(s) => s.app === a.sourceApp && s.collection === a.sourceCollection (s) => s.app === a.sourceApp && s.collection === a.sourceCollection
); );
const opLabel = a.sourceOp === 'insert' ? 'erstellt' : 'geaendert'; const opLabel =
a.sourceOp === 'insert'
? $_('automations.list_view.detail_inserted')
: $_('automations.list_view.detail_updated');
return src ? `${src.collectionLabel} ${opLabel}` : `${a.sourceCollection} ${opLabel}`; return src ? `${src.collectionLabel} ${opLabel}` : `${a.sourceCollection} ${opLabel}`;
} }
@ -177,7 +181,7 @@
<!-- Suggestions --> <!-- Suggestions -->
{#if suggestions.length > 0} {#if suggestions.length > 0}
<div class="section"> <div class="section">
<span class="section-label">Vorschlaege</span> <span class="section-label">{$_('automations.list_view.section_suggestions')}</span>
{#each suggestions as sug (sug.id)} {#each suggestions as sug (sug.id)}
<div class="sug-card"> <div class="sug-card">
<div class="sug-left"> <div class="sug-left">
@ -188,8 +192,12 @@
<span class="sug-desc">{sug.description}</span> <span class="sug-desc">{sug.description}</span>
</div> </div>
<div class="sug-actions"> <div class="sug-actions">
<button class="btn-sm primary" onclick={() => acceptSuggestion(sug)}>Aktivieren</button> <button class="btn-sm primary" onclick={() => acceptSuggestion(sug)}
<button class="btn-sm ghost" onclick={() => handleDismiss(sug.id)}>Nein</button> >{$_('automations.list_view.action_activate')}</button
>
<button class="btn-sm ghost" onclick={() => handleDismiss(sug.id)}
>{$_('automations.list_view.action_dismiss')}</button
>
</div> </div>
</div> </div>
{/each} {/each}
@ -199,9 +207,11 @@
<!-- Active Automations --> <!-- Active Automations -->
<div class="section"> <div class="section">
<div class="section-header"> <div class="section-header">
<span class="section-label">Aktive Regeln</span> <span class="section-label">{$_('automations.list_view.section_active')}</span>
{#if !showCreate} {#if !showCreate}
<button class="btn-sm outline" onclick={() => (showCreate = true)}>+ Neu</button> <button class="btn-sm outline" onclick={() => (showCreate = true)}
>{$_('automations.list_view.action_new')}</button
>
{/if} {/if}
</div> </div>
@ -210,15 +220,15 @@
<input <input
class="form-input full" class="form-input full"
type="text" type="text"
placeholder="Name (optional)" placeholder={$_('automations.list_view.placeholder_name')}
bind:value={newName} bind:value={newName}
/> />
<div class="form-step"> <div class="form-step">
<span class="step-badge when">WENN</span> <span class="step-badge when">{$_('automations.list_view.step_when')}</span>
<div class="step-fields"> <div class="step-fields">
<select class="form-select" bind:value={newSourceKey}> <select class="form-select" bind:value={newSourceKey}>
<option value="">Quelle waehlen...</option> <option value="">{$_('automations.list_view.placeholder_source')}</option>
{#each SOURCE_OPTIONS as src} {#each SOURCE_OPTIONS as src}
<option value="{src.app}.{src.collection}" <option value="{src.app}.{src.collection}"
>{src.appLabel}{src.collectionLabel}</option >{src.appLabel}{src.collectionLabel}</option
@ -227,8 +237,8 @@
</select> </select>
{#if selectedSource} {#if selectedSource}
<select class="form-select narrow" bind:value={newSourceOp}> <select class="form-select narrow" bind:value={newSourceOp}>
<option value="insert">erstellt wird</option> <option value="insert">{$_('automations.list_view.option_when_inserted')}</option>
<option value="update">geaendert wird</option> <option value="update">{$_('automations.list_view.option_when_updated')}</option>
</select> </select>
{/if} {/if}
</div> </div>
@ -236,10 +246,10 @@
{#if selectedSource} {#if selectedSource}
<div class="form-step"> <div class="form-step">
<span class="step-badge filter">FILTER</span> <span class="step-badge filter">{$_('automations.list_view.step_filter')}</span>
<div class="step-fields"> <div class="step-fields">
<select class="form-select" bind:value={newConditionField}> <select class="form-select" bind:value={newConditionField}>
<option value="">Kein Filter</option> <option value="">{$_('automations.list_view.option_no_filter')}</option>
{#each selectedSource.fields as field} {#each selectedSource.fields as field}
<option value={field}>{field}</option> <option value={field}>{field}</option>
{/each} {/each}
@ -253,7 +263,7 @@
<input <input
class="form-input" class="form-input"
type="text" type="text"
placeholder="Wert..." placeholder={$_('automations.list_view.placeholder_value')}
bind:value={newConditionValue} bind:value={newConditionValue}
/> />
{/if} {/if}
@ -262,10 +272,10 @@
{/if} {/if}
<div class="form-step"> <div class="form-step">
<span class="step-badge then">DANN</span> <span class="step-badge then">{$_('automations.list_view.step_then')}</span>
<div class="step-fields"> <div class="step-fields">
<select class="form-select" bind:value={newActionKey}> <select class="form-select" bind:value={newActionKey}>
<option value="">Aktion waehlen...</option> <option value="">{$_('automations.list_view.placeholder_action')}</option>
{#each ACTION_OPTIONS as act} {#each ACTION_OPTIONS as act}
<option value="{act.app}.{act.action}">{act.appLabel}{act.actionLabel}</option> <option value="{act.app}.{act.action}">{act.appLabel}{act.actionLabel}</option>
{/each} {/each}
@ -283,7 +293,7 @@
}; };
}} }}
> >
<option value="">Habit waehlen...</option> <option value="">{$_('automations.list_view.placeholder_habit')}</option>
{#each habits as h} {#each habits as h}
<option value={h.id}>{h.title}</option> <option value={h.id}>{h.title}</option>
{/each} {/each}
@ -308,9 +318,11 @@
</div> </div>
<div class="form-footer"> <div class="form-footer">
<button type="button" class="btn-sm ghost" onclick={resetForm}>Abbrechen</button> <button type="button" class="btn-sm ghost" onclick={resetForm}
>{$_('automations.list_view.action_cancel')}</button
>
<button type="submit" class="btn-sm primary" disabled={!selectedSource || !selectedAction} <button type="submit" class="btn-sm primary" disabled={!selectedSource || !selectedAction}
>Erstellen</button >{$_('automations.list_view.action_create')}</button
> >
</div> </div>
</form> </form>
@ -324,7 +336,9 @@
class="toggle" class="toggle"
class:on={auto.enabled} class:on={auto.enabled}
onclick={() => automationsStore.toggle(auto.id)} onclick={() => automationsStore.toggle(auto.id)}
title={auto.enabled ? 'Deaktivieren' : 'Aktivieren'} title={auto.enabled
? $_('automations.list_view.toggle_disable')
: $_('automations.list_view.toggle_enable')}
> >
<span class="toggle-track"><span class="toggle-thumb"></span></span> <span class="toggle-track"><span class="toggle-thumb"></span></span>
</button> </button>
@ -332,7 +346,7 @@
<button <button
class="icon-btn danger" class="icon-btn danger"
onclick={() => automationsStore.remove(auto.id)} onclick={() => automationsStore.remove(auto.id)}
title="Loeschen" title={$_('automations.list_view.action_delete')}
> >
<Trash size={12} /> <Trash size={12} />
</button> </button>
@ -342,7 +356,7 @@
<span class="flow-detail">{sourceDetail(auto)}</span> <span class="flow-detail">{sourceDetail(auto)}</span>
{#if conditionLabel(auto)} {#if conditionLabel(auto)}
<span class="flow-arrow">&#8594;</span> <span class="flow-arrow">&#8594;</span>
<span class="flow-chip filter">wenn</span> <span class="flow-chip filter">{$_('automations.list_view.flow_when')}</span>
<span class="flow-detail">{conditionLabel(auto)}</span> <span class="flow-detail">{conditionLabel(auto)}</span>
{/if} {/if}
<span class="flow-arrow">&#8594;</span> <span class="flow-arrow">&#8594;</span>
@ -354,10 +368,10 @@
{#if automations.length === 0 && !showCreate} {#if automations.length === 0 && !showCreate}
<div class="empty"> <div class="empty">
<p class="empty-title">Keine Automations</p> <p class="empty-title">{$_('automations.list_view.empty_title')}</p>
<p class="empty-hint">Verbinde Module mit Regeln: "Wenn X passiert, mache Y"</p> <p class="empty-hint">{$_('automations.list_view.empty_hint')}</p>
<button class="btn-sm primary" onclick={() => (showCreate = true)} <button class="btn-sm primary" onclick={() => (showCreate = true)}
>Erste Automation erstellen</button >{$_('automations.list_view.empty_action')}</button
> >
</div> </div>
{/if} {/if}

View file

@ -57,7 +57,6 @@
"apps/mana/apps/web/src/lib/modules/articles/views/HighlightsView.svelte": 4, "apps/mana/apps/web/src/lib/modules/articles/views/HighlightsView.svelte": 4,
"apps/mana/apps/web/src/lib/modules/articles/widgets/ArticlesUnreadWidget.svelte": 1, "apps/mana/apps/web/src/lib/modules/articles/widgets/ArticlesUnreadWidget.svelte": 1,
"apps/mana/apps/web/src/lib/modules/augur/SharedAugurEntryView.svelte": 1, "apps/mana/apps/web/src/lib/modules/augur/SharedAugurEntryView.svelte": 1,
"apps/mana/apps/web/src/lib/modules/automations/ListView.svelte": 12,
"apps/mana/apps/web/src/lib/modules/body/components/CalorieWeightChart.svelte": 1, "apps/mana/apps/web/src/lib/modules/body/components/CalorieWeightChart.svelte": 1,
"apps/mana/apps/web/src/lib/modules/body/components/ExercisePicker.svelte": 6, "apps/mana/apps/web/src/lib/modules/body/components/ExercisePicker.svelte": 6,
"apps/mana/apps/web/src/lib/modules/body/components/ExerciseProgressionChart.svelte": 1, "apps/mana/apps/web/src/lib/modules/body/components/ExerciseProgressionChart.svelte": 1,