fix(localization): de.json-Konsistenz-Pass und restliche harte EN-Strings

Queue/Task(s)/Gate in deutschem Fliesstext auf Warteschlange/Aufgabe(n)/
Limit-Stopp vereinheitlicht, columnTask-Keys auf AUFGABE angeglichen,
Kill-Tonalitaet (closeSession/killSessionTip) ehrlich-destruktiv gemacht.
RepoImportModalViewModel.CreateButtonText und alle Installer-Check-Messages
(Git/GitIdentity/WriteAccess/ClaudeCli/ClaudeVersion/ClaudeAuth/
PermissionModeAuto/Ports) ueber Locale-Keys geroutet statt hartem Englisch,
mit dem bestehenden TrExtension.Localizer-Fallback-Muster.
This commit is contained in:
mika kuns
2026-09-10 13:57:33 +02:00
parent 7eba0affbe
commit d6696c3317
11 changed files with 135 additions and 56 deletions
@@ -1,5 +1,6 @@
using System.Text.Json;
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Localization;
namespace ClaudeDo.Installer.Checks;
@@ -23,11 +24,12 @@ public sealed class ClaudeAuthCheck : IEnvironmentCheck
public async Task<CheckResult> RunAsync(InstallContext ctx, CancellationToken ct)
{
var loc = TrExtension.Localizer;
var lookup = await _lookup.ResolveAsync(ctx, ct);
if (lookup.Resolved is null)
{
return CheckResult.Unknown(Id, Severity, "checks.claudeAuth.title",
"The claude CLI was not found — login could not be checked.");
loc?["checks.claudeAuth.notFound"] ?? "The claude CLI was not found — login could not be checked.");
}
var (fileName, arguments) = ProcessCommand.For(lookup.Resolved, "auth", "status", "--json");
@@ -36,19 +38,19 @@ public sealed class ClaudeAuthCheck : IEnvironmentCheck
if (exitCode != 0)
{
return CheckResult.Unknown(Id, Severity, "checks.claudeAuth.title",
"Login status could not be determined.", output);
loc?["checks.claudeAuth.undetermined"] ?? "Login status could not be determined.", output);
}
var loggedIn = TryParseLoggedIn(output);
if (loggedIn is null)
{
return CheckResult.Unknown(Id, Severity, "checks.claudeAuth.title",
"Login status could not be determined.", output);
loc?["checks.claudeAuth.undetermined"] ?? "Login status could not be determined.", output);
}
return loggedIn.Value
? CheckResult.Ok(Id, Severity, "checks.claudeAuth.title", "Logged in.")
: CheckResult.Fail(Id, Severity, "checks.claudeAuth.title", "Not logged in.", "checks.claudeAuth.hint");
? CheckResult.Ok(Id, Severity, "checks.claudeAuth.title", loc?["checks.claudeAuth.loggedIn"] ?? "Logged in.")
: CheckResult.Fail(Id, Severity, "checks.claudeAuth.title", loc?["checks.claudeAuth.notLoggedIn"] ?? "Not logged in.", "checks.claudeAuth.hint");
}
private static bool? TryParseLoggedIn(string output)
@@ -1,6 +1,7 @@
using System.IO;
using ClaudeDo.Data.Environment;
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Localization;
namespace ClaudeDo.Installer.Checks;
@@ -21,20 +22,21 @@ public sealed class ClaudeCliCheck : IEnvironmentCheck
public async Task<CheckResult> RunAsync(InstallContext ctx, CancellationToken ct)
{
var loc = TrExtension.Localizer;
var lookup = await _lookup.ResolveAsync(ctx, ct);
if (lookup.Resolved is null)
{
var searched = string.Join(", ", SearchedLocations());
return CheckResult.Fail(Id, Severity, "checks.claudeCli.title",
$"'{ctx.ClaudeBin}' was not found on PATH. Searched: {searched}.",
loc?.Get("checks.claudeCli.notFound", ctx.ClaudeBin, searched) ?? $"'{ctx.ClaudeBin}' was not found on PATH. Searched: {searched}.",
"checks.claudeCli.hint");
}
if (lookup.ExitCode != 0)
{
return CheckResult.Fail(Id, Severity, "checks.claudeCli.title",
$"'{lookup.Resolved.Path}' exited with code {lookup.ExitCode}.",
loc?.Get("checks.claudeCli.exitCode", lookup.Resolved.Path, lookup.ExitCode) ?? $"'{lookup.Resolved.Path}' exited with code {lookup.ExitCode}.",
"checks.claudeCli.hint", detail: lookup.Output);
}
@@ -42,7 +44,8 @@ public sealed class ClaudeCliCheck : IEnvironmentCheck
var detail = lookup.Resolved.IsShim
? "Resolved via a shim (.cmd/.bat/.ps1), not a native .exe."
: null;
return CheckResult.Ok(Id, Severity, "checks.claudeCli.title", $"{lookup.Resolved.Path} — {version}", detail);
return CheckResult.Ok(Id, Severity, "checks.claudeCli.title",
loc?.Get("checks.claudeCli.resolvedFormat", lookup.Resolved.Path, version) ?? $"{lookup.Resolved.Path} — {version}", detail);
}
private IEnumerable<string> SearchedLocations()
@@ -1,4 +1,5 @@
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Localization;
namespace ClaudeDo.Installer.Checks;
@@ -27,28 +28,29 @@ public sealed class ClaudeVersionCheck : IEnvironmentCheck
public async Task<CheckResult> RunAsync(InstallContext ctx, CancellationToken ct)
{
var loc = TrExtension.Localizer;
var lookup = await _lookup.ResolveAsync(ctx, ct);
if (lookup.Resolved is null)
{
return CheckResult.Unknown(Id, Severity, "checks.claudeVersion.title",
"The claude CLI was not found — version could not be checked.");
loc?["checks.claudeVersion.notFound"] ?? "The claude CLI was not found — version could not be checked.");
}
if (lookup.ExitCode != 0 || lookup.ParsedVersion is null)
{
return CheckResult.Unknown(Id, Severity, "checks.claudeVersion.title",
$"Could not parse a version from '{lookup.Output.Trim()}'.");
loc?.Get("checks.claudeVersion.parseFailed", lookup.Output.Trim()) ?? $"Could not parse a version from '{lookup.Output.Trim()}'.");
}
if (lookup.ParsedVersion < MinimumVersion)
{
return CheckResult.Fail(Id, Severity, "checks.claudeVersion.title",
$"claude {lookup.ParsedVersion} is older than the required {MinimumVersion}.",
loc?.Get("checks.claudeVersion.tooOld", lookup.ParsedVersion, MinimumVersion) ?? $"claude {lookup.ParsedVersion} is older than the required {MinimumVersion}.",
"checks.claudeVersion.hint");
}
return CheckResult.Ok(Id, Severity, "checks.claudeVersion.title",
$"claude {lookup.ParsedVersion} meets the minimum ({MinimumVersion}).");
loc?.Get("checks.claudeVersion.ok", lookup.ParsedVersion, MinimumVersion) ?? $"claude {lookup.ParsedVersion} meets the minimum ({MinimumVersion}).");
}
}
+8 -3
View File
@@ -2,6 +2,7 @@ using System.Text.RegularExpressions;
using ClaudeDo.Data.Environment;
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Core.Interfaces;
using ClaudeDo.Installer.Localization;
namespace ClaudeDo.Installer.Checks;
@@ -27,10 +28,12 @@ public sealed class GitCheck : IEnvironmentCheck
public async Task<CheckResult> RunAsync(InstallContext ctx, CancellationToken ct)
{
var loc = TrExtension.Localizer;
var resolved = ExecutableResolver.Resolve("git", _pathOverride, _pathExtOverride);
if (resolved is null)
{
return CheckResult.Fail(Id, Severity, "checks.git.title", "git was not found on PATH.",
return CheckResult.Fail(Id, Severity, "checks.git.title",
loc?["checks.git.notFound"] ?? "git was not found on PATH.",
"checks.git.hint", "https://git-scm.com/downloads");
}
@@ -39,11 +42,13 @@ public sealed class GitCheck : IEnvironmentCheck
if (exitCode != 0)
{
return CheckResult.Fail(Id, Severity, "checks.git.title", $"'{resolved.Path}' exited with code {exitCode}.",
return CheckResult.Fail(Id, Severity, "checks.git.title",
loc?.Get("checks.git.exitCode", resolved.Path, exitCode) ?? $"'{resolved.Path}' exited with code {exitCode}.",
"checks.git.hint", "https://git-scm.com/downloads", output);
}
var version = VersionPattern.Match(output) is { Success: true } match ? match.Value : output.Trim();
return CheckResult.Ok(Id, Severity, "checks.git.title", $"{resolved.Path} — {version}");
return CheckResult.Ok(Id, Severity, "checks.git.title",
loc?.Get("checks.git.resolvedFormat", resolved.Path, version) ?? $"{resolved.Path} — {version}");
}
}
@@ -1,6 +1,7 @@
using ClaudeDo.Data.Environment;
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Core.Interfaces;
using ClaudeDo.Installer.Localization;
namespace ClaudeDo.Installer.Checks;
@@ -25,10 +26,12 @@ public sealed class GitIdentityCheck : IEnvironmentCheck
public async Task<CheckResult> RunAsync(InstallContext ctx, CancellationToken ct)
{
var loc = TrExtension.Localizer;
var resolved = ExecutableResolver.Resolve("git", _pathOverride, _pathExtOverride);
if (resolved is null)
{
return CheckResult.Unknown(Id, Severity, "checks.gitIdentity.title", "git was not found — identity could not be checked.");
return CheckResult.Unknown(Id, Severity, "checks.gitIdentity.title",
loc?["checks.gitIdentity.notFound"] ?? "git was not found — identity could not be checked.");
}
var name = await ReadConfigAsync(resolved, "user.name", ct);
@@ -48,7 +51,8 @@ public sealed class GitIdentityCheck : IEnvironmentCheck
_ => "user.email",
};
return CheckResult.Fail(Id, Severity, "checks.gitIdentity.title", $"Missing git identity: {missing}.", "checks.gitIdentity.hint");
return CheckResult.Fail(Id, Severity, "checks.gitIdentity.title",
loc?.Get("checks.gitIdentity.missing", missing) ?? $"Missing git identity: {missing}.", "checks.gitIdentity.hint");
}
private async Task<string> ReadConfigAsync(ResolvedExecutable resolved, string key, CancellationToken ct)
@@ -1,5 +1,6 @@
using System.Text.RegularExpressions;
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Localization;
namespace ClaudeDo.Installer.Checks;
@@ -28,11 +29,12 @@ public sealed class PermissionModeAutoCheck : IEnvironmentCheck
public async Task<CheckResult> RunAsync(InstallContext ctx, CancellationToken ct)
{
var loc = TrExtension.Localizer;
var lookup = await _lookup.ResolveAsync(ctx, ct);
if (lookup.Resolved is null)
{
return CheckResult.Unknown(Id, Severity, "checks.permissionModeAuto.title",
"The claude CLI was not found — permission-mode support could not be checked.");
loc?["checks.permissionModeAuto.notFound"] ?? "The claude CLI was not found — permission-mode support could not be checked.");
}
var (fileName, arguments) = ProcessCommand.For(lookup.Resolved, "--help");
@@ -41,17 +43,17 @@ public sealed class PermissionModeAutoCheck : IEnvironmentCheck
if (exitCode != 0 || string.IsNullOrWhiteSpace(output))
{
return CheckResult.Unknown(Id, Severity, "checks.permissionModeAuto.title",
"Could not determine whether --permission-mode auto is supported.");
loc?["checks.permissionModeAuto.undetermined"] ?? "Could not determine whether --permission-mode auto is supported.");
}
if (AutoIsListed(output))
{
return CheckResult.Ok(Id, Severity, "checks.permissionModeAuto.title",
"--permission-mode auto is recognized by this CLI.");
loc?["checks.permissionModeAuto.ok"] ?? "--permission-mode auto is recognized by this CLI.");
}
return CheckResult.Fail(Id, Severity, "checks.permissionModeAuto.title",
"This claude CLI version does not list 'auto' as a --permission-mode choice.",
loc?["checks.permissionModeAuto.notListed"] ?? "This claude CLI version does not list 'auto' as a --permission-mode choice.",
"checks.permissionModeAuto.hint");
}
+9 -3
View File
@@ -2,6 +2,7 @@ using System.Net;
using System.Net.Sockets;
using ClaudeDo.Installer.Checks.Interfaces;
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Localization;
namespace ClaudeDo.Installer.Checks;
@@ -19,6 +20,7 @@ public sealed class PortCheck : IEnvironmentCheck
public async Task<CheckResult> RunAsync(InstallContext ctx, CancellationToken ct)
{
var loc = TrExtension.Localizer;
var ports = new (string Label, int Port)[]
{
("SignalR", ctx.SignalRPort),
@@ -39,7 +41,9 @@ public sealed class PortCheck : IEnvironmentCheck
continue;
}
blocked.Add(owner is null ? $"{label} port {port} is in use." : $"{label} port {port} is in use by '{owner}'.");
blocked.Add(owner is null
? loc?.Get("checks.ports.inUse", label, port) ?? $"{label} port {port} is in use."
: loc?.Get("checks.ports.inUseBy", label, port, owner) ?? $"{label} port {port} is in use by '{owner}'.");
}
if (blocked.Count > 0)
@@ -49,10 +53,12 @@ public sealed class PortCheck : IEnvironmentCheck
if (ownWorker.Count > 0)
{
return CheckResult.Ok(Id, Severity, "checks.ports.title", $"In use by the running ClaudeDo Worker: {string.Join(", ", ownWorker)}.");
var ownWorkerList = string.Join(", ", ownWorker);
return CheckResult.Ok(Id, Severity, "checks.ports.title",
loc?.Get("checks.ports.inUseByOwnWorker", ownWorkerList) ?? $"In use by the running ClaudeDo Worker: {ownWorkerList}.");
}
return CheckResult.Ok(Id, Severity, "checks.ports.title", "Ports are available.");
return CheckResult.Ok(Id, Severity, "checks.ports.title", loc?["checks.ports.available"] ?? "Ports are available.");
}
private static bool IsFree(int port)
@@ -1,6 +1,7 @@
using System.IO;
using ClaudeDo.Data;
using ClaudeDo.Installer.Core;
using ClaudeDo.Installer.Localization;
namespace ClaudeDo.Installer.Checks;
@@ -14,17 +15,19 @@ public sealed class WriteAccessCheck : IEnvironmentCheck
public Task<CheckResult> RunAsync(InstallContext ctx, CancellationToken ct)
{
var loc = TrExtension.Localizer;
foreach (var target in new[] { ctx.InstallDirectory, Paths.AppDataRoot() })
{
var error = TryWrite(target);
if (error is not null)
{
return Task.FromResult(CheckResult.Fail(Id, Severity, "checks.writeAccess.title",
$"Cannot write to '{target}': {error}", "checks.writeAccess.hint"));
loc?.Get("checks.writeAccess.cannotWrite", target, error) ?? $"Cannot write to '{target}': {error}", "checks.writeAccess.hint"));
}
}
return Task.FromResult(CheckResult.Ok(Id, Severity, "checks.writeAccess.title", "Install directory and data directory are writable."));
return Task.FromResult(CheckResult.Ok(Id, Severity, "checks.writeAccess.title",
loc?["checks.writeAccess.writable"] ?? "Install directory and data directory are writable."));
}
private static string? TryWrite(string path)