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>
1487 lines
34 KiB
Dart
1487 lines
34 KiB
Dart
// ignore: unused_import
|
||
import 'package:intl/intl.dart' as intl;
|
||
import 'app_localizations.dart';
|
||
|
||
// ignore_for_file: type=lint
|
||
|
||
/// The translations for English (`en`).
|
||
class AppLocalizationsEn extends AppLocalizations {
|
||
AppLocalizationsEn([String locale = 'en']) : super(locale);
|
||
|
||
@override
|
||
String get appTitle => 'F∆I Studio';
|
||
|
||
@override
|
||
String get navDoctor => 'Doctor';
|
||
|
||
@override
|
||
String get navModules => 'Modules';
|
||
|
||
@override
|
||
String get navStore => 'Store';
|
||
|
||
@override
|
||
String get navFlows => 'Flows';
|
||
|
||
@override
|
||
String get navAudit => 'Audit';
|
||
|
||
@override
|
||
String get navApprovals => 'Approvals';
|
||
|
||
@override
|
||
String get connectionConnected => 'connected';
|
||
|
||
@override
|
||
String get connectionUnreachable => 'unreachable';
|
||
|
||
@override
|
||
String get connectionConnecting => 'connecting…';
|
||
|
||
@override
|
||
String get connectionStartHub => 'Start hub';
|
||
|
||
@override
|
||
String get buttonCancel => 'Cancel';
|
||
|
||
@override
|
||
String get buttonSave => 'Save';
|
||
|
||
@override
|
||
String get buttonClose => 'Close';
|
||
|
||
@override
|
||
String get buttonRetry => 'Retry';
|
||
|
||
@override
|
||
String get buttonRefresh => 'Refresh';
|
||
|
||
@override
|
||
String get buttonInstall => 'Install';
|
||
|
||
@override
|
||
String get buttonUninstall => 'Uninstall';
|
||
|
||
@override
|
||
String get buttonDetails => 'Details';
|
||
|
||
@override
|
||
String get buttonAdd => 'Add';
|
||
|
||
@override
|
||
String get buttonRemove => 'Remove';
|
||
|
||
@override
|
||
String get buttonOpen => 'Open';
|
||
|
||
@override
|
||
String get buttonExplain => 'Explain';
|
||
|
||
@override
|
||
String get buttonReadDocs => 'Read docs';
|
||
|
||
@override
|
||
String get buttonCopy => 'Copy to clipboard';
|
||
|
||
@override
|
||
String get buttonCopied => 'Copied';
|
||
|
||
@override
|
||
String get settingsTitle => 'Hub endpoint';
|
||
|
||
@override
|
||
String get settingsHost => 'Host';
|
||
|
||
@override
|
||
String get settingsPort => 'Port';
|
||
|
||
@override
|
||
String get settingsTls => 'TLS';
|
||
|
||
@override
|
||
String get settingsSaveAndConnect => 'Save & connect';
|
||
|
||
@override
|
||
String get settingsLanguage => 'Language';
|
||
|
||
@override
|
||
String get settingsLanguageHint =>
|
||
'App language. Affects every page; bilingual store entries also flip via this toggle.';
|
||
|
||
@override
|
||
String get settingsHubEndpointHint =>
|
||
'Where should Studio connect? Default is the local hub at 127.0.0.1:50051.';
|
||
|
||
@override
|
||
String get settingsTlsSubtitle => 'https/grpc-secure';
|
||
|
||
@override
|
||
String get settingsPortError => 'port must be 1–65535';
|
||
|
||
@override
|
||
String get channelsBlurb =>
|
||
'Switch hub channel (writes ~/.fai/current-channel and restarts the daemon). Connect just changes Studio\'s wire.';
|
||
|
||
@override
|
||
String get channelsActionsTooltip => 'Channel actions';
|
||
|
||
@override
|
||
String get systemAiHeader => 'SYSTEM AI';
|
||
|
||
@override
|
||
String get systemAiEnabled => 'enabled';
|
||
|
||
@override
|
||
String get systemAiOff => 'off';
|
||
|
||
@override
|
||
String get systemAiEdit => 'Edit…';
|
||
|
||
@override
|
||
String get systemAiConfigure => 'Configure…';
|
||
|
||
@override
|
||
String get systemAiOffBlurb =>
|
||
'Off — failure explanations on the audit page are disabled. Click Configure… to pick a provider (Ollama / OpenAI / LM Studio / vLLM / Custom). Operator config is rewritten in place; no daemon restart needed.';
|
||
|
||
@override
|
||
String mcpServersCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'servers',
|
||
one: 'server',
|
||
);
|
||
return '$n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String get mcpRediscoverTooltip => 'Re-run discovery';
|
||
|
||
@override
|
||
String get mcpAddTooltip => 'Add MCP server';
|
||
|
||
@override
|
||
String get mcpRemoveTooltip => 'Remove server';
|
||
|
||
@override
|
||
String mcpToolsCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'tools',
|
||
one: 'tool',
|
||
);
|
||
return '$n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String n8nEndpointsCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'endpoints',
|
||
one: 'endpoint',
|
||
);
|
||
return '$n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String n8nWorkflowsCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'workflows',
|
||
one: 'workflow',
|
||
);
|
||
return '$n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String get n8nRediscoverTooltip => 'Re-run discovery';
|
||
|
||
@override
|
||
String get n8nAddTooltip => 'Add n8n endpoint';
|
||
|
||
@override
|
||
String get n8nRemoveTooltip => 'Remove endpoint';
|
||
|
||
@override
|
||
String get addMcpTitle => 'Add MCP server';
|
||
|
||
@override
|
||
String get addMcpIntro =>
|
||
'Tools the server advertises via `tools/list` appear in the Store as `mcp.<name>.<tool>` capabilities.';
|
||
|
||
@override
|
||
String get addMcpSuggestionsLabel => 'Suggested servers — click to pre-fill';
|
||
|
||
@override
|
||
String get addMcpNameLabel => 'Name (no dots)';
|
||
|
||
@override
|
||
String get addMcpNameHint => 'filesystem';
|
||
|
||
@override
|
||
String get addMcpEndpointLabel => 'Endpoint';
|
||
|
||
@override
|
||
String get addMcpEndpointHint => 'http://127.0.0.1:3001/mcp';
|
||
|
||
@override
|
||
String get addMcpApiKeyLabel => 'API key env var (optional)';
|
||
|
||
@override
|
||
String get addMcpApiKeyHint => 'MCP_FILESYSTEM_TOKEN';
|
||
|
||
@override
|
||
String get addMcpNotesLabel => 'Notes (optional)';
|
||
|
||
@override
|
||
String get addMcpAddButton => 'Add + discover';
|
||
|
||
@override
|
||
String get addN8nTitle => 'Add n8n endpoint';
|
||
|
||
@override
|
||
String get addN8nIntro =>
|
||
'Active workflows surface in the Store as `n8n.<name>.<workflow_slug>` capabilities.';
|
||
|
||
@override
|
||
String get addN8nNameLabel => 'Name (no dots)';
|
||
|
||
@override
|
||
String get addN8nNameHint => 'ops';
|
||
|
||
@override
|
||
String get addN8nBaseUrlLabel => 'Base URL (without /api/v1)';
|
||
|
||
@override
|
||
String get addN8nBaseUrlHint => 'https://n8n.example.com';
|
||
|
||
@override
|
||
String get addN8nApiKeyLabel => 'API key env var (optional)';
|
||
|
||
@override
|
||
String get addN8nApiKeyHint => 'N8N_OPS_KEY';
|
||
|
||
@override
|
||
String get addN8nNotesLabel => 'Notes (optional)';
|
||
|
||
@override
|
||
String get addN8nAddButton => 'Add + discover';
|
||
|
||
@override
|
||
String addedMcpToast(String name) {
|
||
return 'Added MCP server \"$name\".';
|
||
}
|
||
|
||
@override
|
||
String addedN8nToast(String name) {
|
||
return 'Added n8n endpoint \"$name\".';
|
||
}
|
||
|
||
@override
|
||
String addFailedToast(String error) {
|
||
return 'Add failed: $error';
|
||
}
|
||
|
||
@override
|
||
String removeFailedToast(String error) {
|
||
return 'Remove failed: $error';
|
||
}
|
||
|
||
@override
|
||
String refreshFailedToast(String error) {
|
||
return 'Refresh failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get channelsHeader => 'CHANNELS';
|
||
|
||
@override
|
||
String get channelsActive => 'active';
|
||
|
||
@override
|
||
String get channelsRunning => 'running';
|
||
|
||
@override
|
||
String get channelsStopped => 'stopped';
|
||
|
||
@override
|
||
String get channelsConnect => 'Connect Studio to this channel';
|
||
|
||
@override
|
||
String get channelsSwitch => 'Make this the active channel';
|
||
|
||
@override
|
||
String get channelsEnableAutostart => 'Enable autostart at login';
|
||
|
||
@override
|
||
String get channelsDisableAutostart => 'Disable autostart';
|
||
|
||
@override
|
||
String get storeSearchHint =>
|
||
'Search modules — name, tagline, tag, capability…';
|
||
|
||
@override
|
||
String get storeAskHint =>
|
||
'What do you need? Try \"a module that reads tabular data\" or just type a keyword.';
|
||
|
||
@override
|
||
String get storeAskSubmit => 'Search';
|
||
|
||
@override
|
||
String get storeAskAi => 'Ask the AI';
|
||
|
||
@override
|
||
String get storeAskClear => 'Clear question';
|
||
|
||
@override
|
||
String get storeAskAiThinking => 'Looking through modules…';
|
||
|
||
@override
|
||
String get storeAskAiUnavailable =>
|
||
'Configure a System AI in Settings to ask questions in plain language.';
|
||
|
||
@override
|
||
String get storeAskNoMatches =>
|
||
'No matches yet — refine the question or browse the grid below.';
|
||
|
||
@override
|
||
String get storeAskAnswerLabel => 'AI suggestion';
|
||
|
||
@override
|
||
String get storeAskAnswerWhy => 'Why this matches';
|
||
|
||
@override
|
||
String get storeAskMatchPill => 'match';
|
||
|
||
@override
|
||
String get storeFilterLabel => 'Filter';
|
||
|
||
@override
|
||
String storeFilterActiveCount(int n) {
|
||
return '$n active';
|
||
}
|
||
|
||
@override
|
||
String get storeFilterReset => 'Reset filters';
|
||
|
||
@override
|
||
String get storeFilterApply => 'Done';
|
||
|
||
@override
|
||
String get storeFilterStatusGroup => 'Status';
|
||
|
||
@override
|
||
String get storeFilterSourceGroup => 'Source';
|
||
|
||
@override
|
||
String get storeFilterInstalledGroup => 'Show only installed';
|
||
|
||
@override
|
||
String get storeFeatured => 'FEATURED';
|
||
|
||
@override
|
||
String get storeFeaturedHint => 'curated picks · click for details';
|
||
|
||
@override
|
||
String get storeNoMatches => 'No matches';
|
||
|
||
@override
|
||
String get storeNoMatchesHint =>
|
||
'Adjust the filters or clear the search to see all entries.';
|
||
|
||
@override
|
||
String get storeClearFilters => 'Clear filters';
|
||
|
||
@override
|
||
String get storeStatusAll => 'All';
|
||
|
||
@override
|
||
String get storeStatusPublished => 'stable';
|
||
|
||
@override
|
||
String get storeStatusAlpha => 'experimental';
|
||
|
||
@override
|
||
String get storeStatusPlanned => 'coming soon';
|
||
|
||
@override
|
||
String get storeInstalledOnly => 'Installed';
|
||
|
||
@override
|
||
String get storeCategoryLabel => 'Category';
|
||
|
||
@override
|
||
String get storeCategoryAll => 'All categories';
|
||
|
||
@override
|
||
String get storeCategoryBridge => 'Connectors';
|
||
|
||
@override
|
||
String get storeCategoryDebug => 'Sample modules';
|
||
|
||
@override
|
||
String get storeCategoryText => 'Text';
|
||
|
||
@override
|
||
String get storeCategoryLlm => 'AI models';
|
||
|
||
@override
|
||
String get storeCategorySystem => 'System';
|
||
|
||
@override
|
||
String get storeCategoryAuth => 'Authentication';
|
||
|
||
@override
|
||
String get storeCategoryStorage => 'Storage';
|
||
|
||
@override
|
||
String get storeCategoryChannel => 'Channels';
|
||
|
||
@override
|
||
String get storeCategoryWeb => 'Web';
|
||
|
||
@override
|
||
String get storeCategoryOrchestrator => 'Orchestration';
|
||
|
||
@override
|
||
String storeNResults(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 's',
|
||
one: '',
|
||
);
|
||
return '$n result$_temp0';
|
||
}
|
||
|
||
@override
|
||
String get storeReloadTooltip => 'Reload';
|
||
|
||
@override
|
||
String get storeTodayBadge => 'TODAY';
|
||
|
||
@override
|
||
String get storeTodayDeck => 'From the F∆I editor';
|
||
|
||
@override
|
||
String get storeTodayDismissTooltip => 'Hide for this session';
|
||
|
||
@override
|
||
String get storePillInstalled => 'installed';
|
||
|
||
@override
|
||
String get storePillUpdate => 'update';
|
||
|
||
@override
|
||
String storeUpdateButton(String version) {
|
||
return 'Update to $version';
|
||
}
|
||
|
||
@override
|
||
String storeUpdateTooltip(String installed, String best) {
|
||
return 'Installed $installed — store has v$best';
|
||
}
|
||
|
||
@override
|
||
String get storeNoTagline => '(no tagline)';
|
||
|
||
@override
|
||
String get storeUninstallTitle => 'Uninstall module?';
|
||
|
||
@override
|
||
String storeUninstallBody(String name) {
|
||
return 'Removes $name from this hub. Flows that reference it will fail at the next run.';
|
||
}
|
||
|
||
@override
|
||
String storeInstalledToast(String name, String version) {
|
||
return '$name v$version installed.';
|
||
}
|
||
|
||
@override
|
||
String storeInstallFailedToast(String error) {
|
||
return 'Install failed: $error';
|
||
}
|
||
|
||
@override
|
||
String storeUninstalledToast(String name, String version) {
|
||
return '$name v$version uninstalled.';
|
||
}
|
||
|
||
@override
|
||
String storeUninstallFailedToast(String error) {
|
||
return 'Uninstall failed: $error';
|
||
}
|
||
|
||
@override
|
||
String storeOpenBrowserFailed(String error) {
|
||
return 'Could not open browser: $error';
|
||
}
|
||
|
||
@override
|
||
String get storeSectionTags => 'Tags';
|
||
|
||
@override
|
||
String get storeSectionRequiredCapabilities => 'Required capabilities';
|
||
|
||
@override
|
||
String get storeSectionRequiredHostServices => 'Required host services';
|
||
|
||
@override
|
||
String get storeSectionScreenshots => 'Screenshots';
|
||
|
||
@override
|
||
String get storeSectionDocumentation => 'Documentation';
|
||
|
||
@override
|
||
String get storeSectionSource => 'Source';
|
||
|
||
@override
|
||
String get storeInstallingButton => 'Installing…';
|
||
|
||
@override
|
||
String get storeNotInstallable => 'Not installable';
|
||
|
||
@override
|
||
String storeNotInstallableTooltip(String status) {
|
||
return 'Status \"$status\" — install path not yet wired.';
|
||
}
|
||
|
||
@override
|
||
String storeInstallProgressTitle(String name) {
|
||
return 'Installing $name';
|
||
}
|
||
|
||
@override
|
||
String get storeInstallProgressBody => 'Fetching, verifying, unpacking…';
|
||
|
||
@override
|
||
String get storeLoadDocs => 'Load documentation';
|
||
|
||
@override
|
||
String get storeDocsHint =>
|
||
'README rendered inline; uses the hub\'s registry token when needed.';
|
||
|
||
@override
|
||
String get storeDocsFetching => 'Fetching README…';
|
||
|
||
@override
|
||
String get storeOpenRepoButton => 'Open repository in browser';
|
||
|
||
@override
|
||
String get storeDocsErrorNotFound =>
|
||
'This module is not in the hub\'s store index.';
|
||
|
||
@override
|
||
String get storeDocsErrorNoDocs =>
|
||
'No repository URL is recorded for this module.';
|
||
|
||
@override
|
||
String get storeDocsErrorAuth =>
|
||
'The registry requires authentication to fetch this README. Set FAI_REGISTRY_TOKEN in the daemon\'s environment and restart the hub.';
|
||
|
||
@override
|
||
String storeDocsErrorNetwork(String detail) {
|
||
return 'Network error while fetching the README. $detail';
|
||
}
|
||
|
||
@override
|
||
String get storeDocsErrorParse => 'README is not valid UTF-8.';
|
||
|
||
@override
|
||
String get storeDocsErrorGeneric => 'Could not load README.';
|
||
|
||
@override
|
||
String get storeSourceLabel => 'Source';
|
||
|
||
@override
|
||
String get storeSourceAll => 'All sources';
|
||
|
||
@override
|
||
String get storeSourceNative => 'Native';
|
||
|
||
@override
|
||
String get storeSourceMcp => 'MCP';
|
||
|
||
@override
|
||
String get storeSourceN8n => 'n8n';
|
||
|
||
@override
|
||
String get storeProvenanceNative => 'native';
|
||
|
||
@override
|
||
String storeProvenanceMcp(String provider) {
|
||
return 'mcp · $provider';
|
||
}
|
||
|
||
@override
|
||
String storeProvenanceN8n(String provider) {
|
||
return 'n8n · $provider';
|
||
}
|
||
|
||
@override
|
||
String get storeRecommendedTitle => 'Add a public source — one click';
|
||
|
||
@override
|
||
String get storeRecommendedBody =>
|
||
'Curated MCP servers reachable over HTTPS. No subprocess, no API key, no Node. Federated capabilities appear in the store immediately.';
|
||
|
||
@override
|
||
String get storeRecommendedAddTooltip => 'Add and discover';
|
||
|
||
@override
|
||
String get storeRecommendedAdding => 'Adding…';
|
||
|
||
@override
|
||
String get storeRecommendedDeepWikiTagline =>
|
||
'GitHub repo documentation search (AI-powered)';
|
||
|
||
@override
|
||
String get storeRecommendedSemgrepTagline =>
|
||
'Security scanning for code vulnerabilities';
|
||
|
||
@override
|
||
String storeProviderAddedToast(String name, int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'capabilities',
|
||
one: 'capability',
|
||
);
|
||
return 'Added $name — $n federated $_temp0.';
|
||
}
|
||
|
||
@override
|
||
String storeProviderAddedZeroToast(String name) {
|
||
return '$name registered, but the server returned no capabilities yet. Open Settings → MCP Clients to retry discovery or check the server.';
|
||
}
|
||
|
||
@override
|
||
String storeProviderAddFailed(String name, String error) {
|
||
return 'Could not add $name: $error';
|
||
}
|
||
|
||
@override
|
||
String get auditTitle => 'Audit';
|
||
|
||
@override
|
||
String get auditNoEvents => 'No events yet';
|
||
|
||
@override
|
||
String get auditNoEventsHint =>
|
||
'Run a flow to populate the audit stream.\nEvents appear here within seconds.';
|
||
|
||
@override
|
||
String get auditFilterAll => 'all';
|
||
|
||
@override
|
||
String get auditFilterFlow => 'flow';
|
||
|
||
@override
|
||
String get auditFilterStep => 'step';
|
||
|
||
@override
|
||
String get auditFilterModule => 'module';
|
||
|
||
@override
|
||
String get auditClearLogTooltip => 'Clear log (local/dev channels only)';
|
||
|
||
@override
|
||
String auditClearedToast(int n, String channel) {
|
||
return 'Cleared $n events on channel \"$channel\". Chain reseeded with marker.';
|
||
}
|
||
|
||
@override
|
||
String auditClearFailed(String detail) {
|
||
return 'Clear failed: $detail';
|
||
}
|
||
|
||
@override
|
||
String get auditExplain => 'Explain';
|
||
|
||
@override
|
||
String get auditReask => 'Re-ask';
|
||
|
||
@override
|
||
String get auditAsking => 'Asking…';
|
||
|
||
@override
|
||
String get auditSystemAi => 'SYSTEM AI';
|
||
|
||
@override
|
||
String get auditCachedPill => 'cached';
|
||
|
||
@override
|
||
String auditOriginalLatency(int ms) {
|
||
return 'orig $ms ms';
|
||
}
|
||
|
||
@override
|
||
String auditLatency(int ms) {
|
||
return '$ms ms';
|
||
}
|
||
|
||
@override
|
||
String get auditRegenerateTooltip =>
|
||
'Regenerate — skip cache, ask the model again';
|
||
|
||
@override
|
||
String auditLiveStatus(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'events',
|
||
one: 'event',
|
||
);
|
||
return 'live · polling 2s · $n $_temp0';
|
||
}
|
||
|
||
@override
|
||
String auditDisconnected(String error) {
|
||
return 'disconnected · $error';
|
||
}
|
||
|
||
@override
|
||
String get auditHashChainVerified => 'hash chain verified';
|
||
|
||
@override
|
||
String get auditDetailHeader => 'DETAIL';
|
||
|
||
@override
|
||
String get auditAskingFull => 'Asking the configured System AI…';
|
||
|
||
@override
|
||
String get auditFixLabel => 'FIX';
|
||
|
||
@override
|
||
String auditCachedTooltipKnown(String at, String hits) {
|
||
return 'Served from the local cache. Originally generated on $at$hits.';
|
||
}
|
||
|
||
@override
|
||
String auditCachedTooltipUnknown(String hits) {
|
||
return 'Served from the local cache. Originally generated at unknown time$hits.';
|
||
}
|
||
|
||
@override
|
||
String auditCachedTooltipHits(int n) {
|
||
return ' · $n hits';
|
||
}
|
||
|
||
@override
|
||
String get auditConfigureSystemAi =>
|
||
'Configure System AI in Settings (Cmd+,)';
|
||
|
||
@override
|
||
String get auditClearDialogTitle => 'Clear audit log?';
|
||
|
||
@override
|
||
String get auditClearDialogBody =>
|
||
'Wipes every audit event on the active channel and seeds a fresh chain.reset marker carrying reviewer + reason. Refused on beta / production. Irreversible.';
|
||
|
||
@override
|
||
String get auditClearReviewerLabel => 'Reviewer';
|
||
|
||
@override
|
||
String get auditClearReasonLabel => 'Reason (recorded in chain.reset marker)';
|
||
|
||
@override
|
||
String get auditClearReasonHelper => 'Required — auditors will read this.';
|
||
|
||
@override
|
||
String get auditClearLogButton => 'Clear log';
|
||
|
||
@override
|
||
String get modulesTitle => 'Modules';
|
||
|
||
@override
|
||
String get modulesNoneTitle => 'No modules yet';
|
||
|
||
@override
|
||
String get modulesNoneHint =>
|
||
'Run `fai install <capability-name>` or check ~/.fai/modules/.';
|
||
|
||
@override
|
||
String get modulesReloadTooltip => 'Reload';
|
||
|
||
@override
|
||
String get modulesRecentActivity => 'RECENT ACTIVITY';
|
||
|
||
@override
|
||
String modulesRecentActivityHint(int n) {
|
||
return 'last $n install/uninstall events from the audit log';
|
||
}
|
||
|
||
@override
|
||
String get modulesActivityInstalled => 'installed';
|
||
|
||
@override
|
||
String get modulesActivityUninstalled => 'uninstalled';
|
||
|
||
@override
|
||
String get modulesCapabilitiesLabel => 'Capabilities';
|
||
|
||
@override
|
||
String get modulesUninstallTitle => 'Uninstall module?';
|
||
|
||
@override
|
||
String modulesUninstallBody(String name, String version) {
|
||
return 'Removes $name v$version from this hub. Flows that reference it will fail at the next run. A `module.uninstalled` audit event is recorded.';
|
||
}
|
||
|
||
@override
|
||
String modulesUninstalledToast(String name, String version) {
|
||
return 'Uninstalled $name v$version.';
|
||
}
|
||
|
||
@override
|
||
String modulesUninstallFailed(String error) {
|
||
return 'Uninstall failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get modulesUninstalling => 'Uninstalling…';
|
||
|
||
@override
|
||
String moduleSheetFailedToLoad(String error) {
|
||
return 'Failed to load: $error';
|
||
}
|
||
|
||
@override
|
||
String get moduleSheetCapabilities => 'Capabilities';
|
||
|
||
@override
|
||
String get moduleSheetPermissions => 'Declared permissions';
|
||
|
||
@override
|
||
String get moduleSheetNoPermissions => '(none — pure-computation module)';
|
||
|
||
@override
|
||
String get flowsTitle => 'Flows';
|
||
|
||
@override
|
||
String get flowsReloadTooltip => 'Reload';
|
||
|
||
@override
|
||
String get flowsNoneTitle => 'No saved flows';
|
||
|
||
@override
|
||
String get flowsNoneHint =>
|
||
'Save a flow with `fai admin flows save <name> <flow.yaml>` and it shows up here.';
|
||
|
||
@override
|
||
String flowsRunDialogTitle(String name) {
|
||
return 'Run $name';
|
||
}
|
||
|
||
@override
|
||
String get flowsRunDialogBody =>
|
||
'Inputs as key=value, one per line. All values are sent as text payloads. For binary inputs use the `fai run` CLI.';
|
||
|
||
@override
|
||
String get flowsInputsHint =>
|
||
'name=World\ntarget_language=English\nsummary_style=three bullet points';
|
||
|
||
@override
|
||
String get flowsRunButton => 'Run';
|
||
|
||
@override
|
||
String flowsRunningTitle(String name) {
|
||
return 'Running $name';
|
||
}
|
||
|
||
@override
|
||
String get flowsRunning => 'Flow running…';
|
||
|
||
@override
|
||
String get flowsNoOutputs => 'Flow completed with no declared outputs.';
|
||
|
||
@override
|
||
String get approvalsTitle => 'Approvals';
|
||
|
||
@override
|
||
String get approvalsTabPending => 'Pending';
|
||
|
||
@override
|
||
String get approvalsTabHistory => 'History';
|
||
|
||
@override
|
||
String get approvalsInboxZero => 'Inbox zero';
|
||
|
||
@override
|
||
String get approvalsInboxHint =>
|
||
'All caught up. New `system.approval@^0` steps land here automatically.';
|
||
|
||
@override
|
||
String get approvalsReloadTooltip => 'Reload';
|
||
|
||
@override
|
||
String get approvalsPillPending => 'pending';
|
||
|
||
@override
|
||
String get approvalsPillApproved => 'approved';
|
||
|
||
@override
|
||
String get approvalsPillRejected => 'rejected';
|
||
|
||
@override
|
||
String get approvalsPillExpired => 'expired';
|
||
|
||
@override
|
||
String get approvalsPayloadPreview => 'PAYLOAD PREVIEW';
|
||
|
||
@override
|
||
String get approvalsApproveButton => 'Approve';
|
||
|
||
@override
|
||
String get approvalsRejectButton => 'Reject';
|
||
|
||
@override
|
||
String get approvalsRejectDialogTitle => 'Reject approval';
|
||
|
||
@override
|
||
String get approvalsRejectReasonLabel => 'Reason (recorded in audit log)';
|
||
|
||
@override
|
||
String approvalsApprovedToast(String flow, String step) {
|
||
return 'approved · $flow › $step';
|
||
}
|
||
|
||
@override
|
||
String approvalsRejectedToast(String flow, String step) {
|
||
return 'rejected · $flow › $step';
|
||
}
|
||
|
||
@override
|
||
String approvalsApproveFailed(String error) {
|
||
return 'approve failed: $error';
|
||
}
|
||
|
||
@override
|
||
String approvalsRejectFailed(String error) {
|
||
return 'reject failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get approvalsHistoryEmpty => 'No history yet';
|
||
|
||
@override
|
||
String get approvalsHistoryEmptyHint =>
|
||
'Decided approvals (approved / rejected / expired) appear here.\nThe audit log keeps the full hash-chained record.';
|
||
|
||
@override
|
||
String get approvalsDialogDecided => 'decided';
|
||
|
||
@override
|
||
String get approvalsDialogCreated => 'created';
|
||
|
||
@override
|
||
String get approvalsDialogReason => 'reason';
|
||
|
||
@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 => 'Doctor';
|
||
|
||
@override
|
||
String get doctorSummaryModules => 'Modules';
|
||
|
||
@override
|
||
String get doctorSummaryApprovals => 'Approvals';
|
||
|
||
@override
|
||
String get doctorSummaryAudit => 'Audit';
|
||
|
||
@override
|
||
String get doctorSummaryServices => 'Services';
|
||
|
||
@override
|
||
String doctorSummaryCapabilities(int n) {
|
||
return '$n capabilities';
|
||
}
|
||
|
||
@override
|
||
String get doctorSummaryPending => 'pending';
|
||
|
||
@override
|
||
String doctorSummaryChain(int verified, int total) {
|
||
return '$verified/$total chain';
|
||
}
|
||
|
||
@override
|
||
String get doctorSummaryDeclared => 'declared';
|
||
|
||
@override
|
||
String doctorModulesPanelSummary(int n, int m) {
|
||
return '$n modules · $m capabilities';
|
||
}
|
||
|
||
@override
|
||
String get doctorApprovalsNone => 'No pending approvals';
|
||
|
||
@override
|
||
String doctorApprovalsCount(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: '$n approvals awaiting review',
|
||
one: '1 approval awaiting review',
|
||
);
|
||
return '$_temp0';
|
||
}
|
||
|
||
@override
|
||
String get doctorApprovalsAttentionPill => 'attention';
|
||
|
||
@override
|
||
String get doctorServicesEmpty => 'No host services declared';
|
||
|
||
@override
|
||
String get doctorServicesEmptyHint =>
|
||
'add to ~/.fai/config.yaml under services:';
|
||
|
||
@override
|
||
String get doctorPillLoaded => 'loaded';
|
||
|
||
@override
|
||
String get doctorPillEmpty => 'empty';
|
||
|
||
@override
|
||
String get doctorRecheckTooltip => 'Re-check';
|
||
|
||
@override
|
||
String get doctorEventLogSection => 'Event log';
|
||
|
||
@override
|
||
String get doctorModulesApprovalsSection => 'Modules & approvals';
|
||
|
||
@override
|
||
String get doctorHostServicesSection => 'Host services';
|
||
|
||
@override
|
||
String get doctorDaemonFilesSection => 'Daemon files';
|
||
|
||
@override
|
||
String get doctorDaemonControlSection => 'Daemon control';
|
||
|
||
@override
|
||
String get doctorChainIntact => 'Hash chain intact';
|
||
|
||
@override
|
||
String doctorChainIntactDetail(int n) {
|
||
return '$n events · prev_event_sha256 verified end-to-end';
|
||
}
|
||
|
||
@override
|
||
String get doctorChainTampered => 'Tampering detected';
|
||
|
||
@override
|
||
String doctorChainTamperedDetail(int verified, int total, String id) {
|
||
return '$verified of $total verified before mismatch at $id';
|
||
}
|
||
|
||
@override
|
||
String get doctorChainPillOk => 'WORM-1';
|
||
|
||
@override
|
||
String get doctorChainPillTamper => 'TAMPER';
|
||
|
||
@override
|
||
String get doctorVerifyNow => 'Verify now';
|
||
|
||
@override
|
||
String get doctorRestart => 'Restart';
|
||
|
||
@override
|
||
String get doctorStart => 'Start';
|
||
|
||
@override
|
||
String get doctorStop => 'Stop';
|
||
|
||
@override
|
||
String get doctorStatusAction => 'Status';
|
||
|
||
@override
|
||
String doctorRunningOn(String name, String endpoint) {
|
||
return 'Running on $name: $endpoint';
|
||
}
|
||
|
||
@override
|
||
String doctorStoppedOn(String name) {
|
||
return '$name daemon stopped';
|
||
}
|
||
|
||
@override
|
||
String get doctorStatusUnknown => 'Daemon status: …';
|
||
|
||
@override
|
||
String get doctorPillRunning => 'running';
|
||
|
||
@override
|
||
String get doctorPillStopped => 'stopped';
|
||
|
||
@override
|
||
String get doctorDaemonControlHint =>
|
||
'Studio shells out to the platform binary — mirrors `fai daemon …` exactly so the CLI and UI stay in lockstep.';
|
||
|
||
@override
|
||
String get doctorDaemonControlWorking => 'Working…';
|
||
|
||
@override
|
||
String get doctorPathLog => 'Log';
|
||
|
||
@override
|
||
String get doctorPathConfig => 'Config';
|
||
|
||
@override
|
||
String get doctorPathDb => 'Audit DB';
|
||
|
||
@override
|
||
String get doctorPathModules => 'Modules dir';
|
||
|
||
@override
|
||
String get doctorPathFlows => 'Flows dir';
|
||
|
||
@override
|
||
String get doctorPathPid => 'PID file';
|
||
|
||
@override
|
||
String get doctorPathsEmpty =>
|
||
'Daemon did not report file paths. Update the running hub via `fai daemon restart`.';
|
||
|
||
@override
|
||
String doctorOpenError(String detail) {
|
||
return 'Could not open: $detail';
|
||
}
|
||
|
||
@override
|
||
String doctorUpdateAvailable(String version) {
|
||
return 'Update available — $version';
|
||
}
|
||
|
||
@override
|
||
String doctorUpdateBody(String channel, String version) {
|
||
return 'Channel $channel now offers $version. Apply via the button — Studio shells out to `fai update apply --channel $channel`.';
|
||
}
|
||
|
||
@override
|
||
String get doctorUpdateUnreachable => 'Release host unreachable';
|
||
|
||
@override
|
||
String doctorUpdateUnreachableBody(String channel) {
|
||
return 'Could not contact the release feed for $channel.';
|
||
}
|
||
|
||
@override
|
||
String doctorReleaseNotes(String url) {
|
||
return 'notes: $url';
|
||
}
|
||
|
||
@override
|
||
String get doctorPillNew => 'new';
|
||
|
||
@override
|
||
String get doctorPillOffline => 'offline';
|
||
|
||
@override
|
||
String get doctorApplyUpdate => 'Apply update';
|
||
|
||
@override
|
||
String get doctorApplying => 'Applying…';
|
||
|
||
@override
|
||
String get doctorApplyDone =>
|
||
'Update applied. Restart Studio to see the new daemon version.';
|
||
|
||
@override
|
||
String get mcpHeader => 'MCP CLIENTS';
|
||
|
||
@override
|
||
String get mcpHint =>
|
||
'External MCP servers federate their tools as `mcp.<server>.<tool>` capabilities. Configure once, see them in the Store.';
|
||
|
||
@override
|
||
String get mcpEmpty => 'No MCP servers configured. Click + to add one.';
|
||
|
||
@override
|
||
String get n8nHeader => 'N8N ENDPOINTS';
|
||
|
||
@override
|
||
String get n8nHint =>
|
||
'Active n8n workflows surface as `n8n.<endpoint>.<slug>` capabilities. Configure once, see them in the Store.';
|
||
|
||
@override
|
||
String get n8nEmpty => 'No n8n endpoints configured. Click + to add one.';
|
||
|
||
@override
|
||
String get hubUnreachable => 'Hub unreachable';
|
||
|
||
@override
|
||
String get hubUnreachableHint => 'Start the hub with `fai serve`.';
|
||
|
||
@override
|
||
String get languageEnglish => 'English';
|
||
|
||
@override
|
||
String get languageGerman => 'Deutsch';
|
||
|
||
@override
|
||
String get searchHint => 'Jump anywhere — modules, store, flows, pages…';
|
||
|
||
@override
|
||
String get searchIndexing => 'Indexing…';
|
||
|
||
@override
|
||
String get searchNoMatches => 'No matches.';
|
||
|
||
@override
|
||
String get searchHintNavigate => '↑↓ navigate';
|
||
|
||
@override
|
||
String get searchHintOpen => 'enter open';
|
||
|
||
@override
|
||
String get searchHintClose => 'esc close';
|
||
|
||
@override
|
||
String get searchGroupPages => 'Pages';
|
||
|
||
@override
|
||
String get searchGroupModules => 'Modules';
|
||
|
||
@override
|
||
String get searchGroupStore => 'Store';
|
||
|
||
@override
|
||
String get searchGroupFlows => 'Flows';
|
||
|
||
@override
|
||
String get searchSettingsLabel => 'Settings';
|
||
|
||
@override
|
||
String searchPageHint(int n) {
|
||
return 'page · ⌘$n';
|
||
}
|
||
|
||
@override
|
||
String get searchSettingsHint => 'hub endpoint, channels, system AI · ⌘;';
|
||
|
||
@override
|
||
String searchInstalledModuleHint(String version) {
|
||
return 'installed module · v$version';
|
||
}
|
||
|
||
@override
|
||
String get searchStoreUncategorized => 'uncategorized';
|
||
|
||
@override
|
||
String searchStoreHintWithTagline(String tagline) {
|
||
return 'store · $tagline';
|
||
}
|
||
|
||
@override
|
||
String searchStoreHintWithCategory(String category) {
|
||
return 'store · $category';
|
||
}
|
||
|
||
@override
|
||
String get searchSavedFlowHint => 'saved flow';
|
||
|
||
@override
|
||
String get systemAiTitle => 'System AI';
|
||
|
||
@override
|
||
String get systemAiIntro =>
|
||
'The hub-internal LLM the platform itself uses for inline failure explanations and operator help. Off by default; configure here. See docs/architecture/system-ai.md for what crosses the wire.';
|
||
|
||
@override
|
||
String get systemAiProviderLabel => 'Provider';
|
||
|
||
@override
|
||
String get systemAiEndpointLabel => 'Endpoint URL (up to /v1)';
|
||
|
||
@override
|
||
String get systemAiApiKeyRequired => 'API key env var (required)';
|
||
|
||
@override
|
||
String get systemAiApiKeyOptional => 'API key env var (optional)';
|
||
|
||
@override
|
||
String systemAiApiKeyDisclaimer(String name) {
|
||
return 'Studio never reads or stores the key value — only its env-var name. The hub reads `\$$name` at request time.';
|
||
}
|
||
|
||
@override
|
||
String get systemAiTestConnection => 'Test connection';
|
||
|
||
@override
|
||
String get systemAiTesting => 'Testing…';
|
||
|
||
@override
|
||
String get systemAiSave => 'Save';
|
||
|
||
@override
|
||
String get systemAiPrivacyHeader => 'PRIVACY MODE';
|
||
|
||
@override
|
||
String get systemAiPrivacyOffLabel => 'Off';
|
||
|
||
@override
|
||
String get systemAiPrivacyOffDesc =>
|
||
'Feature disabled. No requests leave the hub.';
|
||
|
||
@override
|
||
String get systemAiPrivacyRedactedLabel => 'Redacted';
|
||
|
||
@override
|
||
String get systemAiPrivacyRedactedDesc =>
|
||
'Only event_type / error / module names. KRITIS-friendly default.';
|
||
|
||
@override
|
||
String get systemAiPrivacyFullLabel => 'Full';
|
||
|
||
@override
|
||
String get systemAiPrivacyFullDesc =>
|
||
'Includes the audit detail JSON (hash-only — no raw payloads).';
|
||
|
||
@override
|
||
String get systemAiConnectionOk => 'Connection ok';
|
||
|
||
@override
|
||
String get systemAiConnectionFailed => 'Connection failed';
|
||
|
||
@override
|
||
String systemAiReplyPrefix(String text) {
|
||
return 'Reply: $text';
|
||
}
|
||
|
||
@override
|
||
String get systemAiModelLabel => 'Model (required)';
|
||
|
||
@override
|
||
String get systemAiModelHintFallback =>
|
||
'model identifier the provider expects';
|
||
|
||
@override
|
||
String get systemAiModelHelperBase =>
|
||
'Required: pick from the list (Refresh) or type one.';
|
||
|
||
@override
|
||
String get systemAiModelHelperOllama =>
|
||
'Required: pick from the list (Refresh) or type one. Use Pull to download from Ollama.';
|
||
|
||
@override
|
||
String get systemAiRefresh => 'Refresh';
|
||
|
||
@override
|
||
String get systemAiPull => 'Pull';
|
||
|
||
@override
|
||
String get systemAiPulling => 'Pulling…';
|
||
|
||
@override
|
||
String systemAiCouldNotListModels(String error) {
|
||
return 'Could not list models: $error';
|
||
}
|
||
|
||
@override
|
||
String get systemAiNoModelsOllama =>
|
||
'No models on the Ollama server yet. Type one above and click Pull.';
|
||
|
||
@override
|
||
String get systemAiNoModelsGeneric => 'Provider returned no models.';
|
||
|
||
@override
|
||
String get systemAiSuitabilityRecommended => 'recommended';
|
||
|
||
@override
|
||
String get systemAiSuitabilityBalanced => 'balanced';
|
||
|
||
@override
|
||
String get systemAiSuitabilitySmall => 'small — quality may be limited';
|
||
|
||
@override
|
||
String get systemAiSuitabilityLarge => 'large — slower';
|
||
|
||
@override
|
||
String get systemAiSuitabilityHuge => 'huge — likely too slow on a laptop';
|
||
|
||
@override
|
||
String get systemAiSuitabilityUnknown => 'size unknown';
|
||
|
||
@override
|
||
String systemAiHwDetected(String summary) {
|
||
return 'Detected: $summary';
|
||
}
|
||
|
||
@override
|
||
String systemAiHwReviewed(String date) {
|
||
return ' · curation reviewed $date';
|
||
}
|
||
|
||
@override
|
||
String systemAiLegendRecommended(String tier) {
|
||
return 'recommended for this hardware$tier';
|
||
}
|
||
|
||
@override
|
||
String get systemAiLegendBalanced => 'balanced (4-8B)';
|
||
|
||
@override
|
||
String get systemAiLegendSmallLarge =>
|
||
'small <3B / large 9-15B / above hardware';
|
||
|
||
@override
|
||
String get systemAiLegendHuge => 'huge >15B';
|
||
|
||
@override
|
||
String get systemAiLegendUnknown => 'size unknown';
|
||
|
||
@override
|
||
String systemAiCacheRow(int n) {
|
||
String _temp0 = intl.Intl.pluralLogic(
|
||
n,
|
||
locale: localeName,
|
||
other: 'explanations',
|
||
one: 'explanation',
|
||
);
|
||
return 'Cache: $n cached $_temp0. Identical prompts hit the cache; switching model or privacy mode flushes automatically.';
|
||
}
|
||
|
||
@override
|
||
String get systemAiCacheClear => 'Clear';
|
||
|
||
@override
|
||
String systemAiCacheClearedToast(int n) {
|
||
return 'Cleared $n cached System-AI explanations.';
|
||
}
|
||
|
||
@override
|
||
String systemAiCacheClearFailed(String error) {
|
||
return 'Cache clear failed: $error';
|
||
}
|
||
|
||
@override
|
||
String get systemAiPullEmptyError =>
|
||
'Type a model id (e.g. gemma3:4b) first.';
|
||
|
||
@override
|
||
String systemAiPullFailedError(String error) {
|
||
return 'Pull failed: $error';
|
||
}
|
||
}
|