Stufe 4c (#764): Kommentare in C#, WebUI-Skripten, CSS und HTML auf Englisch

Rund 2.600 Kommentarblöcke in 310 C#-Dateien übersetzt, Begründungen vollständig
erhalten: blockweise gleiche Anzahl wie vorher, kein Block unter 60 % seiner
Länge, der Code außerhalb der Kommentare per Tokenizer byte-identisch geprüft.
Zitate deutscher Oberflächentexte und Testdaten bleiben deutsch.

WebUI: Kommentare in JS/CSS/HTML übersetzt, JSDoc-@param an die in 4b
umbenannten Parameter angeglichen.

Dabei behoben:
- 4b hatte "tag" (HTML-Tag) als deutsches "Tag" gelesen und zu "dayValue"
  gemacht (makeElement, svg, Tagesübersicht) - zurück auf tag/day.
- Aufgaben "InProgress" bekamen die Plakettenart "laufend", für die es nie eine
  CSS-Klasse gab - jetzt "success" wie laufende Instanzen.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-10-04 12:45:03 +02:00
co-authored by Claude Opus 5.5
parent da4ceac7d5
commit 837a634a22
311 changed files with 7238 additions and 7252 deletions
@@ -6,11 +6,11 @@ using Shouldly;
namespace ClawdDotNet.Core.Tests.Storage;
/// <summary>
/// Alle Konfigurations- und Zustandsdateien wurden mit File.WriteAllText geschrieben.
/// Das kürzt die Zieldatei zuerst auf null und füllt sie dann — bricht der Vorgang
/// dazwischen ab, ist der alte Inhalt weg und der neue unvollständig.
/// All configuration and state files were written with File.WriteAllText.
/// That first truncates the target file to zero and then fills it — if the operation
/// aborts in between, the old content is gone and the new one incomplete.
///
/// Das ist im Betrieb bereits eingetreten: In einer Instanz lag eine
/// That has already happened in operation: an instance contained a
/// TokenUsage.json.corrupt_…
/// </summary>
public sealed class AtomicFileTests : IDisposable
@@ -26,13 +26,13 @@ public sealed class AtomicFileTests : IDisposable
public void Dispose()
{
try { Directory.Delete(_directory, recursive: true); }
catch { /* Aufräumen ist Nebensache */ }
catch { /* Cleaning up is secondary */ }
}
private string Path_(string name) => Path.Combine(_directory, name);
// ═══════════════════════════════════════════════════════════
// Grundverhalten
// Basic behavior
// ═══════════════════════════════════════════════════════════
[Fact]
@@ -102,13 +102,13 @@ public sealed class AtomicFileTests : IDisposable
}
// ═══════════════════════════════════════════════════════════
// Die eigentliche Zusage: nie ein halber Inhalt
// The actual promise: never half a content
// ═══════════════════════════════════════════════════════════
/// <summary>
/// Während geschrieben wird, wird parallel gelesen. Beim alten Verfahren erwischt
/// man dabei zwangsläufig abgeschnittene Zwischenstände — hier darf jeder Lesevorgang
/// nur ein vollständiges Dokument sehen.
/// While writing, reading happens in parallel. With the old procedure you inevitably
/// catch truncated intermediate states — here every read may
/// only see a complete document.
/// </summary>
[Fact]
public async Task Waehrend_des_Schreibens_wird_nie_ein_halber_Inhalt_sichtbar()
@@ -122,15 +122,15 @@ public sealed class AtomicFileTests : IDisposable
var fehler = 0;
var gelesen = 0;
// Harte Zeitgrenze, damit ein Fehler im Schreiber den Test nicht hängen lässt.
// Hard time limit, so an error in the writer does not leave the test hanging.
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
var schreiber = Task.Run(async () =>
{
try
{
// #722: Geschrieben wird, bis der Leser genug gesehen hat — nicht eine feste
// Zahl von Malen. Unter Parallellast kam der Leser sonst nur auf fuenf Blicke.
// #722: Writing continues until the reader has seen enough — not a fixed
// number of times. Under parallel load the reader otherwise only got five looks.
for (var i = 0; (i < 40 || Volatile.Read(ref gelesen) < 20) && !cts.IsCancellationRequested; i++)
{
AtomicFile.WriteAllText(path, i % 2 == 0 ? gross : klein);
@@ -149,12 +149,12 @@ public sealed class AtomicFileTests : IDisposable
{
try
{
// AtomicFile.ReadAllText, damit der Leser den Schreiber nicht
// blockiert — genau dafür gibt es den Helfer.
// AtomicFile.ReadAllText, so the reader does not block the
// writer — that is exactly what the helper exists for.
var inhalt = AtomicFile.ReadAllText(path);
Interlocked.Increment(ref gelesen);
// Muss immer ein vollständiges JSON-Array sein.
// Must always be a complete JSON array.
JsonSerializer.Deserialize<string[]>(inhalt);
}
catch (JsonException)
@@ -163,7 +163,7 @@ public sealed class AtomicFileTests : IDisposable
}
catch (IOException)
{
// Kurzzeitig nicht zu öffnen ist kein Datenfehler.
// Briefly not being able to open it is not a data error.
}
await Task.Delay(5);
}
@@ -176,12 +176,12 @@ public sealed class AtomicFileTests : IDisposable
}
/// <summary>
/// Der nicht offensichtliche Teil: Ein Leser, der die Datei geöffnet hält, würde
/// das Ersetzen blockieren — es sei denn, er gibt das Löschen frei. Genau das tut
/// <see cref="AtomicFile.ReadAllText"/>.
/// The non-obvious part: a reader holding the file open would
/// block the replacement — unless it shares delete. That is exactly what
/// <see cref="AtomicFile.ReadAllText"/> does.
///
/// Gemessen auf Windows: File.Move scheitert in jedem Fall an einem offenen Leser,
/// File.Replace kommt mit einem freigebenden Leser zurecht. Deshalb Replace.
/// Measured on Windows: File.Move fails in every case with an open reader,
/// File.Replace copes with a sharing reader. Hence Replace.
/// </summary>
[Fact]
public void Ein_offener_Leser_blockiert_das_Schreiben_nicht()
@@ -205,7 +205,7 @@ public sealed class AtomicFileTests : IDisposable
Parallel.For(0, 40, i =>
AtomicFile.WriteAllText(path, JsonSerializer.Serialize(new { lauf = i })));
// Welcher Lauf gewinnt, ist offen — die Datei muss aber lesbar sein.
// Which run wins is open — but the file must be readable.
Should.NotThrow(() => JsonDocument.Parse(File.ReadAllText(path)));
Directory.GetFiles(_directory).ShouldHaveSingleItem();
}