Three changes against the user feedback "der text ist zu
zerhackt, die filter-leiste nimmt zu viel sicht weg, llm-suche
wenn das geht":
1. Today-Hero copy rewritten in flowing prose. The fallback
story drops the code-fence templates ("`mcp.<server>.<tool>`")
and reads as a single arc per language. Same trust model,
gentler register.
2. Filter row collapses behind a single `_FilterButton` with a
"Filter · N active" count badge. Status / Source / Installed
chips now live inside `_FilterDialog` — invisible until the
operator wants them, recovers a full row of viewport. The
category strip stays inline because category is the most
common cut and benefits from being one click away.
3. New `_AskBar` replaces the old single-line `_SearchField`:
- Multi-line input (1-4 lines auto-grow) so questions don't
overflow horizontally.
- Cmd+Enter / Ctrl+Enter submits; bare Enter inserts a
newline so the operator can write multi-line questions
naturally.
- Heuristic question detector (ends in `?` or ≥4 words)
routes the submit to the System-AI's askAi RPC instead of
the substring search. Live keystrokes still keyword-search
for short queries; question-shaped input holds the grid
steady until submit so the visible result set doesn't
wipe with every space.
- The LLM is asked for a strict-JSON ranking of up to 5
modules with a one-phrase reason each. Unknown module
names are dropped silently — operators must not see
hallucinated entries.
- The new `_AiAnswerCard` renders the LLM's answer plus the
ranked match list above the grid; the grid filters to
just those names so the answer and the visible cards
stay coherent. Clearing the question collapses everything
back.
- Falls back to plain keyword search when System AI is off
(with an explanatory hint instead of the AI hint).
The AI path uses the System-AI the operator already configured
in Settings; same privacy mode, same audit-log trail. Nothing
new leaves the hub.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
1368 lines
33 KiB
Dart
1368 lines
33 KiB
Dart
// ignore: unused_import
|
||
import 'package:intl/intl.dart' as intl;
|
||
import 'app_localizations.dart';
|
||
|
||
// ignore_for_file: type=lint
|
||
|
||
/// The translations for German (`de`).
|
||
class AppLocalizationsDe extends AppLocalizations {
|
||
AppLocalizationsDe([String locale = 'de']) : super(locale);
|
||
|
||
@override
|
||
String get appTitle => 'F∆I Studio';
|
||
|
||
@override
|
||
String get navDoctor => 'Diagnose';
|
||
|
||
@override
|
||
String get navModules => 'Module';
|
||
|
||
@override
|
||
String get navStore => 'Store';
|
||
|
||
@override
|
||
String get navFlows => 'Flows';
|
||
|
||
@override
|
||
String get navAudit => 'Protokoll';
|
||
|
||
@override
|
||
String get navApprovals => 'Freigaben';
|
||
|
||
@override
|
||
String get connectionConnected => 'verbunden';
|
||
|
||
@override
|
||
String get connectionUnreachable => 'nicht erreichbar';
|
||
|
||
@override
|
||
String get connectionConnecting => 'verbinde…';
|
||
|
||
@override
|
||
String get connectionStartHub => 'Hub starten';
|
||
|
||
@override
|
||
String get buttonCancel => 'Abbrechen';
|
||
|
||
@override
|
||
String get buttonSave => 'Speichern';
|
||
|
||
@override
|
||
String get buttonClose => 'Schließen';
|
||
|
||
@override
|
||
String get buttonRetry => 'Erneut versuchen';
|
||
|
||
@override
|
||
String get buttonRefresh => 'Aktualisieren';
|
||
|
||
@override
|
||
String get buttonInstall => 'Installieren';
|
||
|
||
@override
|
||
String get buttonUninstall => 'Deinstallieren';
|
||
|
||
@override
|
||
String get buttonDetails => 'Details';
|
||
|
||
@override
|
||
String get buttonAdd => 'Hinzufügen';
|
||
|
||
@override
|
||
String get buttonRemove => 'Entfernen';
|
||
|
||
@override
|
||
String get buttonOpen => 'Öffnen';
|
||
|
||
@override
|
||
String get buttonExplain => 'Erklären';
|
||
|
||
@override
|
||
String get buttonReadDocs => 'Doku öffnen';
|
||
|
||
@override
|
||
String get settingsTitle => 'Hub-Endpunkt';
|
||
|
||
@override
|
||
String get settingsHost => 'Host';
|
||
|
||
@override
|
||
String get settingsPort => 'Port';
|
||
|
||
@override
|
||
String get settingsTls => 'TLS';
|
||
|
||
@override
|
||
String get settingsSaveAndConnect => 'Speichern & verbinden';
|
||
|
||
@override
|
||
String get settingsLanguage => 'Sprache';
|
||
|
||
@override
|
||
String get settingsLanguageHint =>
|
||
'Sprache der App. Wirkt auf alle Seiten; mehrsprachige Store-Einträge folgen ebenfalls.';
|
||
|
||
@override
|
||
String get settingsHubEndpointHint =>
|
||
'Wohin soll Studio sich verbinden? Standard ist der lokale Hub auf 127.0.0.1:50051.';
|
||
|
||
@override
|
||
String get settingsTlsSubtitle => 'https/grpc-secure';
|
||
|
||
@override
|
||
String get settingsPortError => 'Port muss 1–65535 sein';
|
||
|
||
@override
|
||
String get channelsBlurb =>
|
||
'Hub-Kanal wechseln (schreibt ~/.fai/current-channel und startet den Daemon neu). Verbinden ändert nur die Wire von Studio.';
|
||
|
||
@override
|
||
String get channelsActionsTooltip => 'Kanal-Aktionen';
|
||
|
||
@override
|
||
String get systemAiHeader => 'SYSTEM-AI';
|
||
|
||
@override
|
||
String get systemAiEnabled => 'aktiv';
|
||
|
||
@override
|
||
String get systemAiOff => 'aus';
|
||
|
||
@override
|
||
String get systemAiEdit => 'Bearbeiten…';
|
||
|
||
@override
|
||
String get systemAiConfigure => 'Konfigurieren…';
|
||
|
||
@override
|
||
String get systemAiOffBlurb =>
|
||
'Aus — Fehlererklärungen auf der Protokoll-Seite sind deaktiviert. Klicke Konfigurieren…, um einen Provider zu wählen (Ollama / OpenAI / LM Studio / vLLM / Eigene). Die Operator-Konfig wird direkt überschrieben; kein Daemon-Neustart nötig.';
|
||
|
||
@override
|
||
String mcpServersCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'Server',
|
||
one: 'Server',
|
||
);
|
||
return '$n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String get mcpRediscoverTooltip => 'Discovery neu ausführen';
|
||
|
||
@override
|
||
String get mcpAddTooltip => 'MCP-Server hinzufügen';
|
||
|
||
@override
|
||
String get mcpRemoveTooltip => 'Server entfernen';
|
||
|
||
@override
|
||
String mcpToolsCount(int n) {
|
||
return '$n Tools';
|
||
}
|
||
|
||
@override
|
||
String n8nEndpointsCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'Endpunkte',
|
||
one: 'Endpunkt',
|
||
);
|
||
return '$n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String n8nWorkflowsCount(int n) {
|
||
return '$n Workflows';
|
||
}
|
||
|
||
@override
|
||
String get n8nRediscoverTooltip => 'Discovery neu ausführen';
|
||
|
||
@override
|
||
String get n8nAddTooltip => 'n8n-Endpunkt hinzufügen';
|
||
|
||
@override
|
||
String get n8nRemoveTooltip => 'Endpunkt entfernen';
|
||
|
||
@override
|
||
String get addMcpTitle => 'MCP-Server hinzufügen';
|
||
|
||
@override
|
||
String get addMcpIntro =>
|
||
'Tools, die der Server via `tools/list` anbietet, erscheinen im Store als `mcp.<name>.<tool>`-Capabilities.';
|
||
|
||
@override
|
||
String get addMcpSuggestionsLabel => 'Vorschläge — zum Vorausfüllen klicken';
|
||
|
||
@override
|
||
String get addMcpNameLabel => 'Name (keine Punkte)';
|
||
|
||
@override
|
||
String get addMcpNameHint => 'filesystem';
|
||
|
||
@override
|
||
String get addMcpEndpointLabel => 'Endpunkt';
|
||
|
||
@override
|
||
String get addMcpEndpointHint => 'http://127.0.0.1:3001/mcp';
|
||
|
||
@override
|
||
String get addMcpApiKeyLabel => 'API-Key-Umgebungsvariable (optional)';
|
||
|
||
@override
|
||
String get addMcpApiKeyHint => 'MCP_FILESYSTEM_TOKEN';
|
||
|
||
@override
|
||
String get addMcpNotesLabel => 'Notizen (optional)';
|
||
|
||
@override
|
||
String get addMcpAddButton => 'Hinzufügen + Discovery';
|
||
|
||
@override
|
||
String get addN8nTitle => 'n8n-Endpunkt hinzufügen';
|
||
|
||
@override
|
||
String get addN8nIntro =>
|
||
'Aktive Workflows erscheinen im Store als `n8n.<name>.<workflow_slug>`-Capabilities.';
|
||
|
||
@override
|
||
String get addN8nNameLabel => 'Name (keine Punkte)';
|
||
|
||
@override
|
||
String get addN8nNameHint => 'ops';
|
||
|
||
@override
|
||
String get addN8nBaseUrlLabel => 'Basis-URL (ohne /api/v1)';
|
||
|
||
@override
|
||
String get addN8nBaseUrlHint => 'https://n8n.example.com';
|
||
|
||
@override
|
||
String get addN8nApiKeyLabel => 'API-Key-Umgebungsvariable (optional)';
|
||
|
||
@override
|
||
String get addN8nApiKeyHint => 'N8N_OPS_KEY';
|
||
|
||
@override
|
||
String get addN8nNotesLabel => 'Notizen (optional)';
|
||
|
||
@override
|
||
String get addN8nAddButton => 'Hinzufügen + Discovery';
|
||
|
||
@override
|
||
String addedMcpToast(String name) {
|
||
return 'MCP-Server „$name\" hinzugefügt.';
|
||
}
|
||
|
||
@override
|
||
String addedN8nToast(String name) {
|
||
return 'n8n-Endpunkt „$name\" hinzugefügt.';
|
||
}
|
||
|
||
@override
|
||
String addFailedToast(String error) {
|
||
return 'Hinzufügen fehlgeschlagen: $error';
|
||
}
|
||
|
||
@override
|
||
String removeFailedToast(String error) {
|
||
return 'Entfernen fehlgeschlagen: $error';
|
||
}
|
||
|
||
@override
|
||
String refreshFailedToast(String error) {
|
||
return 'Aktualisieren fehlgeschlagen: $error';
|
||
}
|
||
|
||
@override
|
||
String get channelsHeader => 'KANÄLE';
|
||
|
||
@override
|
||
String get channelsActive => 'aktiv';
|
||
|
||
@override
|
||
String get channelsRunning => 'läuft';
|
||
|
||
@override
|
||
String get channelsStopped => 'gestoppt';
|
||
|
||
@override
|
||
String get channelsConnect => 'Studio mit diesem Kanal verbinden';
|
||
|
||
@override
|
||
String get channelsSwitch => 'Diesen Kanal aktivieren';
|
||
|
||
@override
|
||
String get channelsEnableAutostart => 'Autostart bei Anmeldung aktivieren';
|
||
|
||
@override
|
||
String get channelsDisableAutostart => 'Autostart deaktivieren';
|
||
|
||
@override
|
||
String get storeSearchHint =>
|
||
'Module suchen — Name, Tagline, Tag, Capability…';
|
||
|
||
@override
|
||
String get storeAskHint =>
|
||
'Was brauchst du? Versuch\'s mit „ein Modul, das tabellarische Daten liest\" oder tippe einfach einen Begriff.';
|
||
|
||
@override
|
||
String get storeAskSubmit => 'Suchen';
|
||
|
||
@override
|
||
String get storeAskAi => 'KI fragen';
|
||
|
||
@override
|
||
String get storeAskClear => 'Frage zurücksetzen';
|
||
|
||
@override
|
||
String get storeAskAiThinking => 'Module werden durchsucht…';
|
||
|
||
@override
|
||
String get storeAskAiUnavailable =>
|
||
'Konfiguriere eine System-AI in den Einstellungen, um Fragen in normaler Sprache zu stellen.';
|
||
|
||
@override
|
||
String get storeAskNoMatches =>
|
||
'Keine Treffer — Frage verfeinern oder im Grid unten stöbern.';
|
||
|
||
@override
|
||
String get storeAskAnswerLabel => 'KI-Vorschlag';
|
||
|
||
@override
|
||
String get storeAskAnswerWhy => 'Warum es passt';
|
||
|
||
@override
|
||
String get storeAskMatchPill => 'Treffer';
|
||
|
||
@override
|
||
String get storeFilterLabel => 'Filter';
|
||
|
||
@override
|
||
String storeFilterActiveCount(int n) {
|
||
return '$n aktiv';
|
||
}
|
||
|
||
@override
|
||
String get storeFilterReset => 'Filter zurücksetzen';
|
||
|
||
@override
|
||
String get storeFilterApply => 'Fertig';
|
||
|
||
@override
|
||
String get storeFilterStatusGroup => 'Status';
|
||
|
||
@override
|
||
String get storeFilterSourceGroup => 'Quelle';
|
||
|
||
@override
|
||
String get storeFilterInstalledGroup => 'Nur installierte zeigen';
|
||
|
||
@override
|
||
String get storeFeatured => 'EMPFOHLEN';
|
||
|
||
@override
|
||
String get storeFeaturedHint => 'kuratierte Auswahl · klicken für Details';
|
||
|
||
@override
|
||
String get storeNoMatches => 'Keine Treffer';
|
||
|
||
@override
|
||
String get storeNoMatchesHint =>
|
||
'Filter anpassen oder Suche leeren, um alle Einträge zu sehen.';
|
||
|
||
@override
|
||
String get storeClearFilters => 'Filter zurücksetzen';
|
||
|
||
@override
|
||
String get storeStatusAll => 'Alle';
|
||
|
||
@override
|
||
String get storeStatusPublished => 'Veröffentlicht';
|
||
|
||
@override
|
||
String get storeStatusAlpha => 'Alpha';
|
||
|
||
@override
|
||
String get storeStatusPlanned => 'Geplant';
|
||
|
||
@override
|
||
String get storeInstalledOnly => 'Installiert';
|
||
|
||
@override
|
||
String storeNResults(int n) {
|
||
return '$n Treffer';
|
||
}
|
||
|
||
@override
|
||
String get storeReloadTooltip => 'Aktualisieren';
|
||
|
||
@override
|
||
String get storeTodayBadge => 'HEUTE';
|
||
|
||
@override
|
||
String get storeTodayDeck => 'Von der F∆I-Redaktion';
|
||
|
||
@override
|
||
String get storeTodayDismissTooltip => 'Für diese Sitzung ausblenden';
|
||
|
||
@override
|
||
String get storePillInstalled => 'installiert';
|
||
|
||
@override
|
||
String get storePillUpdate => 'Update';
|
||
|
||
@override
|
||
String storeUpdateButton(String version) {
|
||
return 'Update auf $version';
|
||
}
|
||
|
||
@override
|
||
String storeUpdateTooltip(String installed, String best) {
|
||
return 'Installiert $installed — Store bietet v$best';
|
||
}
|
||
|
||
@override
|
||
String get storeNoTagline => '(keine Beschreibung)';
|
||
|
||
@override
|
||
String get storeUninstallTitle => 'Modul deinstallieren?';
|
||
|
||
@override
|
||
String storeUninstallBody(String name) {
|
||
return 'Entfernt $name aus diesem Hub. Flows, die es verwenden, schlagen beim nächsten Lauf fehl.';
|
||
}
|
||
|
||
@override
|
||
String storeInstalledToast(String name, String version) {
|
||
return '$name v$version installiert.';
|
||
}
|
||
|
||
@override
|
||
String storeInstallFailedToast(String error) {
|
||
return 'Installation fehlgeschlagen: $error';
|
||
}
|
||
|
||
@override
|
||
String storeUninstalledToast(String name, String version) {
|
||
return '$name v$version deinstalliert.';
|
||
}
|
||
|
||
@override
|
||
String storeUninstallFailedToast(String error) {
|
||
return 'Deinstallation fehlgeschlagen: $error';
|
||
}
|
||
|
||
@override
|
||
String storeOpenBrowserFailed(String error) {
|
||
return 'Browser konnte nicht geöffnet werden: $error';
|
||
}
|
||
|
||
@override
|
||
String get storeSectionTags => 'Tags';
|
||
|
||
@override
|
||
String get storeSectionRequiredCapabilities => 'Erforderliche Capabilities';
|
||
|
||
@override
|
||
String get storeSectionRequiredHostServices => 'Erforderliche Host-Dienste';
|
||
|
||
@override
|
||
String get storeSectionScreenshots => 'Screenshots';
|
||
|
||
@override
|
||
String get storeSectionDocumentation => 'Dokumentation';
|
||
|
||
@override
|
||
String get storeSectionSource => 'Quelle';
|
||
|
||
@override
|
||
String get storeInstallingButton => 'Installiere…';
|
||
|
||
@override
|
||
String get storeNotInstallable => 'Nicht installierbar';
|
||
|
||
@override
|
||
String storeNotInstallableTooltip(String status) {
|
||
return 'Status „$status\" — Installations-Pfad noch nicht verdrahtet.';
|
||
}
|
||
|
||
@override
|
||
String storeInstallProgressTitle(String name) {
|
||
return 'Installation von $name';
|
||
}
|
||
|
||
@override
|
||
String get storeInstallProgressBody => 'Holen, verifizieren, entpacken…';
|
||
|
||
@override
|
||
String get storeLoadDocs => 'Dokumentation laden';
|
||
|
||
@override
|
||
String get storeDocsHint =>
|
||
'README inline gerendert; nutzt das Registry-Token des Hubs, falls nötig.';
|
||
|
||
@override
|
||
String get storeDocsFetching => 'README wird geladen…';
|
||
|
||
@override
|
||
String get storeOpenRepoButton => 'Repository im Browser öffnen';
|
||
|
||
@override
|
||
String get storeDocsErrorNotFound =>
|
||
'Dieses Modul ist nicht im Store-Index des Hubs enthalten.';
|
||
|
||
@override
|
||
String get storeDocsErrorNoDocs =>
|
||
'Für dieses Modul ist keine Repository-URL hinterlegt.';
|
||
|
||
@override
|
||
String get storeDocsErrorAuth =>
|
||
'Die Registry erfordert Authentifizierung, um dieses README zu laden. Setze FAI_REGISTRY_TOKEN in der Umgebung des Daemons und starte den Hub neu.';
|
||
|
||
@override
|
||
String storeDocsErrorNetwork(String detail) {
|
||
return 'Netzwerkfehler beim Laden des README. $detail';
|
||
}
|
||
|
||
@override
|
||
String get storeDocsErrorParse => 'README ist kein gültiges UTF-8.';
|
||
|
||
@override
|
||
String get storeDocsErrorGeneric => 'README konnte nicht geladen werden.';
|
||
|
||
@override
|
||
String get storeSourceLabel => 'Quelle';
|
||
|
||
@override
|
||
String get storeSourceAll => 'Alle Quellen';
|
||
|
||
@override
|
||
String get storeSourceNative => 'Nativ';
|
||
|
||
@override
|
||
String get storeSourceMcp => 'MCP';
|
||
|
||
@override
|
||
String get storeSourceN8n => 'n8n';
|
||
|
||
@override
|
||
String get storeProvenanceNative => 'nativ';
|
||
|
||
@override
|
||
String storeProvenanceMcp(String provider) {
|
||
return 'mcp · $provider';
|
||
}
|
||
|
||
@override
|
||
String storeProvenanceN8n(String provider) {
|
||
return 'n8n · $provider';
|
||
}
|
||
|
||
@override
|
||
String get storeRecommendedTitle =>
|
||
'Öffentliche Quelle hinzufügen — ein Klick';
|
||
|
||
@override
|
||
String get storeRecommendedBody =>
|
||
'Kuratierte MCP-Server über HTTPS erreichbar. Kein Subprozess, kein API-Key, kein Node. Föderierte Capabilities erscheinen sofort im Store.';
|
||
|
||
@override
|
||
String get storeRecommendedAddTooltip => 'Hinzufügen und entdecken';
|
||
|
||
@override
|
||
String get storeRecommendedAdding => 'Wird hinzugefügt…';
|
||
|
||
@override
|
||
String get storeRecommendedDeepWikiTagline =>
|
||
'GitHub-Repo-Doku-Suche (KI-gestützt)';
|
||
|
||
@override
|
||
String get storeRecommendedSemgrepTagline =>
|
||
'Security-Scanning für Code-Schwachstellen';
|
||
|
||
@override
|
||
String storeProviderAddedToast(String name, int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'föderierte Capabilities',
|
||
one: 'föderierte Capability',
|
||
);
|
||
return '$name hinzugefügt — $n $_temp0.';
|
||
}
|
||
|
||
@override
|
||
String storeProviderAddFailed(String name, String error) {
|
||
return '$name konnte nicht hinzugefügt werden: $error';
|
||
}
|
||
|
||
@override
|
||
String get auditTitle => 'Protokoll';
|
||
|
||
@override
|
||
String get auditNoEvents => 'Noch keine Ereignisse';
|
||
|
||
@override
|
||
String get auditNoEventsHint =>
|
||
'Starte einen Flow, um den Audit-Stream zu füllen.\nEreignisse erscheinen innerhalb von Sekunden.';
|
||
|
||
@override
|
||
String get auditFilterAll => 'alle';
|
||
|
||
@override
|
||
String get auditFilterFlow => 'Flow';
|
||
|
||
@override
|
||
String get auditFilterStep => 'Step';
|
||
|
||
@override
|
||
String get auditFilterModule => 'Modul';
|
||
|
||
@override
|
||
String get auditClearLogTooltip => 'Protokoll löschen (nur local/dev Kanal)';
|
||
|
||
@override
|
||
String auditClearedToast(int n, String channel) {
|
||
return '$n Ereignisse auf Kanal „$channel\" gelöscht. Chain mit Marker neu geseedet.';
|
||
}
|
||
|
||
@override
|
||
String auditClearFailed(String detail) {
|
||
return 'Löschen fehlgeschlagen: $detail';
|
||
}
|
||
|
||
@override
|
||
String get auditExplain => 'Erklären';
|
||
|
||
@override
|
||
String get auditReask => 'Neu fragen';
|
||
|
||
@override
|
||
String get auditAsking => 'Frage läuft…';
|
||
|
||
@override
|
||
String get auditSystemAi => 'SYSTEM-AI';
|
||
|
||
@override
|
||
String get auditCachedPill => 'gecacht';
|
||
|
||
@override
|
||
String auditOriginalLatency(int ms) {
|
||
return 'ursprünglich $ms ms';
|
||
}
|
||
|
||
@override
|
||
String auditLatency(int ms) {
|
||
return '$ms ms';
|
||
}
|
||
|
||
@override
|
||
String get auditRegenerateTooltip =>
|
||
'Neu generieren — Cache überspringen, Modell erneut fragen';
|
||
|
||
@override
|
||
String auditLiveStatus(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'Ereignisse',
|
||
one: 'Ereignis',
|
||
);
|
||
return 'live · Abfrage alle 2s · $n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String auditDisconnected(String error) {
|
||
return 'getrennt · $error';
|
||
}
|
||
|
||
@override
|
||
String get auditHashChainVerified => 'Hash-Chain verifiziert';
|
||
|
||
@override
|
||
String get auditDetailHeader => 'DETAIL';
|
||
|
||
@override
|
||
String get auditAskingFull => 'Frage an die konfigurierte System-AI läuft…';
|
||
|
||
@override
|
||
String get auditFixLabel => 'FIX';
|
||
|
||
@override
|
||
String auditCachedTooltipKnown(String at, String hits) {
|
||
return 'Aus dem lokalen Cache geliefert. Ursprünglich erzeugt am $at$hits.';
|
||
}
|
||
|
||
@override
|
||
String auditCachedTooltipUnknown(String hits) {
|
||
return 'Aus dem lokalen Cache geliefert. Ursprünglicher Zeitpunkt unbekannt$hits.';
|
||
}
|
||
|
||
@override
|
||
String auditCachedTooltipHits(int n) {
|
||
return ' · $n Treffer';
|
||
}
|
||
|
||
@override
|
||
String get auditConfigureSystemAi =>
|
||
'System-AI unter Einstellungen konfigurieren (Cmd+,)';
|
||
|
||
@override
|
||
String get auditClearDialogTitle => 'Audit-Log löschen?';
|
||
|
||
@override
|
||
String get auditClearDialogBody =>
|
||
'Löscht jedes Audit-Event auf dem aktiven Kanal und seedet einen neuen chain.reset-Marker mit Prüfer und Begründung. Auf beta / production verweigert. Nicht umkehrbar.';
|
||
|
||
@override
|
||
String get auditClearReviewerLabel => 'Prüfer';
|
||
|
||
@override
|
||
String get auditClearReasonLabel =>
|
||
'Begründung (im chain.reset-Marker festgehalten)';
|
||
|
||
@override
|
||
String get auditClearReasonHelper =>
|
||
'Erforderlich — Auditoren werden das lesen.';
|
||
|
||
@override
|
||
String get auditClearLogButton => 'Log löschen';
|
||
|
||
@override
|
||
String get modulesTitle => 'Module';
|
||
|
||
@override
|
||
String get modulesNoneTitle => 'Noch keine Module';
|
||
|
||
@override
|
||
String get modulesNoneHint =>
|
||
'`fai install <capability-name>` ausführen oder ~/.fai/modules/ prüfen.';
|
||
|
||
@override
|
||
String get modulesReloadTooltip => 'Aktualisieren';
|
||
|
||
@override
|
||
String get modulesRecentActivity => 'LETZTE AKTIVITÄT';
|
||
|
||
@override
|
||
String modulesRecentActivityHint(int n) {
|
||
return 'letzte $n install/uninstall-Ereignisse aus dem Audit-Log';
|
||
}
|
||
|
||
@override
|
||
String get modulesActivityInstalled => 'installiert';
|
||
|
||
@override
|
||
String get modulesActivityUninstalled => 'deinstalliert';
|
||
|
||
@override
|
||
String get modulesCapabilitiesLabel => 'Capabilities';
|
||
|
||
@override
|
||
String get modulesUninstallTitle => 'Modul deinstallieren?';
|
||
|
||
@override
|
||
String modulesUninstallBody(String name, String version) {
|
||
return 'Entfernt $name v$version von diesem Hub. Flows, die es verwenden, schlagen beim nächsten Lauf fehl. Ein `module.uninstalled`-Audit-Event wird festgehalten.';
|
||
}
|
||
|
||
@override
|
||
String modulesUninstalledToast(String name, String version) {
|
||
return '$name v$version deinstalliert.';
|
||
}
|
||
|
||
@override
|
||
String modulesUninstallFailed(String error) {
|
||
return 'Deinstallation fehlgeschlagen: $error';
|
||
}
|
||
|
||
@override
|
||
String get modulesUninstalling => 'Wird deinstalliert…';
|
||
|
||
@override
|
||
String moduleSheetFailedToLoad(String error) {
|
||
return 'Laden fehlgeschlagen: $error';
|
||
}
|
||
|
||
@override
|
||
String get moduleSheetCapabilities => 'Capabilities';
|
||
|
||
@override
|
||
String get moduleSheetPermissions => 'Deklarierte Berechtigungen';
|
||
|
||
@override
|
||
String get moduleSheetNoPermissions => '(keine — reines Berechnungsmodul)';
|
||
|
||
@override
|
||
String get flowsTitle => 'Flows';
|
||
|
||
@override
|
||
String get flowsReloadTooltip => 'Aktualisieren';
|
||
|
||
@override
|
||
String get flowsNoneTitle => 'Keine gespeicherten Flows';
|
||
|
||
@override
|
||
String get flowsNoneHint =>
|
||
'Flow speichern mit `fai admin flows save <name> <flow.yaml>`, dann taucht er hier auf.';
|
||
|
||
@override
|
||
String flowsRunDialogTitle(String name) {
|
||
return '$name ausführen';
|
||
}
|
||
|
||
@override
|
||
String get flowsRunDialogBody =>
|
||
'Eingaben als key=value, eine pro Zeile. Alle Werte werden als Text-Payloads gesendet. Für binäre Eingaben die `fai run` CLI nutzen.';
|
||
|
||
@override
|
||
String get flowsInputsHint =>
|
||
'name=World\ntarget_language=English\nsummary_style=three bullet points';
|
||
|
||
@override
|
||
String get flowsRunButton => 'Starten';
|
||
|
||
@override
|
||
String flowsRunningTitle(String name) {
|
||
return '$name läuft';
|
||
}
|
||
|
||
@override
|
||
String get flowsRunning => 'Flow läuft…';
|
||
|
||
@override
|
||
String get flowsNoOutputs => 'Flow abgeschlossen ohne deklarierte Outputs.';
|
||
|
||
@override
|
||
String get approvalsTitle => 'Freigaben';
|
||
|
||
@override
|
||
String get approvalsTabPending => 'Offen';
|
||
|
||
@override
|
||
String get approvalsTabHistory => 'Verlauf';
|
||
|
||
@override
|
||
String get approvalsInboxZero => 'Posteingang leer';
|
||
|
||
@override
|
||
String get approvalsInboxHint =>
|
||
'Alles erledigt. Neue `system.approval@^0`-Schritte landen automatisch hier.';
|
||
|
||
@override
|
||
String get approvalsReloadTooltip => 'Aktualisieren';
|
||
|
||
@override
|
||
String get approvalsPillPending => 'offen';
|
||
|
||
@override
|
||
String get approvalsPillApproved => 'freigegeben';
|
||
|
||
@override
|
||
String get approvalsPillRejected => 'abgelehnt';
|
||
|
||
@override
|
||
String get approvalsPillExpired => 'abgelaufen';
|
||
|
||
@override
|
||
String get approvalsPayloadPreview => 'PAYLOAD-VORSCHAU';
|
||
|
||
@override
|
||
String get approvalsApproveButton => 'Freigeben';
|
||
|
||
@override
|
||
String get approvalsRejectButton => 'Ablehnen';
|
||
|
||
@override
|
||
String get approvalsRejectDialogTitle => 'Freigabe ablehnen';
|
||
|
||
@override
|
||
String get approvalsRejectReasonLabel =>
|
||
'Begründung (im Audit-Log festgehalten)';
|
||
|
||
@override
|
||
String approvalsApprovedToast(String flow, String step) {
|
||
return 'freigegeben · $flow › $step';
|
||
}
|
||
|
||
@override
|
||
String approvalsRejectedToast(String flow, String step) {
|
||
return 'abgelehnt · $flow › $step';
|
||
}
|
||
|
||
@override
|
||
String approvalsApproveFailed(String error) {
|
||
return 'Freigabe fehlgeschlagen: $error';
|
||
}
|
||
|
||
@override
|
||
String approvalsRejectFailed(String error) {
|
||
return 'Ablehnung fehlgeschlagen: $error';
|
||
}
|
||
|
||
@override
|
||
String get approvalsHistoryEmpty => 'Noch kein Verlauf';
|
||
|
||
@override
|
||
String get approvalsHistoryEmptyHint =>
|
||
'Entschiedene Freigaben (freigegeben / abgelehnt / abgelaufen) erscheinen hier.\nDas Audit-Log enthält den vollständigen hash-chained Datensatz.';
|
||
|
||
@override
|
||
String get approvalsDialogDecided => 'entschieden';
|
||
|
||
@override
|
||
String get approvalsDialogCreated => 'erstellt';
|
||
|
||
@override
|
||
String get approvalsDialogReason => 'Begründung';
|
||
|
||
@override
|
||
String get approvalsDialogPrompt => 'PROMPT';
|
||
|
||
@override
|
||
String approvalsExpiresIn(int minutes) {
|
||
return '${minutes}m';
|
||
}
|
||
|
||
@override
|
||
String approvalsExpiresInHours(int hours) {
|
||
return '${hours}h';
|
||
}
|
||
|
||
@override
|
||
String get doctorTitle => 'Diagnose';
|
||
|
||
@override
|
||
String get doctorRecheckTooltip => 'Erneut prüfen';
|
||
|
||
@override
|
||
String get doctorEventLogSection => 'Audit-Log';
|
||
|
||
@override
|
||
String get doctorModulesApprovalsSection => 'Module & Freigaben';
|
||
|
||
@override
|
||
String get doctorHostServicesSection => 'Host-Dienste';
|
||
|
||
@override
|
||
String get doctorDaemonFilesSection => 'Daemon-Dateien';
|
||
|
||
@override
|
||
String get doctorDaemonControlSection => 'Daemon-Steuerung';
|
||
|
||
@override
|
||
String get doctorChainIntact => 'Hash-Chain intakt';
|
||
|
||
@override
|
||
String doctorChainIntactDetail(int n) {
|
||
return '$n Ereignisse · prev_event_sha256 lückenlos verifiziert';
|
||
}
|
||
|
||
@override
|
||
String get doctorChainTampered => 'Manipulation erkannt';
|
||
|
||
@override
|
||
String doctorChainTamperedDetail(int verified, int total, String id) {
|
||
return '$verified von $total verifiziert vor Mismatch bei $id';
|
||
}
|
||
|
||
@override
|
||
String get doctorChainPillOk => 'WORM-1';
|
||
|
||
@override
|
||
String get doctorChainPillTamper => 'MANIPULIERT';
|
||
|
||
@override
|
||
String get doctorVerifyNow => 'Jetzt prüfen';
|
||
|
||
@override
|
||
String get doctorRestart => 'Neustart';
|
||
|
||
@override
|
||
String get doctorStart => 'Starten';
|
||
|
||
@override
|
||
String get doctorStop => 'Stoppen';
|
||
|
||
@override
|
||
String get doctorStatusAction => 'Status';
|
||
|
||
@override
|
||
String doctorRunningOn(String name, String endpoint) {
|
||
return 'Läuft auf $name: $endpoint';
|
||
}
|
||
|
||
@override
|
||
String doctorStoppedOn(String name) {
|
||
return '$name-Daemon gestoppt';
|
||
}
|
||
|
||
@override
|
||
String get doctorStatusUnknown => 'Daemon-Status: …';
|
||
|
||
@override
|
||
String get doctorPillRunning => 'läuft';
|
||
|
||
@override
|
||
String get doctorPillStopped => 'gestoppt';
|
||
|
||
@override
|
||
String get doctorDaemonControlHint =>
|
||
'Studio ruft das Platform-Binary auf — entspricht `fai daemon …`, sodass CLI und UI im Gleichschritt bleiben.';
|
||
|
||
@override
|
||
String get doctorDaemonControlWorking => 'Wird ausgeführt…';
|
||
|
||
@override
|
||
String get doctorPathLog => 'Log';
|
||
|
||
@override
|
||
String get doctorPathConfig => 'Konfig';
|
||
|
||
@override
|
||
String get doctorPathDb => 'Audit-DB';
|
||
|
||
@override
|
||
String get doctorPathModules => 'Module-Verzeichnis';
|
||
|
||
@override
|
||
String get doctorPathFlows => 'Flow-Verzeichnis';
|
||
|
||
@override
|
||
String get doctorPathPid => 'PID-Datei';
|
||
|
||
@override
|
||
String get doctorPathsEmpty =>
|
||
'Daemon hat keine Datei-Pfade gemeldet. Hub aktualisieren via `fai daemon restart`.';
|
||
|
||
@override
|
||
String doctorOpenError(String detail) {
|
||
return 'Konnte nicht öffnen: $detail';
|
||
}
|
||
|
||
@override
|
||
String doctorUpdateAvailable(String version) {
|
||
return 'Update verfügbar — $version';
|
||
}
|
||
|
||
@override
|
||
String doctorUpdateBody(String channel, String version) {
|
||
return 'Kanal $channel bietet jetzt $version. Per Button anwenden — Studio ruft `fai update apply --channel $channel` auf.';
|
||
}
|
||
|
||
@override
|
||
String get doctorUpdateUnreachable => 'Release-Host nicht erreichbar';
|
||
|
||
@override
|
||
String doctorUpdateUnreachableBody(String channel) {
|
||
return 'Release-Feed für $channel konnte nicht erreicht werden.';
|
||
}
|
||
|
||
@override
|
||
String doctorReleaseNotes(String url) {
|
||
return 'Notes: $url';
|
||
}
|
||
|
||
@override
|
||
String get doctorPillNew => 'neu';
|
||
|
||
@override
|
||
String get doctorPillOffline => 'offline';
|
||
|
||
@override
|
||
String get doctorApplyUpdate => 'Update anwenden';
|
||
|
||
@override
|
||
String get doctorApplying => 'Wird angewendet…';
|
||
|
||
@override
|
||
String get doctorApplyDone =>
|
||
'Update angewendet. Studio neu starten, um die neue Daemon-Version zu sehen.';
|
||
|
||
@override
|
||
String get mcpHeader => 'MCP-CLIENTS';
|
||
|
||
@override
|
||
String get mcpHint =>
|
||
'Externe MCP-Server bringen ihre Tools als `mcp.<server>.<tool>` Capabilities ein. Einmal konfigurieren, im Store sichtbar.';
|
||
|
||
@override
|
||
String get mcpEmpty =>
|
||
'Keine MCP-Server konfiguriert. + klicken zum Hinzufügen.';
|
||
|
||
@override
|
||
String get n8nHeader => 'N8N-ENDPUNKTE';
|
||
|
||
@override
|
||
String get n8nHint =>
|
||
'Aktive n8n-Workflows erscheinen als `n8n.<endpoint>.<slug>` Capabilities. Einmal konfigurieren, im Store sichtbar.';
|
||
|
||
@override
|
||
String get n8nEmpty =>
|
||
'Keine n8n-Endpunkte konfiguriert. + klicken zum Hinzufügen.';
|
||
|
||
@override
|
||
String get hubUnreachable => 'Hub nicht erreichbar';
|
||
|
||
@override
|
||
String get hubUnreachableHint => 'Hub starten mit `fai serve`.';
|
||
|
||
@override
|
||
String get languageEnglish => 'English';
|
||
|
||
@override
|
||
String get languageGerman => 'Deutsch';
|
||
|
||
@override
|
||
String get searchHint =>
|
||
'Springe überall hin — Module, Store, Flows, Seiten…';
|
||
|
||
@override
|
||
String get searchIndexing => 'Indiziere…';
|
||
|
||
@override
|
||
String get searchNoMatches => 'Keine Treffer.';
|
||
|
||
@override
|
||
String get searchHintNavigate => '↑↓ navigieren';
|
||
|
||
@override
|
||
String get searchHintOpen => 'Enter öffnen';
|
||
|
||
@override
|
||
String get searchHintClose => 'Esc schließen';
|
||
|
||
@override
|
||
String get searchGroupPages => 'Seiten';
|
||
|
||
@override
|
||
String get searchGroupModules => 'Module';
|
||
|
||
@override
|
||
String get searchGroupStore => 'Store';
|
||
|
||
@override
|
||
String get searchGroupFlows => 'Flows';
|
||
|
||
@override
|
||
String get searchSettingsLabel => 'Einstellungen';
|
||
|
||
@override
|
||
String searchPageHint(int n) {
|
||
return 'Seite · ⌘$n';
|
||
}
|
||
|
||
@override
|
||
String get searchSettingsHint => 'Hub-Endpunkt, Kanäle, System-AI · ⌘;';
|
||
|
||
@override
|
||
String searchInstalledModuleHint(String version) {
|
||
return 'installiertes Modul · v$version';
|
||
}
|
||
|
||
@override
|
||
String get searchStoreUncategorized => 'ohne Kategorie';
|
||
|
||
@override
|
||
String searchStoreHintWithTagline(String tagline) {
|
||
return 'Store · $tagline';
|
||
}
|
||
|
||
@override
|
||
String searchStoreHintWithCategory(String category) {
|
||
return 'Store · $category';
|
||
}
|
||
|
||
@override
|
||
String get searchSavedFlowHint => 'gespeicherter Flow';
|
||
|
||
@override
|
||
String get systemAiTitle => 'System-AI';
|
||
|
||
@override
|
||
String get systemAiIntro =>
|
||
'Die hub-interne LLM, die die Plattform selbst für Fehlererklärungen und Operator-Hilfe nutzt. Standardmäßig aus; hier konfigurieren. Siehe docs/architecture/system-ai.md, was über die Leitung geht.';
|
||
|
||
@override
|
||
String get systemAiProviderLabel => 'Provider';
|
||
|
||
@override
|
||
String get systemAiEndpointLabel => 'Endpunkt-URL (bis /v1)';
|
||
|
||
@override
|
||
String get systemAiApiKeyRequired =>
|
||
'API-Key-Umgebungsvariable (erforderlich)';
|
||
|
||
@override
|
||
String get systemAiApiKeyOptional => 'API-Key-Umgebungsvariable (optional)';
|
||
|
||
@override
|
||
String systemAiApiKeyDisclaimer(String name) {
|
||
return 'Studio liest oder speichert den Key-Wert nie — nur den Namen der Umgebungsvariable. Der Hub liest `\$$name` zur Anfragezeit.';
|
||
}
|
||
|
||
@override
|
||
String get systemAiTestConnection => 'Verbindung testen';
|
||
|
||
@override
|
||
String get systemAiTesting => 'Teste…';
|
||
|
||
@override
|
||
String get systemAiSave => 'Speichern';
|
||
|
||
@override
|
||
String get systemAiPrivacyHeader => 'PRIVACY-MODUS';
|
||
|
||
@override
|
||
String get systemAiPrivacyOffLabel => 'Aus';
|
||
|
||
@override
|
||
String get systemAiPrivacyOffDesc =>
|
||
'Feature deaktiviert. Keine Anfragen verlassen den Hub.';
|
||
|
||
@override
|
||
String get systemAiPrivacyRedactedLabel => 'Redigiert';
|
||
|
||
@override
|
||
String get systemAiPrivacyRedactedDesc =>
|
||
'Nur event_type / error / Modul-Namen. KRITIS-freundlicher Standard.';
|
||
|
||
@override
|
||
String get systemAiPrivacyFullLabel => 'Voll';
|
||
|
||
@override
|
||
String get systemAiPrivacyFullDesc =>
|
||
'Enthält das Audit-Detail-JSON (nur Hash — keine Roh-Payloads).';
|
||
|
||
@override
|
||
String get systemAiConnectionOk => 'Verbindung ok';
|
||
|
||
@override
|
||
String get systemAiConnectionFailed => 'Verbindung fehlgeschlagen';
|
||
|
||
@override
|
||
String systemAiReplyPrefix(String text) {
|
||
return 'Antwort: $text';
|
||
}
|
||
|
||
@override
|
||
String get systemAiModelLabel => 'Modell (erforderlich)';
|
||
|
||
@override
|
||
String get systemAiModelHintFallback =>
|
||
'Modell-Identifier, den der Provider erwartet';
|
||
|
||
@override
|
||
String get systemAiModelHelperBase =>
|
||
'Erforderlich: aus der Liste auswählen (Aktualisieren) oder eintippen.';
|
||
|
||
@override
|
||
String get systemAiModelHelperOllama =>
|
||
'Erforderlich: aus der Liste auswählen (Aktualisieren) oder eintippen. Mit Pull von Ollama herunterladen.';
|
||
|
||
@override
|
||
String get systemAiRefresh => 'Aktualisieren';
|
||
|
||
@override
|
||
String get systemAiPull => 'Pull';
|
||
|
||
@override
|
||
String get systemAiPulling => 'Lade…';
|
||
|
||
@override
|
||
String systemAiCouldNotListModels(String error) {
|
||
return 'Modelle konnten nicht aufgelistet werden: $error';
|
||
}
|
||
|
||
@override
|
||
String get systemAiNoModelsOllama =>
|
||
'Noch keine Modelle auf dem Ollama-Server. Oben eintippen und Pull klicken.';
|
||
|
||
@override
|
||
String get systemAiNoModelsGeneric => 'Provider lieferte keine Modelle.';
|
||
|
||
@override
|
||
String get systemAiSuitabilityRecommended => 'empfohlen';
|
||
|
||
@override
|
||
String get systemAiSuitabilityBalanced => 'ausgewogen';
|
||
|
||
@override
|
||
String get systemAiSuitabilitySmall => 'klein — Qualität evtl. eingeschränkt';
|
||
|
||
@override
|
||
String get systemAiSuitabilityLarge => 'groß — langsamer';
|
||
|
||
@override
|
||
String get systemAiSuitabilityHuge =>
|
||
'sehr groß — auf einem Laptop wahrscheinlich zu langsam';
|
||
|
||
@override
|
||
String get systemAiSuitabilityUnknown => 'Größe unbekannt';
|
||
|
||
@override
|
||
String systemAiHwDetected(String summary) {
|
||
return 'Erkannt: $summary';
|
||
}
|
||
|
||
@override
|
||
String systemAiHwReviewed(String date) {
|
||
return ' · Kuratierung geprüft $date';
|
||
}
|
||
|
||
@override
|
||
String systemAiLegendRecommended(String tier) {
|
||
return 'empfohlen für diese Hardware$tier';
|
||
}
|
||
|
||
@override
|
||
String get systemAiLegendBalanced => 'ausgewogen (4-8B)';
|
||
|
||
@override
|
||
String get systemAiLegendSmallLarge =>
|
||
'klein <3B / groß 9-15B / über Hardware';
|
||
|
||
@override
|
||
String get systemAiLegendHuge => 'sehr groß >15B';
|
||
|
||
@override
|
||
String get systemAiLegendUnknown => 'Größe unbekannt';
|
||
|
||
@override
|
||
String systemAiCacheRow(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'gespeicherte Erklärungen',
|
||
one: 'gespeicherte Erklärung',
|
||
);
|
||
return 'Cache: $n $_temp0. Identische Prompts treffen den Cache; Modell- oder Privacy-Modus-Wechsel leeren ihn automatisch.';
|
||
}
|
||
|
||
@override
|
||
String get systemAiCacheClear => 'Leeren';
|
||
|
||
@override
|
||
String systemAiCacheClearedToast(int n) {
|
||
return '$n gespeicherte System-AI-Erklärungen gelöscht.';
|
||
}
|
||
|
||
@override
|
||
String systemAiCacheClearFailed(String error) {
|
||
return 'Cache-Löschen fehlgeschlagen: $error';
|
||
}
|
||
|
||
@override
|
||
String get systemAiPullEmptyError =>
|
||
'Erst eine Modell-ID eintippen (z.B. gemma3:4b).';
|
||
|
||
@override
|
||
String systemAiPullFailedError(String error) {
|
||
return 'Pull fehlgeschlagen: $error';
|
||
}
|
||
}
|