fix(l10n): low-severity language findings from the usertest panel
Some checks are pending
Security / Security check (push) Waiting to run

- 'Mit Endpunkt verbinden' — no Endpoint/Endpunkt mix
- audit-chain lead term is 'Hash-Kette' everywhere (doctor pill);
  chain detail says 'Verkettung lückenlos geprüft' instead of the
  raw field name prev_event_sha256
- welcome checklist line says who refreshes what
- setup privacy note explains the local model instead of ending in
  a bare model tag
- default project renders localized ('Allgemein') in the switcher;
  sealed-area status pills explain run state on hover

Signed-off-by: flemming-it <stefan.a.flemming@googlemail.com>
This commit is contained in:
flemming-it 2026-07-18 00:33:27 +02:00
parent 32e2510c63
commit 12b2e8327a
6 changed files with 99 additions and 30 deletions

View file

@ -75,7 +75,7 @@
}
},
"welcomeChecklistHeader": "ERSTE SCHRITTE",
"welcomeChecklistBody": "Vier Schritte zu einem funktionierenden Hub. Live-Zustand — nach jeder Änderung aktualisieren.",
"welcomeChecklistBody": "Vier Schritte zu einem funktionierenden Hub. Die Liste zeigt den Live-Zustand — nach einer Änderung oben rechts aktualisieren.",
"welcomeChecklistAi": "System-KI konfigurieren",
"welcomeChecklistAiHint": "Einstellungen → System-KI. Wird für die KI-Suche und Fehlererklärungen gebraucht.",
"welcomeChecklistMcp": "Öffentlichen Werkzeug-Katalog verbinden",
@ -163,7 +163,7 @@
"settingsHost": "Host",
"settingsPort": "Port",
"settingsTls": "TLS",
"settingsSaveAndConnect": "Mit Endpoint verbinden",
"settingsSaveAndConnect": "Mit Endpunkt verbinden",
"settingsLanguage": "Sprache",
"settingsLanguageHint": "Sprache der App. Wirkt auf alle Seiten; mehrsprachige Store-Einträge folgen ebenfalls.",
"settingsHubEndpointHint": "Wohin soll Studio sich verbinden? Standard ist der lokale Hub auf 127.0.0.1:50051.",
@ -1212,7 +1212,7 @@
"doctorDaemonFilesSection": "Daemon-Dateien",
"doctorDaemonControlSection": "Daemon-Steuerung",
"doctorChainIntact": "Hash-Kette intakt",
"doctorChainIntactDetail": "{n} {n, plural, =1{Ereignis} other{Ereignisse}} · prev_event_sha256 lückenlos verifiziert",
"doctorChainIntactDetail": "{n} {n, plural, =1{Ereignis} other{Ereignisse}} · Verkettung lückenlos geprüft",
"@doctorChainIntactDetail": {
"placeholders": {
"n": {
@ -1235,7 +1235,7 @@
}
}
},
"doctorChainPillOk": "Integritätskette geprüft",
"doctorChainPillOk": "Hash-Kette geprüft",
"doctorChainPillTamper": "MANIPULIERT",
"doctorVerifyNow": "Jetzt prüfen",
"doctorRestart": "Neustart",
@ -1741,6 +1741,7 @@
"federationCopied": "In die Zwischenablage kopiert",
"federationEnrollmentHint": "Übergeben Sie das Token dem Satelliten-Betreiber über einen sicheren Kanal. Die mitgelieferte Zertifikatsstelle authentifiziert die erste Verbindung des Satelliten.",
"workspaceAll": "Alle Projekte",
"workspaceDefaultProject": "Allgemein",
"workspaceSwitcherTooltip": "Arbeitsbereich — filtert diese Ansicht und stempelt neue Läufe mit dem gewählten Projekt",
"workspaceProtectedHint": "Geschützt: logisch getrennt im gemeinsamen Hub — keine harte Prozessgrenze. Kritische Mandate nutzen einen abgeschotteten Bereich.",
"runsTitle": "Läufe",
@ -1765,6 +1766,8 @@
"workspaceSealedHeader": "ABGESCHOTTETE BEREICHE",
"workspaceSealedRunning": "läuft",
"workspaceSealedStopped": "gestoppt",
"workspaceSealedRunningHint": "Der abgeschottete Bereich läuft als eigener Hub-Prozess. Auswählen wechselt hinein.",
"workspaceSealedStoppedHint": "Der abgeschottete Bereich ist gerade nicht gestartet. Auswählen startet ihn und wechselt hinein.",
"workspaceSealedStarting": "Starte abgeschotteten Bereich „{name}“…",
"@workspaceSealedStarting": {"placeholders": {"name": {"type": "String"}}},
"workspaceSealedStarted": "Abgeschotteter Bereich „{name}“ gestartet.",
@ -1854,7 +1857,7 @@
"setupApplyNotes": "Hinweise aus der Einrichtung",
"setupFreeTextHint": "z. B.: Eingehende Anträge vorprüfen und unvollständige markieren",
"setupFreeTextSuggest": "Vorschlagen lassen",
"setupFreeTextPrivacyLocal": "Ihre Beschreibung wird lokal auf diesem Rechner verarbeitet ({model}).",
"setupFreeTextPrivacyLocal": "Ihre Beschreibung wird direkt auf diesem Rechner verarbeitet — durch das lokale KI-Modell {model}. Nichts verlässt das Gerät.",
"@setupFreeTextPrivacyLocal": {"placeholders": {"model": {"type": "String"}}},
"setupFreeTextPrivacyRemote": "Ihre Beschreibung wird an die eingerichtete System-KI gesendet: {model} ({provider}).",
"@setupFreeTextPrivacyRemote": {"placeholders": {"model": {"type": "String"}, "provider": {"type": "String"}}},

