feat(studio): Flows + Module sheet + System-AI editor i18n (v0.28.0)

- Localize Flows page: app-bar title and reload tooltip,
  hub-unreachable / no-saved-flows empty states, run-flow input
  dialog (title with flow name, description, hint, Cancel /
  Run), running dialog (title, "Flow running…" status, no-output
  message, Close button), flow-card Run button.
- Localize the module-sheet bottom sheet: failed-to-load text,
  Capabilities and "Declared permissions" section headers,
  no-permissions placeholder copy.
- Localize the System-AI configuration dialog: title, intro
  paragraph, provider dropdown label, endpoint label, API-key
  env-var label (required vs optional) and disclaimer, privacy
  mode header and three options (Off / Redacted / Full) plus
  their descriptions, test-result panel ("Connection ok" /
  "Connection failed", "Reply: …" prefix), model picker (label,
  hint fallback, helper text with Ollama variant, Refresh /
  Pull / Pulling… buttons, list errors and empty states),
  hardware banner ("Detected: …" + " · curation reviewed …"
  suffix), suitability legend (recommended / balanced / small /
  large / huge / unknown), cache row with pluralized count and
  Clear button, cache cleared / clear-failed toasts, pull-empty
  / pull-failed errors. Suitability label moved off a getter
  onto a `labelFor(BuildContext)` method so it can read the
  current locale.

Provider preset descriptions and modelHint strings stay in
English in `_ProviderPreset.all` — they're tightly coupled to
the wire-protocol identifiers and would require a runtime
factory rebuild rather than a const list.

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-05-08 02:59:08 +02:00
parent e2b2639a86
commit b5a4c74c4b
10 changed files with 1120 additions and 91 deletions

View file

@ -679,6 +679,60 @@ class AppLocalizationsEn extends AppLocalizations {
@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';
@ -1017,4 +1071,187 @@ class AppLocalizationsEn extends AppLocalizations {
@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';
}
}