feat(studio): de-jargonize, reveal-in-OS, copyable errors, today carousel, AppBar alignment, F∆I window title (v0.34.0)

Sweeping pass against six user reports collected this session.

1. "Capabilities ist nicht deutsch, Chain auch nicht."
   The DE locale still leaked English vocabulary. Replaced
   "Capabilities" → "Fähigkeiten" and "Chain" / "Hash-Chain"
   → "Kette" / "Hash-Kette" everywhere — store search hint,
   recommended-source body, federated toast, doctor summary
   chain row, modules panel summary, MCP / n8n hints, the
   approvals history blurb. Wire-level identifiers
   (`chain.reset`) stay as code.

2. "Bei Fehlern unten muss man die auch ins clipboard
   kopieren können." New `FaiErrorBox` widget: selectable
   monospace block with a small copy-to-clipboard icon
   button that flips to a checkmark for two seconds after
   click. Applied to the Doctor update banner output and
   the Settings channel toast — the two places long
   stderr / stdout lands.

3. "Öffnen bei Log kann es nicht öffnen. Audit-DB auch
   nicht. PID auch nicht."
   Cause: `SystemActions.openInOs` shells out to `open` /
   `xdg-open` on file paths the OS has no default handler
   for (SQLite DB, PID file, log without an .ext that
   binds). New `revealInOs` uses `open -R` on macOS,
   `explorer /select,` on Windows, and the parent
   directory via `xdg-open` on Linux. Doctor's path rows
   carry an `isDirectory` flag that routes through the new
   `openOrReveal` so files reveal in Finder / Explorer
   instead of failing silently.

4. "Oben im Store könnte man diesen Redaktionshinweis auch
   so bauen, dass man mit pfeil nach rechts links auch
   weitere anzeigen kann."
   The Today-Hero became a carousel. Curated fallback
   list grew from one entry to four (public sources, the
   sandbox-by-default permission story, the hash-chained
   audit story, the air-gap-ready single-binary pitch).
   Hero gets prev / next chevrons plus a dot indicator
   when the current snapshot has more than one slide.
   Operator-accepted stories stay single — the carousel
   collapses when there's only one to show.

5. "Ich fände es schöner wenn rechts und links im Store
   die Abstände konsistent sind, das Reload-Symbol rechts
   ist zu weit rechts und Store links auch nicht bündig."
   AppBar now has `titleSpacing: FaiSpace.xl` so the
   title's left edge sits flush with the body's left
   padding (24 dp), and the trailing `SizedBox` after the
   reload icon shrunk so the icon's outer edge meets the
   right edge of the rightmost grid card.

6. "Oben der Titel zeigt fai_studio an, das sollte F∆I
   Studio sein." The OS window title was the
   pubspec-derived "fai_studio". Macos/Linux/Windows
   runners now hard-code "F∆I Studio" (with the U+2206
   triangle escape so the C++ source stays ASCII). macOS
   bundle name and display name lifted out of the
   PRODUCT_NAME variable for the same reason.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-05-08 14:48:33 +02:00
parent 22a851b7e2
commit 3b5fb027c3
17 changed files with 454 additions and 119 deletions

View file

