Locale-Dateien
Alle Strings einer Lösung liegen in genau einem Skript: ou.sp.<PREFIX>.installer.step.globalPropertiesLocales.ts. Dort werden sie als verschachtelte JavaScript-Objekte definiert, bei der Installation in das Properties-Format transformiert und als Globale Eigenschaft gespeichert.
Aufbau der Datei
Die Referenzsprache wird mit as const definiert, daraus wird der Struktur-Typ abgeleitet, und dieser erzwingt Vollständigkeit in allen weiteren Sprachen.
import { installLocales, type LocaleShape } from "@one-unity/library/ou.sp.I18n";
import type { InstallStepInputOptions } from "@one-unity/library/ou.sp.Package";
const de = {
folder: {
importFile: "Dateiimport",
importFileError: {
label: "Fehlerhaft",
action: { start: "Verarbeitung starten" },
},
},
importFile: {
transform: {
error: { overall: "{{count}} Dokumente mit Fehlern" },
},
},
} as const;
export type Locales = LocaleShape<typeof de>;
const en: Locales = {
folder: {
importFile: "File import",
importFileError: {
label: "Faulty",
action: { start: "Start processing" },
},
},
importFile: {
transform: {
error: { overall: "{{count}} documents with errors" },
},
},
};
export const locales = { de, en };
export function install(options: InstallStepInputOptions): void {
installLocales({ baseName: "ou.sp.ImportFiles", locales }, options);
}
Fehlt in en ein Key oder ist er falsch verschachtelt, ist das ein Compile-Fehler — nicht ein Laufzeitproblem, das erst in der zweiten Sprache auffällt.
- Typ-Fehler bei fehlenden Übersetzungen.
- Auto-Completion an jeder Aufrufstelle über Selektor-Funktionen (siehe Übersetzen).
- Eine neue Sprache ist eine weitere Konstante plus ein Eintrag in
locales.
installLocales
Erzeugt pro Sprache eine Globale Eigenschaft nach der Namenskonvention <baseName>_<sprache> und gibt die erzeugten Namen zurück. Signatur und alle Optionen siehe installLocales und InstallLocalesOptions.
Zwei Punkte, die sich aus der Signatur allein nicht ergeben: baseName ist der Name ohne Sprachsuffix — ou.sp.ImportFiles erzeugt ou.sp.ImportFiles_de und ou.sp.ImportFiles_en. Und wird der zweite Parameter mit den Installer-Step-Options belegt, meldet jede erzeugte Eigenschaft sich selbst über appendToResultSuccess.
Für den Sonderfall, dass ein Name nicht der Konvention folgen soll, gibt es installLocale für eine einzelne Sprache.
Erzeugtes Format
Aus dem Objekt oben wird für de folgender Inhalt gespeichert:
$PROPERTIES_ENCODING=UTF-8
folder.importFile=Dateiimport
folder.importFileError.label=Fehlerhaft
folder.importFileError.action.start=Verarbeitung starten
importFile.transform.error.overall={{count}} Dokumente mit Fehlern
Konventionen für Keys
Abschnitte nach Zuständigkeit
Die oberste Ebene trennt Beschriftungen, die bei der Installation gesetzt werden, von Meldungen, die zur Laufzeit entstehen.
| Abschnitt | Zweck | Beispiel |
|---|---|---|
outbar | Beschriftungen von Outbar-Einträgen | outbar.ptpInvoice → "Rechnungen" |
folder | Namen der angelegten Ordner | folder.importFile → "Dateiimport" |
filetype | Feldbeschriftungen, Registernamen und Action-Buttons am Mappentyp | filetype.importFile.filePath → "Pfad" |
workflow | Aufgabennamen, Entscheidungskommentare und Action-Buttons im Workflow | workflow.ptpInvoice.action.restart → "Erneute Prüfung" |
<entity> | Laufzeitmeldungen der Verarbeitung | importFile.transform.error.overall → "{{count}} Dokumente mit Fehlern" |
outbar, folder, filetype und workflow decken die Installationszeit ab. Alles andere ist ein paketspezifischer Abschnitt für Laufzeitmeldungen, benannt nach seiner Entität.
Beispielpfade aus invoice (ou.sp.ptpINV.installer.step.globalPropertiesLocales.ts):
# Installationszeit
outbar.ptpInvoice Outbar-Eintrag
folder.ptpInvoice Ordnername
filetype.ptpInvoice.MultiLangLabel Anzeigename des Mappentyps (PascalCase, Documents-Attribut)
filetype.ptpInvoice.Title AutoTitle-Präfix (PascalCase, Documents-Attribut)
filetype.ptpInvoice.eInvoiceType.label Feldbeschriftung mit Enum-Kindern
filetype.ptpInvoice.eInvoiceType.XRechnung Enum-Wert
folder.statusCodeConfig.form.table.column.statusCode.label Spaltenüberschrift
folder.statusCodeConfig.form.table.column.statusCode.tooltip Tooltip
workflow.ptpInvoice.Description Workflow-Beschreibung
workflow.ptpInvoice.task.validateData Aufgabenname
workflow.ptpInvoice.decisioncomment.validData.ok Entscheidungskommentar
workflow.ptpInvoice.action.restart Action-Button im Workflow
# Laufzeitmeldungen
goodsReceiptCheck.status.timeout.summary Aktionstext eines Statuseintrags
goodsReceiptCheck.status.timeout.description Kommentar dazu, mit {{days}}
ptpInvoice.exportToExtract.notification.title Titel einer Benachrichtigung
ptpInvoice.exportToExtract.notification.message Text dazu
Benennung
-
labelbei Knoten mit Doppelrolle — ist ein Knoten gleichzeitig Wert und Elternknoten, bekommt der Wert den Keylabel:fileType: {label: "Dateityp",singleFiles: "Einzeldatei",sid3: "SID3",} -
Platzhalter immer in doppelten geschweiften Klammern (
{{count}}). Einfache Klammern werden zur Laufzeit nicht ersetzt. -
Nach Domänen-Substantiv gruppieren, dann
errorbzw.action— Laufzeitabschnitte folgen dem Muster<entity>.error.*und<entity>.action.*.
Ein Key darf entweder verschachtelt oder in Punkt-Notation geschrieben werden, aber nicht beides parallel für denselben Pfad — sonst kollidieren zwei Einträge im erzeugten Properties-Inhalt und einer überschreibt den anderen. Der Testhelfer expectLocalesConsistent erkennt solche Kollisionen.
Bei Upgrades
Damit geänderte Strings auch in bestehenden Installationen ankommen, muss die exportierte install-Funktion als Erstes im Upgrade-Schritt in ou.sp.<PREFIX>.installer.update.next.ts aufgerufen werden.