Two reports:
1. "In Diagnose ist viel nicht übersetzt, wie pending, chain
etc." The Doctor summary strip (Modules / Approvals / Audit
/ Services tiles) and the modules panel still rendered
English wire labels: "pending", "chain", "declared",
"loaded", "empty", "attention", "No pending approvals",
"No host services declared", and the matching "{n} modules
· {m} capabilities" / "{n} approvals awaiting review"
strings.
Fix: 13 new ARB keys covering the summary tiles, modules
panel, and services panel; doctor.dart now reads them via
AppLocalizations. German operators no longer see English
labels on Diagnose.
2. "Im Light mode ist der kontrast zur überschrift falsch,
store ist weiß auf weiß." The AppBar title rendered
white-on-white in light mode.
Cause: `appBarTheme.titleTextStyle = textTheme.headlineSmall`
passed a TextStyle built fresh from GoogleFonts.inter(...)
with `color: null`. Material's "merge foregroundColor at
draw time" path didn't always populate it — depended on
build configuration. The colour fell through to whatever
the surrounding DefaultTextStyle had, which on the
light-mode AppBar was the surface colour.
Fix: bake the foreground colour straight into the title
style via `copyWith(color: scheme.onSurface)`. Also pin
`iconTheme: IconThemeData(color: scheme.onSurface)` so
actions-row icons get the same treatment defensively.
Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
1481 lines
34 KiB
Dart
1481 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 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';
|
||
}
|
||
}
|