Clientseitig
Für Code, der im Browser läuft — Gadgets, Userexits und die in serverseitigen Konfigurationen eingebetteten Callbacks — steht das Clientmodul I18n bereit. Die Übersetzungen stammen aus derselben Locale-Datei; clientseitig werden sie über den I18n-Kontext des Clients gelesen statt über die Systemtabelle.
Zugriff
Das Modul wird wie jedes andere Clientmodul über mustGetClientModule geholt:
import { mustGetClientModule } from "@one-unity/library/client";
import type { Locales } from "./ou.sp.ptpINV.installer.step.globalPropertiesLocales";
const t = mustGetClientModule<typeof I18n>("I18n").createT<Locales>();
Welche Member es gibt und wie ihre Signaturen aussehen, steht in der API-Referenz unter I18n.
Ein language-Parameter existiert clientseitig nicht; es gilt immer die Sprache der aktuellen Sitzung.
Eingebettete Callbacks
Viele Konfigurationsskripte (settings.*, Hitlist- und Gadget-Konfigurationen) laufen auf dem Server, um die Konfiguration zu bauen. Nur die Funktionskörper von click, render und ähnlichen Callbacks werden serialisiert und im Browser neu ausgeführt.
t muss innerhalb des Callbacks erzeugt werdenEin serialisierter Callback ist keine Closure. Er kann zur Laufzeit ausschließlich auf clientseitige Globals zugreifen (I18n, document, documentsContext) — niemals auf eine Variable, die im umgebenden serverseitigen Objektliteral deklariert wurde. Der mustGetClientModule-Aufruf gehört deshalb in den Callback selbst.
markPosition: {
click: (_, row, options) => {
const t = mustGetClientModule<typeof I18n>("I18n").createT<Locales>();
if (isParentContainerInvisible) {
documentsContext.openMessageDialog(
t((l) => l.filetype.ptpInvoice.monitorRMB.viewerNotOpen.title),
t((l) => l.filetype.ptpInvoice.monitorRMB.viewerNotOpen.message)
);
return;
}
},
},
Ob ein Codeabschnitt server- oder clientseitig läuft, entscheidet sich am umgebenden Code, nicht am Dateinamen: serverseitiger Code verwendet context.* und docFile.*, clientseitiger documents.sdk.*, einen documentsContext-Parameter oder DOM-Globals. Eine einzelne Gadget_*-Datei kann beides enthalten.
Verhalten
Identisch zur Serverseite: fehlt ein Eintrag, wird der Key zurückgegeben; {{platzhalter}} ohne passenden Wert bleiben stehen; ohne data findet keine Ersetzung statt.
Inline-Literale ersetzen
documents.sdk.utils.getLocaleValue("de:…;en:…") sieht wie eine Übersetzung aus, ist aber ein hart kodierter zweisprachiger String — eine neue Sprache erreicht er nie. Beim Migrieren wird er wie jeder andere Klartext behandelt: erst einen Key in der Locale-Datei anlegen, dann den Aufruf ersetzen.
// vorher
documents.sdk.utils.getLocaleValue("de:Warnung;en:Warning");
// nachher
t((l) => l.filetype.ptpInvoice.monitorRMB.viewerNotOpen.title);