@ -80,6 +80,12 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get buttonReadDocs => 'Doku öffnen';
@override
String get buttonCopy => 'In Zwischenablage kopieren';
@override
String get buttonCopied => 'Kopiert';
@override
String get settingsTitle => 'Hub-Endpunkt';
@ -193,7 +199,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get addMcpIntro =>
'Tools, die der Server via `tools/list` anbietet, erscheinen im Store als `mcp.<name>.<tool>`-Capabilities.';
'Tools, die der Server via `tools/list` anbietet, erscheinen im Store als `mcp.<name>.<tool>`-Fähigkeiten.';
@override
String get addMcpSuggestionsLabel => 'Vorschläge — zum Vorausfüllen klicken';
@ -227,7 +233,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get addN8nIntro =>
'Aktive Workflows erscheinen im Store als `n8n.<name>.<workflow_slug>`-Capabilities.';
'Aktive Workflows erscheinen im Store als `n8n.<name>.<workflow_slug>`-Fähigkeiten.';
@override
String get addN8nNameLabel => 'Name (keine Punkte)';
@ -304,7 +310,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get storeSearchHint =>
'Module suchen — Name, Tagline, Tag, Capability';
'Module suchen — Name, Tagline, Tag, Fähigkeit';
@override
String get storeAskHint =>
@ -502,7 +508,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get storeSectionTags => 'Tags';
@override
String get storeSectionRequiredCapabilities => 'Erforderliche Capabilities';
String get storeSectionRequiredCapabilities => 'Erforderliche Fähigkeiten';
@override
String get storeSectionRequiredHostServices => 'Erforderliche Host-Dienste';
@ -605,7 +611,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get storeRecommendedBody =>
'Kuratierte MCP-Server über HTTPS erreichbar. Kein Subprozess, kein API-Key, kein Node. Föderierte Capabilities erscheinen sofort im Store.';
'Kuratierte MCP-Server über HTTPS erreichbar. Kein Subprozess, kein API-Key, kein Node. Föderierte Fähigkeiten erscheinen sofort im Store.';
@override
String get storeRecommendedAddTooltip => 'Hinzufügen und entdecken';
@ -626,15 +632,15 @@ class AppLocalizationsDe extends AppLocalizations {
String _temp0 = intl.Intl.pluralLogic(
n,
locale: localeName,
other: 'föderierte Capabilities',
one: 'föderierte Capability',
other: 'föderierte Fähigkeiten',
one: 'föderierte Fähigkeit',
);
return '$name hinzugefügt — $n $_temp0.';
}
@override
String storeProviderAddedZeroToast(String name) {
return '$name ist eingetragen, aber der Server hat noch keine Capabilities geliefert. Öffne Einstellungen → MCP-Clients, um Discovery erneut zu versuchen oder den Server zu prüfen.';
return '$name ist eingetragen, aber der Server hat noch keine Fähigkeiten geliefert. Öffne Einstellungen → MCP-Clients, um Discovery erneut zu versuchen oder den Server zu prüfen.';
}
@override
@ -669,7 +675,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String auditClearedToast(int n, String channel) {
return '$n Ereignisse auf Kanal „$channel\" gelöscht. Chain mit Marker neu geseedet.';
return '$n Ereignisse auf Kanal „$channel\" gelöscht. Kette mit Marker neu geseedet.';
}
@override
@ -723,7 +729,7 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get auditHashChainVerified => 'Hash-Chain verifiziert';
String get auditHashChainVerified => 'Hash-Kette verifiziert';
@override
String get auditDetailHeader => 'DETAIL';
@ -802,7 +808,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get modulesActivityUninstalled => 'deinstalliert';
@override
String get modulesCapabilitiesLabel => 'Capabilities';
String get modulesCapabilitiesLabel => 'Fähigkeiten';
@override
String get modulesUninstallTitle => 'Modul deinstallieren?';
@ -831,7 +837,7 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get moduleSheetCapabilities => 'Capabilities';
String get moduleSheetCapabilities => 'Fähigkeiten';
@override
String get moduleSheetPermissions => 'Deklarierte Berechtigungen';
@ -951,7 +957,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get approvalsHistoryEmptyHint =>
'Entschiedene Freigaben (freigegeben / abgelehnt / abgelaufen) erscheinen hier.\nDas Audit-Log enthält den vollständigen hash-chained Datensatz.';
'Entschiedene Freigaben (freigegeben / abgelehnt / abgelaufen) erscheinen hier.\nDas Audit-Log enthält den vollständigen hash-verketteten Datensatz.';
@override
String get approvalsDialogDecided => 'entschieden';
@ -992,7 +998,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String doctorSummaryCapabilities(int n) {
return '$n Capabilities';
return '$n Fähigkeiten';
}
@override
@ -1000,7 +1006,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String doctorSummaryChain(int verified, int total) {
return '$verified/$total Chain';
return '$verified/$total Kette';
}
@override
@ -1008,7 +1014,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String doctorModulesPanelSummary(int n, int m) {
return '$n Module · $m Capabilities';
return '$n Module · $m Fähigkeiten';
}
@override
@ -1060,7 +1066,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get doctorDaemonControlSection => 'Daemon-Steuerung';
@override
String get doctorChainIntact => 'Hash-Chain intakt';
String get doctorChainIntact => 'Hash-Kette intakt';
@override
String doctorChainIntactDetail(int n) {
@ -1193,7 +1199,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get mcpHint =>
'Externe MCP-Server bringen ihre Tools als `mcp.<server>.<tool>` Capabilities ein. Einmal konfigurieren, im Store sichtbar.';
'Externe MCP-Server bringen ihre Tools als `mcp.<server>.<tool>` Fähigkeiten ein. Einmal konfigurieren, im Store sichtbar.';
@override
String get mcpEmpty =>
@ -1204,7 +1210,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get n8nHint =>
'Aktive n8n-Workflows erscheinen als `n8n.<endpoint>.<slug>` Capabilities. Einmal konfigurieren, im Store sichtbar.';
'Aktive n8n-Workflows erscheinen als `n8n.<endpoint>.<slug>` Fähigkeiten. Einmal konfigurieren, im Store sichtbar.';
@override
String get n8nEmpty =>