Unser vorheriger Architektur-Beitrag behandelte Plugins, Action Guards und das Pipeline-System. In diesem Beitrag gehen wir näher auf die Übersetzungs-Engine ein, die Rasepi meiner Meinung nach grundlegend von allen anderen Dokumentationsplattformen unterscheidet.
Es geht nicht um das Marketing, dass Absätze statt Seiten übersetzt werden. Der eigentliche Code. Wie Glossare pro Tenant aufgelöst werden, wie die Stilregeln und benutzerdefinierten Anweisungen von DeepL jede Übersetzung beeinflussen, wie Content Hashing die Erkennung von veralteten Inhalten steuert und wie der Orchestrator entscheidet, welche Blöcke neu übersetzt werden.
Die Übersetzungspipeline
Wenn ein Benutzer ein Dokument speichert, übersetzt das System nicht einfach alles neu. Es führt eine ganz bestimmte Sequenz durch:
- Es zerlegt das TipTap JSON in einzelne Blöcke
- Inhalts-Hashes vergleichen, um festzustellen, welche Blöcke sich tatsächlich geändert haben
- Löse für geänderte Blöcke das Glossar und die Stilregel-Liste des Tenants für das Sprachpaar auf
- Wende Stilregeln, benutzerdefinierte Anweisungen und Formalitäten aus der Tenant-Konfiguration an
- Sende nur geänderte Blöcke an DeepL
- Übersetzungsblöcke aktualisieren und Inhaltshashes synchronisieren
Jeder Schritt ist ein eigener Dienst mit einer eigenen Schnittstelle. Das ist wichtig, weil jeder Schritt gegen einen anderen ausgetauscht werden kann: einen anderen Übersetzungsanbieter, einen anderen Hash-Algorithmus oder eine andere Glossarquelle.
Glossarauflösung: mieterübergreifend, DeepL-synchronisiert
DeepL Glossare haben eine Einschränkung, von der die meisten Menschen nichts wissen: **Sie sind unveränderlich. ** Du kannst ein DeepL Glossar nicht bearbeiten. Jede Änderung bedeutet, dass das alte Glossar gelöscht und ein neues erstellt wird.
Rasepi behandelt dies, indem es die Datenbank als Quelle der Wahrheit und DeepL Glossare als Wegwerf-Artefakte zur Laufzeit behandelt. Die Entität TenantGlossary speichert alles lokal:
public class TenantGlossary : ITenantScoped
{
public Guid Id { get; set; }
public Guid TenantId { get; set; }
public string Name { get; set; }
public string SourceLanguage { get; set; } // e.g. "en"
public string TargetLanguage { get; set; } // e.g. "de"
public string? DeepLGlossaryId { get; set; } // Runtime DeepL ID
public DateTime? LastSyncedAt { get; set; }
public bool IsDirty { get; set; } = true; // Triggers re-sync
public ICollection<TenantGlossaryEntry> Entries { get; set; }
}
Wenn ein Benutzer einen Glossareintrag hinzufügt, z.B. die Zuordnung von "Sprint Review" zu "Sprint-Überprüfung" für EN→DE, wird der Datenbankeintrag sofort aktualisiert und IsDirty wird auf true gesetzt. Das Glossar DeepL wird nicht sofort neu erstellt. Es wird erst nach und nach neu erstellt, wenn es das nächste Mal für eine Übersetzung benötigt wird.
Der Sync-Fluss
Vor jedem Übersetzungsaufruf löst das System das Glossar auf:
public async Task<string?> GetOrSyncDeepLGlossaryIdAsync(
string sourceLanguage, string targetLanguage,
CancellationToken ct = default)
{
var glossary = await _db.TenantGlossaries
.Include(g => g.Entries)
.FirstOrDefaultAsync(g =>
g.SourceLanguage == sourceLanguage &&
g.TargetLanguage == targetLanguage, ct);
if (glossary is null || glossary.Entries.Count == 0)
return null;
if (!glossary.IsDirty && glossary.DeepLGlossaryId is not null)
return glossary.DeepLGlossaryId;
// Dirty - delete old, create new
if (glossary.DeepLGlossaryId is not null)
await _deepL.DeleteGlossaryAsync(glossary.DeepLGlossaryId);
var entries = glossary.Entries
.ToDictionary(e => e.SourceTerm, e => e.TargetTerm);
var deepLGlossary = await _deepL.CreateGlossaryAsync(
$"rasepi-{glossary.Id}",
glossary.SourceLanguage,
glossary.TargetLanguage,
entries);
glossary.DeepLGlossaryId = deepLGlossary.GlossaryId;
glossary.IsDirty = false;
glossary.LastSyncedAt = DateTime.UtcNow;
await _db.SaveChangesAsync(ct);
return glossary.DeepLGlossaryId;
}
Drei Dinge sind hier erwähnenswert:
- Lazy sync. Wir rufen die DeepL API nur auf, wenn tatsächlich eine Übersetzung benötigt wird. Die Bearbeitung von Glossareinträgen löst nicht Dutzende von API-Aufrufen aus.
- Mieterisolierung. Die Abfrage durchläuft die globalen EF-Abfragefilter, sodass
TenantGlossariesautomatisch gescannt wird. Die Glossareinträge von Tenant A gelangen nicht in die Übersetzungen von Tenant B. - Ein Glossar pro Sprachenpaar. DeepL erzwingt dies ohnehin. Ein EN→DE-Glossar, ein EN→FR-Glossar, und so weiter. Das
(SourceLanguage, TargetLanguage)-Paar ist pro Tenant eindeutig.
Glossar-Einträge
Einzelne Einträge sind nur Begriffszuordnungen:
public class TenantGlossaryEntry
{
public Guid Id { get; set; }
public Guid GlossaryId { get; set; }
public string SourceTerm { get; set; } // e.g. "Sprint Review"
public string TargetTerm { get; set; } // e.g. "Sprint-Überprüfung"
}
Die API bietet dir vollständiges CRUD sowie CSV-Import/Export für die Massenverwaltung:
POST /api/admin/glossaries Create glossary
POST /api/admin/glossaries/{id}/entries Add term
PUT /api/admin/glossaries/{id}/entries/{entryId} Update term
DELETE /api/admin/glossaries/{id}/entries/{entryId} Remove term
POST /api/admin/glossaries/{id}/import Import CSV
GET /api/admin/glossaries/{id}/export Export CSV
POST /api/admin/glossaries/{id}/sync Force DeepL sync
Der CSV-Import ist besonders nützlich für Teams, die von bestehenden Translation-Memory-Systemen migrieren. Exportiere deine Begriffe, bereinige sie, importiere sie in Rasepi, und der nächste Übersetzungslauf verwendet das neue Glossar automatisch.
Stilregeln, benutzerdefinierte Anweisungen und Formalitäten
Glossare kümmern sich um die Terminologie. Aber Terminologie ist nur die halbe Miete. Eine Übersetzung kann alle richtigen Wörter verwenden und trotzdem falsch klingen. Falscher Ton, falsches Datumsformat, falsche Zeichensetzungskonventionen.
Die Style Rules API (v3) von DeepL schafft hier Abhilfe. Du kannst wiederverwendbare Stilregel-Listen erstellen, die zwei Arten von Steuerelementen kombinieren:
- Konfigurierte Regeln, vordefinierte Formatierungskonventionen für Datumsangaben, Zeitangaben, Interpunktion, Zahlen und mehr
- Benutzerdefinierte Anweisungen, Freitextanweisungen, die den Ton, die Formulierung und bereichsspezifische Konventionen bestimmen
Rasepi erstellt und verwaltet diese pro Tenant und pro Zielsprache. Die Entität TenantStyleRuleList speichert die DeepL style_id neben den konfigurierten Regeln und benutzerdefinierten Anweisungen des Tenants:
public class TenantStyleRuleList : ITenantScoped
{
public Guid Id { get; set; }
public Guid TenantId { get; set; }
public string Name { get; set; }
public string TargetLanguage { get; set; } // e.g. "de"
public string? DeepLStyleId { get; set; } // Runtime DeepL style_id
public string ConfiguredRulesJson { get; set; } // Serialized configured rules
public bool IsDirty { get; set; } = true;
public DateTime? LastSyncedAt { get; set; }
public ICollection<TenantCustomInstruction> CustomInstructions { get; set; }
}
Erstellen von Stilregel-Listen
Wenn ein Admin Übersetzungsregeln für Deutsch einrichtet, ruft Rasepi die v3 API von DeepL auf, um die Stilregel-Liste zu erstellen. So sieht das aus:
public async Task<string> CreateOrSyncStyleRuleListAsync(
TenantStyleRuleList ruleList, CancellationToken ct = default)
{
if (!ruleList.IsDirty && ruleList.DeepLStyleId is not null)
return ruleList.DeepLStyleId;
// DeepL style rule lists are mutable - we can update in place
if (ruleList.DeepLStyleId is not null)
{
// Replace configured rules on existing list
await _httpClient.PutAsJsonAsync(
$"v3/style_rules/{ruleList.DeepLStyleId}/configured_rules",
JsonSerializer.Deserialize<JsonElement>(ruleList.ConfiguredRulesJson),
ct);
// Sync custom instructions
await SyncCustomInstructionsAsync(ruleList, ct);
ruleList.IsDirty = false;
ruleList.LastSyncedAt = DateTime.UtcNow;
return ruleList.DeepLStyleId;
}
// Create new style rule list
var payload = new
{
name = $"rasepi-{ruleList.TenantId}-{ruleList.TargetLanguage}",
language = ruleList.TargetLanguage,
configured_rules = JsonSerializer.Deserialize<JsonElement>(
ruleList.ConfiguredRulesJson),
custom_instructions = ruleList.CustomInstructions.Select(ci => new
{
label = ci.Label,
prompt = ci.Prompt,
source_language = ci.SourceLanguage
})
};
var response = await _httpClient.PostAsJsonAsync("v3/style_rules", payload, ct);
var result = await response.Content.ReadFromJsonAsync<StyleRuleResponse>(ct);
ruleList.DeepLStyleId = result.StyleId;
ruleList.IsDirty = false;
ruleList.LastSyncedAt = DateTime.UtcNow;
await _db.SaveChangesAsync(ct);
return ruleList.DeepLStyleId;
}
Anders als Glossare sind DeepL Stilregel-Listen veränderbar. Du kannst konfigurierte Regeln mit PUT /v3/style_rules/{style_id}/configured_rules ersetzen, und benutzerdefinierte Anweisungen können individuell hinzugefügt, aktualisiert oder gelöscht werden. Das ist viel besser für die iterative Verfeinerung geeignet.
Wie konfigurierte Regeln aussehen
Konfigurierte Regeln decken Formatierungskonventionen ab, die je nach Sprache oder Firmenpräferenz variieren. Dinge wie:
{
"dates_and_times": {
"time_format": "use_24_hour_clock",
"calendar_era": "use_bc_and_ad"
},
"punctuation": {
"periods_in_academic_degrees": "do_not_use"
},
"numbers": {
"decimal_separator": "use_comma"
}
}
Das hört sich trivial an, aber es wird schnell kompliziert. Ein deutsches Dokument, das das AM/PM-Zeitformat und durch Punkte getrennte Dezimalzahlen verwendet, liest sich für einen deutschen Leser einfach als "aus dem Englischen übersetzt". Wenn du use_24_hour_clock und use_comma für Dezimaltrennzeichen in allen deutschen Übersetzungen einstellst, wird das sofort behoben.
Benutzerdefinierte Anweisungen: Das ist die wahre Macht
Benutzerdefinierte Anweisungen sind Freitextanweisungen, bis zu 200 pro Stilregel-Liste, jede mit bis zu 300 Zeichen. Damit sagst du DeepL, wie die Übersetzung aussehen soll, und zwar in einfacher Sprache:
public class TenantCustomInstruction
{
public Guid Id { get; set; }
public Guid StyleRuleListId { get; set; }
public string Label { get; set; } // e.g. "Tone instruction"
public string Prompt { get; set; } // e.g. "Use a friendly, diplomatic tone"
public string? SourceLanguage { get; set; } // Optional source lang filter
}
Echte Beispiele von unseren Mietern:
"Use a friendly, diplomatic tone"für ein Startup, das ansprechende Dokumente braucht"Always use 'Sie' form, never 'du'"für eine deutsche Anwaltskanzlei"Translate 'deployment' as 'Bereitstellung', never 'Deployment'"für Begriffe, die eine kontextabhängige Handhabung benötigen, die über eine einfache Glossarzuordnung hinausgeht"Use British English spelling (colour, organisation, licence)"für britische Unternehmen, die zwischen englischen Varianten übersetzen"Put currency symbols after the numeric amount"zur Anpassung an europäische Konventionen
Benutzerdefinierte Anweisungen sind sehr hilfreich, wenn es um domänenspezifische Konventionen geht, die nicht in Glossareinträge passen. Ein Glossar ordnet einen Begriff einem anderen zu. In einer benutzerdefinierten Anweisung kann stehen: "Wenn du API-Dokumente übersetzst, verwende den Imperativ statt des Passivs. Das ist eine ganz andere Art der Kontrolle.
Formalität
DeepL's formality Parameter (default, more, less, prefer_more, prefer_less) ist immer noch als separates Steuerelement neben Stilregeln verfügbar. Deutsch "du" versus "Sie", Französisch "tu" versus "vous", japanische Höflichkeitsstufen. Diese werden pro Mietersprache über TenantLanguageConfig eingestellt:
public class TenantLanguageConfig : ITenantScoped
{
public string LanguageCode { get; set; }
public string DisplayName { get; set; }
public bool IsEnabled { get; set; }
public TranslationTrigger Trigger { get; set; }
public string? Formality { get; set; } // "more", "less", "prefer_more", etc.
public string? StyleRuleListId { get; set; } // Links to TenantStyleRuleList
public string? TranslationProvider { get; set; }
public int SortOrder { get; set; }
public bool IsDefault { get; set; }
}
Formalitäten, Stilregeln und Glossare setzen sich zusammen. Ein einziger Übersetzungsaufruf kann alle drei enthalten:
var glossaryId = await GetOrSyncDeepLGlossaryIdAsync(sourceLang, targetLang, ct);
var styleId = await GetOrSyncStyleRuleListAsync(targetLang, ct);
var formality = tenantLanguageConfig.Formality ?? "default";
// Build the v2/translate request payload
var payload = new
{
text = new[] { blockContent },
source_lang = NormalizeLanguageCode(sourceLang),
target_lang = NormalizeLanguageCode(targetLang),
glossary_id = glossaryId,
style_id = styleId,
formality = formality,
preserve_formatting = true,
context = surroundingContext, // Adjacent blocks, not billed
model_type = "quality_optimized"
};
Zwei Dinge sind hier erwähnenswert:
- Der
contextParameter. Wir übergeben benachbarte Blöcke als Kontext, um die Übersetzungsqualität zu verbessern. DeepL nutzt dies, um Mehrdeutigkeiten aufzulösen, übersetzt oder berechnet sie aber nicht. Ein Absatz über "Zellen" wird anders übersetzt, wenn der umgebende Kontext ein Biologiedokument und eine Tabellenkalkulationsanleitung ist. - Modellauswahl. Jede Anfrage mit
style_idodercustom_instructionsverwendet automatisch dasquality_optimizedModell von DeepL. Dies ist die höchste Qualitätsstufe. Du kannst sie nicht mitlatency_optimizedkombinieren, und das ist eine bewusste Einschränkung von DeepL. Für die Stilanpassung brauchst du das komplette Modell.
Warum das wichtiger ist, als du denkst
Stell dir vor, ein Unternehmen schreibt interne Dokumente auf Deutsch mit dem formlosen "du" und wechselt in einem übersetzten Abschnitt plötzlich zum formellen "Sie". Das sieht bestenfalls inkonsequent und schlimmstenfalls unprofessionell aus. Die Formalität regelt das. Aber die Formalität allein reicht nicht aus, um ein Dokument zu erkennen, das AM/PM-Zeitstempel verwendet, obwohl dein deutsches Büro das 24-Stunden-Format benutzt, oder das Währungssymbol vor die Zahl setzt, statt danach.
Alles zusammen (Stilregeln, benutzerdefinierte Anweisungen, Formalitäten, Glossare) ergibt Übersetzungen, die sich so lesen, als hätte sie jemand aus deinem Team geschrieben. Nicht wie die Ausgabe einer Maschine, die nicht weiß, dass dein Unternehmen existiert.
Die DeepL Service-Schicht
Die gesamte DeepL Kommunikation läuft über IDeepLService. Sie umhüllt das offizielle DeepL .NET SDK und verarbeitet v3 API-Aufrufe für Stilregeln:
public interface IDeepLService
{
// Text translation (v2)
Task<TextResult> TranslateTextAsync(
string text, string sourceLanguage, string targetLanguage,
string? options = null);
Task<TextResult[]> TranslateTextBatchAsync(
IEnumerable<string> texts, string sourceLanguage,
string targetLanguage, string? options = null);
// Glossary management (v2)
Task<GlossaryInfo> CreateGlossaryAsync(
string name, string sourceLang, string targetLang,
Dictionary<string, string> entries);
Task DeleteGlossaryAsync(string glossaryId);
Task<GlossaryInfo> GetGlossaryAsync(string glossaryId);
Task<GlossaryInfo[]> ListGlossariesAsync();
Task<Dictionary<string, string>> GetGlossaryEntriesAsync(
string glossaryId);
// Style rules (v3)
Task<StyleRuleResponse> CreateStyleRuleListAsync(
string name, string language,
JsonElement configuredRules,
IEnumerable<CustomInstructionRequest> customInstructions);
Task ReplaceConfiguredRulesAsync(
string styleId, JsonElement configuredRules);
Task<CustomInstructionResponse> AddCustomInstructionAsync(
string styleId, string label, string prompt,
string? sourceLanguage = null);
Task DeleteCustomInstructionAsync(
string styleId, string instructionId);
Task DeleteStyleRuleListAsync(string styleId);
// Usage tracking
Task<Usage> GetUsageAsync();
Task<Language[]> GetSourceLanguagesAsync();
Task<Language[]> GetTargetLanguagesAsync();
}
Die Implementierung kümmert sich um die Normalisierung des Sprachcodes. DeepL erfordert EN-US oder EN-GB anstelle des bloßen en und PT-PT oder PT-BR anstelle von pt:
private static string NormalizeLanguageCode(string code)
=> code.ToLower() switch
{
"en" => "EN-US",
"pt" => "PT-PT",
_ => code.ToUpper()
};
Die Batch-Übersetzung verwendet 50-Elemente-Chunking, um die API-Grenzen von DeepL einzuhalten und gleichzeitig den Durchsatz zu maximieren:
public async Task<TranslationBatchResult> TranslateBatchAsync(
Dictionary<string, string> texts,
string sourceLanguage, string targetLanguage)
{
var translations = new Dictionary<string, string>();
long totalChars = 0;
foreach (var chunk in texts.Chunk(50))
{
var results = await _deepL.TranslateTextBatchAsync(
chunk.Select(kv => kv.Value),
sourceLanguage, targetLanguage);
for (int i = 0; i < chunk.Length; i++)
{
translations[chunk[i].Key] = results[i].Text;
totalChars += chunk[i].Value.Length;
}
}
return new TranslationBatchResult
{
Translations = translations,
BilledCharacters = totalChars
};
}
Da wir nur veraltete Blöcke und nicht ganze Dokumente senden, enthält ein typischer Übersetzungsstapel für eine einzelne Bearbeitung 1-3 Blöcke statt 40+. Daher kommt die Kostenreduzierung von 94 %.
Der Übersetzungs-Orchestrator
Der TranslationOrchestrator entscheidet, was mit den einzelnen Blöcken geschehen soll, wenn sich das Quelldokument ändert. Schauen wir uns den Entscheidungsbaum an:
public async Task OrchestrateTranslationAsync(
Guid entryId, List<Guid> changedBlockIds,
CancellationToken ct = default)
{
var entry = await _db.Entries
.FirstOrDefaultAsync(e => e.Id == entryId, ct);
var translations = await _db.EntryTranslations
.Where(t => t.EntryId == entryId)
.ToListAsync(ct);
foreach (var translation in translations)
{
var langConfig = await GetLanguageConfigAsync(
translation.Language, ct);
var translationBlocks = await _db.TranslationBlocks
.Where(tb => changedBlockIds.Contains(tb.SourceBlockId)
&& tb.Language == translation.Language)
.ToListAsync(ct);
foreach (var block in translationBlocks)
{
if (block.IsLocked || block.TranslatedById is not null)
{
// Human-edited or locked - mark stale, don't overwrite
block.Status = TranslationStatus.Stale;
}
else if (langConfig.Trigger == TranslationTrigger.AlwaysTranslate)
{
// Machine-translated, auto mode - retranslate now
await RetranslateBlockAsync(block, translation.Language, ct);
}
else
{
// TranslateOnFirstVisit - mark stale, translate later
block.Status = TranslationStatus.Stale;
}
}
}
await _db.SaveChangesAsync(ct);
}
Der wichtigste Punkt: Von Menschen bearbeitete Blöcke werden niemals automatisch überschrieben. Wenn ein Übersetzer einen Block manuell angepasst hat, z. B. durch Hinzufügen von kulturellem Kontext oder eine klarere Formulierung, respektiert das System diese Arbeit. Es markiert den Block als veraltet, damit der Übersetzer weiß, dass sich die Quelle geändert hat, aber es ersetzt seine Änderungen nicht stillschweigend.
Maschinell übersetzte Blöcke, bei denen AlwaysTranslate aktiviert ist, werden sofort neu übersetzt. Maschinell übersetzte Blöcke mit TranslateOnFirstVisit werden als veraltet markiert und übersetzt, wenn jemand das Dokument in dieser Sprache öffnet.
Übersetzungsauslöser: wann Übersetzungen stattfinden
Jede Sprache hat einen TranslationTrigger, der das Timing steuert:
public enum TranslationTrigger
{
AlwaysTranslate, // Translate on every save
TranslateOnFirstVisit // Translate when first opened in that language
}
AlwaysTranslate ist nützlich für Sprachen mit hoher Priorität, bei denen du möchtest, dass die Übersetzungen sofort aktuell sind. Französisch für ein Unternehmen mit einer großen Niederlassung in Paris. Deutsch für ein Unternehmen mit Hauptsitz in München.
TranslateOnFirstVisit ist nützlich für Sprachen, die gelegentlich gebraucht werden, aber die API-Kosten nicht wert sind, um sie immer auf dem neuesten Stand zu halten. Wenn jemand das Dokument in dieser Sprache öffnet, werden veraltete Blöcke sofort übersetzt.
Beide Modi verwenden die gleiche Glossarauflösung, die gleichen Formalitätseinstellungen und das gleiche Content-Hashing. Der einzige Unterschied ist das Timing.
Einzigartige Anpassung von Inhalt und Struktur
Hier zahlt sich die Architektur über die reine Übersetzung hinaus wirklich aus.
Wenn ein deutscher Übersetzer einen Abschnitt zur Einhaltung der DSGVO hinzufügt, den es im Englischen nicht gibt, fügt er ihn in der deutschen Version als neuen Block hinzu. Dieser Block hat keinen SourceBlockId, er ist als einzigartiger Inhalt gekennzeichnet. Das System schickt ihn nie zur Neuübersetzung, weil es keine Quelle gibt, aus der er übersetzt werden kann. Er existiert nur auf Deutsch.
Wenn ein japanischer Übersetzer eine Aufzählung in eine nummerierte Liste umwandelt (eine gängige Konvention in der japanischen Fachliteratur), bleibt das IsStructureAdapted-Kennzeichen des Blocks auch in zukünftigen Übersetzungszyklen erhalten:
var translation = new TranslationBlock
{
SourceBlockId = sourceBlockId,
Language = targetLanguage,
BlockType = translatedBlockType,
SourceBlockType = sourceBlock.BlockType,
IsStructureAdapted = translatedBlockType != sourceBlock.BlockType,
StructureAdaptationNotes = "Numbered list preferred in JP technical docs",
SourceContentHash = sourceBlock.ContentHash,
Status = TranslationStatus.UpToDate,
};
Das IsNoTranslate Flag behandelt Inhalte, die wortwörtlich kopiert werden sollen: Codeblöcke, URLs, Produktnamen, mathematische Notationen. Der Übersetzungsanbieter überspringt diese komplett.
Alles zusammenfügen
Gehen wir den gesamten Ablauf durch. Ein Benutzer in London bearbeitet einen Absatz im englischen Quelldokument, und dein Münchner Büro hat Deutsch auf AlwaysTranslate eingestellt:
- Benutzer speichert. TipTap sendet JSON an die API.
- Blockextraktion und Änderungserkennung.
CreateBlocksFromDocumentAsyncanalysiert JSON, berechnet die Hashes der Inhalte neu und vergleicht die alten und neuen Hashes, um festzustellen, welche Blöcke sich tatsächlich geändert haben. - Orchestrator läuft. Findet den deutschen
EntryTranslation, überprüft den deutschen Block. Er ist maschinell übersetzt, nicht gesperrt und nicht von Menschenhand bearbeitet, also kann er neu übersetzt werden. - **Übersetzungskonfiguration geladen ** Glossar-ID über
GetOrSyncDeepLGlossaryIdAsync("en", "de")aufgelöst, Stilregeln überGetOrSyncStyleRuleListAsync("de"), Formalität auf "mehr" (formal "Sie") gesetzt, benachbarte Blöcke als Kontext für die Disambiguierung übergeben. - DeepL Aufruf. Ein einzelner Block wird mit Glossar-ID, Stil-ID, Formalität und Kontext gesendet.
- Block aktualisiert. Übersetzter Inhalt gespeichert,
SourceContentHashsynchronisiert, Status aufUpToDategesetzt. Ein Block anstelle von 40+ übersetzt. Die restlichen 39 Blöcke? Unangetastet.
In deinem Büro in Tokio ist Japanisch auf TranslateOnFirstVisit gesetzt. Die gleiche Bearbeitung markiert den japanischen Übersetzungsblock als Stale. Wenn jemand in Tokio das Dokument öffnet, werden die Schritte 5-9 im Handumdrehen ausgeführt. Ihre Strukturanpassung (nummerierte Liste) bleibt erhalten. Ihre einzigartigen Blöcke bleiben genau dort, wo sie sind.
Meiner Meinung nach ist die Übersetzungsmaschine der Teil von Rasepi, der den größten sichtbaren Nutzen bringt. Übersetzungen, die deine Terminologie verwenden, deine Formatierungskonventionen befolgen, deine eigenen Anweisungen befolgen, deinen Tonfall treffen, die Arbeit deiner Übersetzer respektieren und nur einen Bruchteil dessen kosten, was eine vollständige Neuübersetzung kosten würde. Die Architektur sorgt dafür, dass all das automatisch abläuft, und hält sich aus dem Weg, wenn Menschen die Arbeit übernehmen wollen.
Dieselbe DeepL Engine, die für die schriftlichen Übersetzungen zuständig ist, treibt auch Talk to Docs an, unsere dialogorientierte Dokumentationsschnittstelle, bei der DeepL Voice die gesprochene Interaktion übernimmt. Dieselben Glossare, dieselben Stilregeln, dieselbe Formalität, dieselbe Konsistenz. Ob dein Team die Dokumentation liest oder mit ihr spricht, die Sprachqualität ist identisch.