feat(editor): localised analyzer/strip/run messages + monospace font fallback

Closes operator-reported issues around the text-tab font and
the English-only run + diagnostic surfaces.

  - **Real monospace everywhere**. The package never bundled
    JetBrains Mono as an asset (it relied on Studio's
    google_fonts pre-load), so a host that doesn't ship the
    font saw the YAML editor render in the system proportional
    default. New _monoTextStyle() pins fontFamilyFallback to a
    cross-platform monospace chain (Menlo / Consolas / Courier
    New / monospace) so the editor stays a grid in every host.
    Applied to the code field, gutter, diagnostic strip,
    issue rows, hover card, fix buttons, and the run tab's
    error box.

  - **Locale-aware analyzer messages**. New AnalyzerStrings
    adapter holds every string the analyzer emits, with an
    .english default + an .from(FlowEditorStrings) factory.
    FlowYamlCodeController.setCapabilityProviders takes the
    strings; FlowEditorPage wires them from the active locale.
    The analyzer's 'Unknown capability', 'Did you mean',
    'Not in the store — install locally with fai install
    --link', 'Unknown input/output type', YAML parse errors,
    and every quick-fix label (Install / Add source / Use /
    Change to) now flip to DE when the editor's locale is DE.

  - **Localised run + diagnostic chrome**. The bottom strip's
    'No issues', '2 errors · 1 warning', 'Copy all'; the
    issue row's L-prefix + Copy tooltip; the hover card's
    L-prefix + Copy tooltip; the run-block tooltip + inline
    message ('2 Fehler verhindern den Lauf · siehe
    Diagnose-Leiste unten'); the step-row 'awaiting approval'
    suffix; the CopyableErrorBox's Copy / Copied tooltip —
    all now flow through FlowEditorStrings.

Bumped to 0.20.0.

Signed-off-by: flemming-it <sf@flemming.it>
This commit is contained in:
flemming-it 2026-06-09 01:36:39 +02:00
parent b6bb8741a9
commit 5cd2745db5
6 changed files with 306 additions and 97 deletions

View file

@ -183,7 +183,10 @@ class _RunTabState extends State<RunTab> {
if (_error != null) ...[
const SizedBox(height: FaiSpace.lg),
_section(theme, strings.runTitleFailed),
_CopyableErrorBox(text: _error.toString()),
_CopyableErrorBox(
text: _error.toString(),
strings: widget.strings,
),
],
],
),
@ -300,6 +303,7 @@ class _RunTabState extends State<RunTab> {
}
Widget _stepRow(ThemeData theme, String id, _StepState state) {
final strings = widget.strings;
final IconData glyph;
final Color color;
String suffix = '';
@ -317,7 +321,7 @@ class _RunTabState extends State<RunTab> {
case _StepKind.awaiting:
glyph = Icons.pause_circle_outline;
color = theme.colorScheme.tertiary;
suffix = ' awaiting approval';
suffix = ' ${strings.runAwaitingApproval}';
}
final isError = state.kind == _StepKind.error &&
state.error != null &&
@ -347,7 +351,10 @@ class _RunTabState extends State<RunTab> {
const SizedBox(height: 4),
Padding(
padding: const EdgeInsets.only(left: 24),
child: _CopyableErrorBox(text: state.error!),
child: _CopyableErrorBox(
text: state.error!,
strings: widget.strings,
),
),
],
],
@ -365,9 +372,7 @@ class _RunTabState extends State<RunTab> {
return Row(
children: [
Tooltip(
message: blocked
? '$errors error${errors == 1 ? '' : 's'} prevent the run'
: '',
message: blocked ? strings.runErrorsBlockTooltip(errors) : '',
child: FilledButton.icon(
onPressed: _running || widget.driver == null || blocked
? null
@ -389,8 +394,8 @@ class _RunTabState extends State<RunTab> {
const SizedBox(width: FaiSpace.sm),
Flexible(
child: Text(
'$errors error${errors == 1 ? '' : 's'} prevent the run · '
'check the diagnostic strip',
'${strings.runErrorsBlockRun(errors)} · '
'${strings.runErrorsBlockHint}',
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.error,
),
@ -619,7 +624,8 @@ class _StepState {
/// so flow_editor doesn't depend on Studio internals.
class _CopyableErrorBox extends StatefulWidget {
final String text;
const _CopyableErrorBox({required this.text});
final FlowEditorStrings strings;
const _CopyableErrorBox({required this.text, required this.strings});
@override
State<_CopyableErrorBox> createState() => _CopyableErrorBoxState();
@ -661,7 +667,8 @@ class _CopyableErrorBoxState extends State<_CopyableErrorBox> {
Align(
alignment: Alignment.centerRight,
child: Tooltip(
message: _justCopied ? 'Copied' : 'Copy',
message:
_justCopied ? widget.strings.runCopied : widget.strings.runCopy,
child: IconButton(
icon: Icon(
_justCopied ? Icons.check : Icons.content_copy,
@ -682,6 +689,12 @@ class _CopyableErrorBoxState extends State<_CopyableErrorBox> {
widget.text,
style: TextStyle(
fontFamily: 'JetBrains Mono',
fontFamilyFallback: const [
'Menlo',
'Consolas',
'Courier New',
'monospace',
],
fontSize: 12,
color: theme.colorScheme.onErrorContainer,
),