View file

@ -83,7 +83,7 @@
}
},
"welcomeChecklistHeader": "GETTING STARTED",
"welcomeChecklistBody": "Four steps to a working hub. Live state — refresh after changing anything.",
"welcomeChecklistBody": "Four steps to a working hub. The list shows the live state — refresh top right after changing anything.",
"welcomeChecklistAi": "Configure System AI",
"welcomeChecklistAiHint": "Settings → System AI. Required for the AI search and inline failure explanations.",
"welcomeChecklistMcp": "Connect a public tool catalog",
@ -1236,7 +1236,7 @@
"doctorDaemonFilesSection": "Daemon files",
"doctorDaemonControlSection": "Daemon control",
"doctorChainIntact": "Hash chain intact",
"doctorChainIntactDetail": "{n} {n, plural, =1{event} other{events}} · prev_event_sha256 verified end-to-end",
"doctorChainIntactDetail": "{n} {n, plural, =1{event} other{events}} · linkage verified end-to-end",
"@doctorChainIntactDetail": {
"placeholders": {
"n": {
@ -1259,7 +1259,7 @@
}
}
},
"doctorChainPillOk": "Integrity chain verified",
"doctorChainPillOk": "Hash chain verified",
"doctorChainPillTamper": "TAMPER",
"doctorVerifyNow": "Verify now",
"doctorRestart": "Restart",
@ -1780,6 +1780,7 @@
"federationCopied": "Copied to clipboard",
"federationEnrollmentHint": "Hand the token to the satellite operator over a secure channel. The bundled CA authenticates the satellite's first connect.",
"workspaceAll": "All projects",
"workspaceDefaultProject": "General",
"workspaceSwitcherTooltip": "Workspace — filters this view and stamps new runs with the selected project",
"workspaceProtectedHint": "Protected: logically separated in the shared hub — no hard process barrier. Critical engagements use a sealed area.",
"runsTitle": "Runs",
@ -1804,6 +1805,8 @@
"workspaceSealedHeader": "SEALED AREAS",
"workspaceSealedRunning": "running",
"workspaceSealedStopped": "stopped",
"workspaceSealedRunningHint": "The sealed area runs as its own hub process. Selecting it switches in.",
"workspaceSealedStoppedHint": "The sealed area is not running right now. Selecting it starts it and switches in.",
"workspaceSealedStarting": "Starting sealed area “{name}”…",
"@workspaceSealedStarting": {"placeholders": {"name": {"type": "String"}}},
"workspaceSealedStarted": "Started sealed area “{name}”.",
@ -1893,7 +1896,7 @@
"setupApplyNotes": "Notes from the setup",
"setupFreeTextHint": "e.g.: pre-screen incoming applications and flag incomplete ones",
"setupFreeTextSuggest": "Suggest a setup",
"setupFreeTextPrivacyLocal": "Your description is processed locally on this machine ({model}).",
"setupFreeTextPrivacyLocal": "Your description is processed right on this machine — by the local AI model {model}. Nothing leaves the device.",
"@setupFreeTextPrivacyLocal": {"placeholders": {"model": {"type": "String"}}},
"setupFreeTextPrivacyRemote": "Your description is sent to the configured system AI: {model} ({provider}).",
"@setupFreeTextPrivacyRemote": {"placeholders": {"model": {"type": "String"}, "provider": {"type": "String"}}},

View file

@ -509,7 +509,7 @@ abstract class AppLocalizations {
/// No description provided for @welcomeChecklistBody.
///
/// In en, this message translates to:
/// **'Four steps to a working hub. Live state — refresh after changing anything.'**
/// **'Four steps to a working hub. The list shows the live state — refresh top right after changing anything.'**
String get welcomeChecklistBody;
/// No description provided for @welcomeChecklistAi.
@ -3731,7 +3731,7 @@ abstract class AppLocalizations {
/// No description provided for @doctorChainIntactDetail.
///
/// In en, this message translates to:
/// **'{n} {n, plural, =1{event} other{events}} · prev_event_sha256 verified end-to-end'**
/// **'{n} {n, plural, =1{event} other{events}} · linkage verified end-to-end'**
String doctorChainIntactDetail(int n);
/// No description provided for @doctorChainTampered.
@ -3749,7 +3749,7 @@ abstract class AppLocalizations {
/// No description provided for @doctorChainPillOk.
///
/// In en, this message translates to:
/// **'Integrity chain verified'**
/// **'Hash chain verified'**
String get doctorChainPillOk;
/// No description provided for @doctorChainPillTamper.
@ -5281,6 +5281,12 @@ abstract class AppLocalizations {
/// **'All projects'**
String get workspaceAll;
/// No description provided for @workspaceDefaultProject.
///
/// In en, this message translates to:
/// **'General'**
String get workspaceDefaultProject;
/// No description provided for @workspaceSwitcherTooltip.
///
/// In en, this message translates to:
@ -5413,6 +5419,18 @@ abstract class AppLocalizations {
/// **'stopped'**
String get workspaceSealedStopped;
/// No description provided for @workspaceSealedRunningHint.
///
/// In en, this message translates to:
/// **'The sealed area runs as its own hub process. Selecting it switches in.'**
String get workspaceSealedRunningHint;
/// No description provided for @workspaceSealedStoppedHint.
///
/// In en, this message translates to:
/// **'The sealed area is not running right now. Selecting it starts it and switches in.'**
String get workspaceSealedStoppedHint;
/// No description provided for @workspaceSealedStarting.
///
/// In en, this message translates to:
@ -5884,7 +5902,7 @@ abstract class AppLocalizations {
/// No description provided for @setupFreeTextPrivacyLocal.
///
/// In en, this message translates to:
/// **'Your description is processed locally on this machine ({model}).'**
/// **'Your description is processed right on this machine — by the local AI model {model}. Nothing leaves the device.'**
String setupFreeTextPrivacyLocal(String model);
/// No description provided for @setupFreeTextPrivacyRemote.

View file

@ -247,7 +247,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get welcomeChecklistBody =>
'Vier Schritte zu einem funktionierenden Hub. Live-Zustand — nach jeder Änderung aktualisieren.';
'Vier Schritte zu einem funktionierenden Hub. Die Liste zeigt den Live-Zustand — nach einer Änderung oben rechts aktualisieren.';
@override
String get welcomeChecklistAi => 'System-KI konfigurieren';
@ -499,7 +499,7 @@ class AppLocalizationsDe extends AppLocalizations {
String get settingsTls => 'TLS';
@override
String get settingsSaveAndConnect => 'Mit Endpoint verbinden';
String get settingsSaveAndConnect => 'Mit Endpunkt verbinden';
@override
String get settingsLanguage => 'Sprache';
@ -2194,7 +2194,7 @@ class AppLocalizationsDe extends AppLocalizations {
other: 'Ereignisse',
one: 'Ereignis',
);
return '$n $_temp0 · prev_event_sha256 lückenlos verifiziert';
return '$n $_temp0 · Verkettung lückenlos geprüft';
}
@override
@ -2206,7 +2206,7 @@ class AppLocalizationsDe extends AppLocalizations {
}
@override
String get doctorChainPillOk => 'Integritätskette geprüft';
String get doctorChainPillOk => 'Hash-Kette geprüft';
@override
String get doctorChainPillTamper => 'MANIPULIERT';
@ -3126,6 +3126,9 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get workspaceAll => 'Alle Projekte';
@override
String get workspaceDefaultProject => 'Allgemein';
@override
String get workspaceSwitcherTooltip =>
'Arbeitsbereich — filtert diese Ansicht und stempelt neue Läufe mit dem gewählten Projekt';
@ -3201,6 +3204,14 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String get workspaceSealedStopped => 'gestoppt';
@override
String get workspaceSealedRunningHint =>
'Der abgeschottete Bereich läuft als eigener Hub-Prozess. Auswählen wechselt hinein.';
@override
String get workspaceSealedStoppedHint =>
'Der abgeschottete Bereich ist gerade nicht gestartet. Auswählen startet ihn und wechselt hinein.';
@override
String workspaceSealedStarting(String name) {
return 'Starte abgeschotteten Bereich „$name“…';
@ -3498,7 +3509,7 @@ class AppLocalizationsDe extends AppLocalizations {
@override
String setupFreeTextPrivacyLocal(String model) {
return 'Ihre Beschreibung wird lokal auf diesem Rechner verarbeitet ($model).';
return 'Ihre Beschreibung wird direkt auf diesem Rechner verarbeitet — durch das lokale KI-Modell $model. Nichts verlässt das Gerät.';
}
@override

View file

@ -247,7 +247,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get welcomeChecklistBody =>
'Four steps to a working hub. Live state — refresh after changing anything.';
'Four steps to a working hub. The list shows the live state — refresh top right after changing anything.';
@override
String get welcomeChecklistAi => 'Configure System AI';
@ -2200,7 +2200,7 @@ class AppLocalizationsEn extends AppLocalizations {
other: 'events',
one: 'event',
);
return '$n $_temp0 · prev_event_sha256 verified end-to-end';
return '$n $_temp0 · linkage verified end-to-end';
}
@override
@ -2212,7 +2212,7 @@ class AppLocalizationsEn extends AppLocalizations {
}
@override
String get doctorChainPillOk => 'Integrity chain verified';
String get doctorChainPillOk => 'Hash chain verified';
@override
String get doctorChainPillTamper => 'TAMPER';
@ -3126,6 +3126,9 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get workspaceAll => 'All projects';
@override
String get workspaceDefaultProject => 'General';
@override
String get workspaceSwitcherTooltip =>
'Workspace — filters this view and stamps new runs with the selected project';
@ -3201,6 +3204,14 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String get workspaceSealedStopped => 'stopped';
@override
String get workspaceSealedRunningHint =>
'The sealed area runs as its own hub process. Selecting it switches in.';
@override
String get workspaceSealedStoppedHint =>
'The sealed area is not running right now. Selecting it starts it and switches in.';
@override
String workspaceSealedStarting(String name) {
return 'Starting sealed area “$name”…';
@ -3492,7 +3503,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override
String setupFreeTextPrivacyLocal(String model) {
return 'Your description is processed locally on this machine ($model).';
return 'Your description is processed right on this machine — by the local AI model $model. Nothing leaves the device.';
}
@override

View file

@ -11,6 +11,7 @@
import 'package:flutter/material.dart';
import '../data/hub.dart' show ProjectRef;
import '../data/sealed_areas.dart';
import '../data/workspace.dart';
import '../l10n/app_localizations.dart';
@ -36,7 +37,11 @@ class ChainWorkspaceSwitcher extends StatelessWidget {
final label = ws.inSealedArea
? ws.activeSealed!.name
: (ws.isAll ? l.workspaceAll : (ws.active?.name ?? ws.activeSlug));
: (ws.isAll
? l.workspaceAll
: (ws.active == null
? ws.activeSlug
: _projectLabel(l, ws.active!)));
return Tooltip(
message: l.workspaceSwitcherTooltip,
@ -82,7 +87,12 @@ class ChainWorkspaceSwitcher extends StatelessWidget {
children: [
_ProjectDot(color: p.color),
const SizedBox(width: ChainSpace.sm),
Flexible(child: Text(p.name, overflow: TextOverflow.ellipsis)),
Flexible(
child: Text(
_projectLabel(l, p),
overflow: TextOverflow.ellipsis,
),
),
if (p.isProtected) ...[
const SizedBox(width: ChainSpace.sm),
Tooltip(
@ -130,12 +140,19 @@ class ChainWorkspaceSwitcher extends StatelessWidget {
const SizedBox(width: 4),
Flexible(child: Text(a.name, overflow: TextOverflow.ellipsis)),
const SizedBox(width: ChainSpace.sm),
Text(
a.running ? l.workspaceSealedRunning : l.workspaceSealedStopped,
style: theme.textTheme.labelSmall?.copyWith(
color: a.running
? ChainColors.success
: theme.colorScheme.onSurfaceVariant,
Tooltip(
message: a.running
? l.workspaceSealedRunningHint
: l.workspaceSealedStoppedHint,
child: Text(
a.running
? l.workspaceSealedRunning
: l.workspaceSealedStopped,
style: theme.textTheme.labelSmall?.copyWith(
color: a.running
? ChainColors.success
: theme.colorScheme.onSurfaceVariant,
),
),
),
],
@ -266,6 +283,12 @@ class ChainWorkspaceSwitcher extends StatelessWidget {
}
}
/// Display name for a registry project. The hub's default project
/// carries the fixed English name "General"; render it localized
/// ("Allgemein") so no English label sits in the German menu.
String _projectLabel(AppLocalizations l, ProjectRef p) =>
p.slug == 'general' ? l.workspaceDefaultProject : p.name;
/// The project's registry colour as a small marking dot. Falls back
/// to the theme's outline colour when unset.
class _ProjectDot extends StatelessWidget {