Files
mdg-filius/packages/editor/test/i18n.test.ts
T
julian.kiedaischandClaude Opus 5.5 065b42430d feat: F4.6g2 the DNS server window, its records being /dns/hosts
Oracle DnsWindowRun uses Java's DNS server window as a person does and
asks a computer's resolver after each step. The core's DNS server is a
program its window changes: on and off (its socket on port 53),
recursive resolution, and records that are /dns/hosts, read on every
query as Java's server reads them (the reader moves from fls to the
core). The snapshot carries every installed DNS server with whether it
runs. The room takes the window's actions, sends its view and writes
the server back after the run; the editor shows Java's window with its
three tabs. Not taken from Java: a cell edit spilling into records of
another type, an add losing what another program wrote into the file,
an empty mail domain, a removal hitting the first record of the name.
A table cell no longer takes the room's value over what is being typed
(the web server's too).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 20:36:17 +00:00

387 lines
20 KiB
TypeScript

// The catalogs: the same keys in both languages, placeholders filled, and —
// where Java FILIUS names a thing — Java's word in its bundle (M11).
import { existsSync, readFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { describe, expect, it } from 'vitest';
import { CATALOGS, translate } from '../src/i18n/i18n.js';
const bundles = join(dirname(fileURLToPath(import.meta.url)), '../../../tools/java-oracle/.upstream/src/main/resources/filius/messages');
/** A Java .properties file: ISO-8859-1, \uXXXX escapes, `key = value`, a backslash at a line's end going on in the next without its indent. */
function properties(file: string): Map<string, string> {
const text = new TextDecoder('latin1').decode(readFileSync(join(bundles, file))).replace(/\\\r?\n[ \t]*/g, '');
const entries = new Map<string, string>();
for (const line of text.split(/\r?\n/)) {
const match = /^([\w.]+)\s*=\s*(.*)$/.exec(line);
if (match !== null) entries.set(match[1]!, match[2]!.replace(/\\u([0-9a-fA-F]{4})/g, (_, hex: string) => String.fromCharCode(Number.parseInt(hex, 16))).trim());
}
return entries;
}
/** The editor's keys whose words are Java's, and the key of each in Java's bundle. */
const FROM_JAVA: Readonly<Record<string, string>> = {
'device.pc': 'hw_rechner_msg1',
'explorer.newFolder': 'fileexplorer_msg3',
'explorer.delete': 'fileexplorer_msg4',
'explorer.cut': 'fileexplorer_msg5',
'explorer.copy': 'fileexplorer_msg6',
'explorer.paste': 'fileexplorer_msg7',
'explorer.rename': 'fileexplorer_msg8',
'explorer.newName': 'fileexplorer_msg9',
'explorer.file': 'fileexplorer_msg10',
'explorer.folder': 'fileexplorer_msg11',
'explorer.import': 'fileexplorer_msg2',
'explorer.importTitle': 'fileexplorer_msg12',
'explorer.localFile': 'fileexplorer_msg13',
'explorer.chooseFile': 'fileexplorer_msg14',
'explorer.importButton': 'fileexplorer_msg15',
'explorer.importMissing': 'fileexplorer_msg16',
'explorer.sure': 'fileexplorer_msg18',
'explorer.invalidTarget': 'fileexplorer_msg19',
'explorer.close': 'sw_fileimporter_msg3',
'explorer.imported': 'sw_fileexplorer_msg2',
'explorer.notImported': 'sw_fileexplorer_msg1',
'explorer.tooLarge': 'sw_fileexplorer_msg3',
'viewer.open': 'imageviewer_msg2',
'echoServer.port': 'serverbaustein_msg1',
'echoServer.stop': 'serverbaustein_msg2',
'echoServer.start': 'serverbaustein_msg3',
'simpleClient.address': 'clientbaustein_msg1',
'simpleClient.port': 'clientbaustein_msg2',
'simpleClient.connect': 'clientbaustein_msg3',
'simpleClient.message': 'clientbaustein_msg4',
'simpleClient.send': 'clientbaustein_msg5',
'simpleClient.disconnect': 'clientbaustein_msg6',
'simpleClient.connected': 'sw_clientbaustein_msg2',
'simpleClient.disconnected': 'sw_clientbaustein_msg3',
'simpleClient.notConnected': 'sw_clientbaustein_msg4',
'simpleClient.receiveFailed': 'sw_tcpsocket_msg9',
'simpleClient.failure.unresolved': 'sw_socket_msg1',
'simpleClient.failure.timedOut': 'sw_tcpsocket_msg2',
'simpleClient.failure.failed': 'sw_tcpsocket_msg3',
'dnsServer.start': 'dnsserver_msg1',
'dnsServer.stop': 'dnsserver_msg14',
'dnsServer.tabA': 'dnsserver_msg2',
'dnsServer.tabMX': 'dnsserver_msg3',
'dnsServer.tabNS': 'dnsserver_msg15',
'dnsServer.aName': 'dnsserver_msg4',
'dnsServer.aAddress': 'dnsserver_msg5',
'dnsServer.add': 'dnsserver_msg6',
'dnsServer.remove': 'dnsserver_msg7',
'dnsServer.aNameColumn': 'dnsserver_msg8',
'dnsServer.aAddressColumn': 'dnsserver_msg9',
'dnsServer.mxDomain': 'dnsserver_msg10',
'dnsServer.mxServer': 'dnsserver_msg11',
'dnsServer.mxDomainColumn': 'dnsserver_msg12',
'dnsServer.mxServerColumn': 'dnsserver_msg13',
'dnsServer.nsDomain': 'dnsserver_msg16',
'dnsServer.nsServer': 'dnsserver_msg17',
'dnsServer.nsDomainColumn': 'dnsserver_msg18',
'dnsServer.nsServerColumn': 'dnsserver_msg19',
'dnsServer.recursive': 'dnsserver_msg20',
'textEditor.new': 'texteditor_msg3',
'textEditor.open': 'texteditor_msg4',
'textEditor.save': 'texteditor_msg5',
'textEditor.saveAs': 'texteditor_msg6',
'fileDialog.up': 'dmtnfilechooser_msg1',
'fileDialog.name': 'dmtnfilechooser_msg2',
'fileDialog.cancel': 'dmtnfilechooser_msg4',
'fileDialog.saveTitle': 'dmtnfilechooser_msg5',
'fileDialog.save': 'dmtnfilechooser_msg6',
'fileDialog.openTitle': 'dmtnfilechooser_msg7',
'fileDialog.open': 'dmtnfilechooser_msg8',
'fileDialog.folder': 'dmtnfilechooser_msg11',
'device.notebook': 'hw_notebook_msg1',
'device.networkSwitch': 'hw_switch_msg1',
'device.router': 'hw_vermittlungsrechner_msg1',
'device.gateway': 'hw_gateway_msg1',
'device.cable': 'hw_kabel_msg1',
'menu.removeCable': 'guievents_msg5',
'menu.removeAllCables': 'guievents_msg6',
'menu.delete': 'guievents_msg7',
'cable.noFreePort': 'guievents_msg1',
'cable.alreadyConnected': 'guievents_msg12',
'cable.wanOccupied': 'guievents_msg22',
'cable.lanOccupied': 'guievents_msg23',
'cable.wan': 'guievents_msg24',
'cable.lan': 'guievents_msg25',
'cable.wirelessNotPossible': 'guievents_msg26',
'router.title': 'guicontainer_msg2',
'sheet.name': 'jhostkonfiguration_msg1',
'sheet.ipAddress': 'jhostkonfiguration_msg3',
'sheet.subnetMask': 'jhostkonfiguration_msg4',
'sheet.defaultGateway': 'jhostkonfiguration_msg5',
'sheet.dnsServer': 'jhostkonfiguration_msg6',
'sheet.dhcpClient': 'jhostkonfiguration_msg7',
'sheet.macAddress': 'jhostkonfiguration_msg9',
'sheet.ipAsName': 'jhostkonfiguration_msg10',
'sheet.ipForwarding': 'jhostkonfiguration_msg11',
'sheet.macAsName': 'jhostkonfiguration_msg12',
'sheet.wireless': 'jhostkonfiguration_msg13',
'sheet.cable': 'jhostkonfiguration_msg14',
'sheet.chooseNetwork': 'jhostkonfiguration_msg16',
'sheet.cloud': 'jswitchkonfiguration_msg3',
'sheet.switchSsid': 'jswitchkonfiguration_msg4',
'sheet.retention': 'jswitchkonfiguration_msg5',
'sheet.port': 'jmodemkonfiguration_msg4',
'sheet.general': 'jvermittlungsrechnerkonfiguration_msg17',
'sheet.notConnected': 'jvermittlungsrechnerkonfiguration_msg16',
'sheet.rip': 'jvermittlungsrechnerkonfiguration_msg26',
'sheet.forwardingTable': 'jvermittlungsrechnerkonfiguration_msg15',
'sheet.showAllEntries': 'jvermittlungsrechnerkonfiguration_msg11',
'sheet.newEntry': 'jvermittlungsrechnerkonfiguration_msg12',
'route.destinationNetwork': 'jweiterleitungstabelle_msg3',
'route.subnetMask': 'jweiterleitungstabelle_msg4',
'route.gateway': 'jweiterleitungstabelle_msg5',
'route.interfaceIPAddress': 'jweiterleitungstabelle_msg6',
'sheet.dhcpServer': 'jhostkonfiguration_msg8',
'sheet.portForwarding': 'jgatewayconfiguration_msg19',
'dhcp.lowerBound': 'jdhcpkonfiguration_msg1',
'dhcp.upperBound': 'jdhcpkonfiguration_msg2',
'dhcp.subnetMask': 'jdhcpkonfiguration_msg3',
'dhcp.gateway': 'jdhcpkonfiguration_msg4',
'dhcp.dnsServer': 'jdhcpkonfiguration_msg5',
'dhcp.active': 'jdhcpkonfiguration_msg6',
'dhcp.ownSettings': 'jdhcpkonfiguration_msg8',
'dhcp.basic': 'jdhcpkonfiguration_msg10',
'dhcp.static': 'jdhcpkonfiguration_msg11',
'dhcp.macAddress': 'jdhcpkonfiguration_msg12',
'dhcp.ipAddress': 'jdhcpkonfiguration_msg13',
'dhcp.add': 'jdhcpkonfiguration_msg14',
'dhcp.remove': 'jdhcpkonfiguration_msg15',
'forwarding.protocolValue': 'jportforwarding_msg4',
'forwarding.publicPortValue': 'jportforwarding_msg5',
'forwarding.lanIPAddress': 'jportforwarding_msg6',
'forwarding.lanPortValue': 'jportforwarding_msg7',
'sheet.firewall': 'jvermittlungsrechnerkonfiguration_msg4',
'firewall.rules': 'jfirewalldialog_msg21',
'firewall.up': 'jfirewalldialog_msg22',
'firewall.down': 'jfirewalldialog_msg23',
'firewall.add': 'jfirewalldialog_msg24',
'firewall.delete': 'jfirewalldialog_msg25',
'firewall.number': 'jfirewalldialog_msg26',
'firewall.sourceIPAddress': 'jfirewalldialog_msg27',
'firewall.sourceSubnetMask': 'jfirewalldialog_msg28',
'firewall.destinationIPAddress': 'jfirewalldialog_msg29',
'firewall.destinationSubnetMask': 'jfirewalldialog_msg30',
'firewall.protocol': 'jfirewalldialog_msg31',
'firewall.accept': 'jfirewalldialog_msg33',
'firewall.drop': 'jfirewalldialog_msg34',
'firewall.port': 'jfirewalldialog_msg35',
'firewall.active': 'jfirewalldialog_msg38',
'firewall.activeHint': 'jfirewalldialog_msg39',
'firewall.dropIcmp': 'jfirewalldialog_msg40',
'firewall.dropIcmpHint': 'jfirewalldialog_msg41',
'firewall.filterSyn': 'jfirewalldialog_msg42',
'sheet.connections': 'jvermittlungsrechnerkonfiguration_msg23',
'connections.local': 'jvermittlungsrechnerkonfiguration_msg22',
'connections.add': 'jvermittlungsrechnerkonfiguration_msg24',
'connections.most': 'jvermittlungsrechnerkonfiguration_msg25',
'mode.speed': 'guimainmemu_msg16',
'installation.installed': 'installationsdialog_msg3',
'installation.available': 'installationsdialog_msg4',
'installation.apply': 'installationsdialog_msg2',
'mode.currentSpeed': 'guimainmemu_msg15',
'menu.showDesktop': 'guievents_msg3',
'desktop.home': 'desktoppanel_application',
'desktop.installation': 'desktoppanel_msg1',
'network.ipAddress': 'network_msg1',
'network.subnetMask': 'network_msg4',
'network.dnsServer': 'network_msg2',
'network.gateway': 'network_msg3',
'network.macAddress': 'network_msg9',
'browser.go': 'webbrowser_msg2',
'server.start': 'webserver_msg1',
'server.stop': 'webserver_msg2',
'webServer.virtualHosts': 'webserver_msg3',
'webServer.hostName': 'webserver_msg4',
'webServer.folder': 'webserver_msg5',
'webServer.useVirtualHosts': 'webserver_msg6',
'server.acceptingStopped': 'sw_serveranwendung_msg1',
'server.acceptingStarted': 'sw_serveranwendung_msg2',
'server.serverSocketClosed': 'sw_serveranwendung_msg3',
'server.serverSocketFailed': 'sw_serveranwendung_msg6',
'server.sendFailed.notConnected': 'sw_tcpsocket_msg6',
'server.sendFailed.connectionLost': 'sw_tcpsocket_msg7',
'server.sendFailed.timedOut': 'sw_tcpsocket_msg8', 'emailClient.sender': 'emailanwendung_msg1',
'emailClient.subject': 'emailanwendung_msg2',
'emailClient.recipient': 'emailanwendung_msg3',
'emailClient.inbox': 'emailanwendung_msg5',
'emailClient.sent': 'emailanwendung_msg6',
'emailClient.fetch': 'emailanwendung_msg7',
'emailClient.compose': 'emailanwendung_msg8',
'emailClient.answer': 'emailanwendung_msg9',
'emailClient.deleteHint': 'emailanwendung_msg10',
'emailClient.accountHint': 'emailanwendung_msg11',
'emailClient.composeTitle': 'emailanwendung_msg12',
'emailClient.send': 'emailanwendung_msg13',
'emailClient.toLabel': 'emailanwendung_msg14',
'emailClient.ccLabel': 'emailanwendung_msg15',
'emailClient.bccLabel': 'emailanwendung_msg16',
'emailClient.subjectLabel': 'emailanwendung_msg17',
'emailClient.re': 'emailanwendung_msg18',
'emailClient.wrote': 'emailanwendung_msg19',
'emailClient.invalidAddress': 'emailanwendung_msg20',
'emailClient.noRecipient': 'emailanwendung_msg21',
'emailClient.accountTitle': 'emailanwendung_msg25',
'emailClient.email': 'emailanwendung_msg26',
'emailClient.pop3Host': 'emailanwendung_msg27',
'emailClient.pop3Port': 'emailanwendung_msg28',
'emailClient.smtpHost': 'emailanwendung_msg29',
'emailClient.smtpPort': 'emailanwendung_msg30',
'emailClient.username': 'emailanwendung_msg31',
'emailClient.password': 'emailanwendung_msg32',
'emailClient.save': 'emailanwendung_msg33',
'emailClient.cancel': 'emailanwendung_msg37',
'emailClient.delete': 'emailanwendung_msg43',
'emailClient.account': 'emailanwendung_msg44',
'emailClient.name': 'emailanwendung_msg45',
'emailClient.accountInvalid': 'emailanwendung_msg46',
'emailClient.noAccount': 'emailanwendung_msg47',
'emailServer.start': 'emailserver_msg1',
'emailServer.started': 'emailserver_msg2',
'emailServer.stopped': 'emailserver_msg3',
'emailServer.domain': 'emailserver_msg4',
'emailServer.deleteAccount': 'emailserver_msg8',
'emailServer.yes': 'emailserver_msg9',
'emailServer.cancel': 'emailserver_msg10',
'emailServer.confirmTitle': 'emailserver_msg13',
'emailServer.address': 'emailserver_msg14',
'emailServer.mails': 'emailserver_msg15',
'emailServer.username': 'emailserver_msg16',
'emailServer.name': 'emailserver_msg17',
'emailServer.password': 'emailserver_msg18',
'emailServer.create': 'emailserver_msg19',
'emailServer.lastNamePlaceholder': 'emailserver_msg20',
'emailServer.firstNamePlaceholder': 'emailserver_msg21',
'emailServer.whiteSpace': 'emailserver_msg24',
'emailServer.missing': 'emailserver_msg25',
'emailServer.newAccount': 'emailserver_msg26',
'emailServer.accounts': 'emailserver_msg27',
'emailServer.log': 'emailserver_msg28',
'emailServer.stop': 'emailserver_msg29',
'mail.failure.unresolved': 'sw_socket_msg1',
'mail.failure.timedOut': 'sw_tcpsocket_msg2',
'mail.failure.failed': 'sw_tcpsocket_msg3',
'mail.failure.receiveFailed': 'sw_tcpsocket_msg6',
};
/** Java's words, mended: the prompt says "Vermittlungsrechnerns" (guicontainer_msg1). */
const FROM_JAVA_MENDED: Readonly<Record<string, readonly [string, (java: string) => string]>> = {
'router.prompt': ['guicontainer_msg1', (java) => java.replace(' \\n ', ' ').replace('Vermittlungsrechnerns', 'Vermittlungsrechners')],
// A label above its list, without the colon of Java's label beside it.
'sheet.network': ['jhostkonfiguration_msg15', (java) => java.replace(/:$/, '')],
// Java's message dialog breaks its lines with \n.
'dnsServer.invalidA': ['dnsserver_msg21', (java) => java.replaceAll('\\n', '\n')],
'dnsServer.invalidNS': ['dnsserver_msg22', (java) => java.replaceAll('\\n', '\n')],
'dnsServer.invalidMX': ['dnsserver_msg23', (java) => java.replaceAll('\\n', '\n')],
// Java writes "Eintrag Löschen".
'sheet.deleteEntry': ['jvermittlungsrechnerkonfiguration_msg13', (java) => java.replace('Löschen', 'löschen')],
// Java's word, then what it joins or which card.
'sheet.connectedTo': ['jvermittlungsrechnerkonfiguration_msg6', (java) => `${java} {device}`],
'sheet.nic': ['jvermittlungsrechnerkonfiguration_msg10', (java) => `${java} {number}`],
// A column's title without Java's question mark ("Aktion?").
'firewall.action': ['jfirewalldialog_msg32', (java) => java.replace(/\?$/, '')],
// A label above its list, without the colon.
'firewall.defaultPolicy': ['jfirewalldialog_msg36', (java) => java.replace(/:$/, '')],
// Java's "\n" as line breaks; the last sentence of the German starts with a small letter there.
'firewall.intro': ['jfirewalldialog_msg37', (java) => java.replaceAll('\\n', '\n').replace('\nüber', '\nÜber')],
'firewall.filterSynHint': ['jfirewalldialog_msg43', (java) => java.replaceAll('\\n', '\n')],
// Java's welcome without its bold tags (the panel writes it as text, Java's "!" after it).
'emailClient.welcome': ['emailanwendung_msg4', (java) => java.replace(/<\/?b>/g, '')],
// Without Java's key (Strg+D, Strg+R): in a browser they bookmark and reload the page.
'mode.design': ['guimainmemu_msg3', (java) => java.replace(/ \((Strg|Ctrl)\+D\)$/, '')],
'mode.simulation': ['guimainmemu_msg4', (java) => java.replace(/ \((Strg|Ctrl)\+R\)$/, '')],
// Java's lines without their leading space and the empty one; a step starts with a capital letter.
'connections.hint': [
'jvermittlungsrechnerkonfiguration_msg19',
(java) =>
java
.split('\\n')
.map((line) => line.trim().replace(/^(\d\. )(\p{Ll})/u, (_, step: string, letter: string) => step + letter.toUpperCase()))
.filter((line) => line !== '')
.join('\n'),
],
};
/** Java's words around a value, as its programs join them („Verbindung zu“ + address + „hergestellt“). */
const FROM_JAVA_JOINED: Readonly<Record<string, readonly [string, string, string]>> = {
'server.connectionAccepted': ['sw_serveranwendung_msg4', '{address}', 'sw_serveranwendung_msg5'],
'simpleClient.connectionClosed': ['sw_clientbaustein_msg5', '{address}', 'sw_clientbaustein_msg6'],
'server.connectionClosed': ['sw_servermitarbeiter_msg1', '{address}', 'sw_servermitarbeiter_msg2'],
'emailServer.created': ['emailserver_msg22', '{name}', 'emailserver_msg23'],
'mail.stored': ['sw_smtpmitarbeiter_msg12', '{name}', 'sw_smtpmitarbeiter_msg13'],
'mail.connected': ['sw_smtpclient_msg1', '{address}', 'sw_smtpclient_msg2'],
'mail.disconnected': ['sw_smtpclient_msg1', '{address}', 'sw_smtpclient_msg3'],
};
/** Java's words before a value, joined as its programs join them (SMTPMitarbeiter, SMTPClient, the server window's question). */
const FROM_JAVA_BEFORE: Readonly<Record<string, readonly [string, string, string?]>> = {
'mail.sendFailed': ['sw_smtpmitarbeiter_msg14', ' {address}'],
'mail.mailSent': ['sw_smtpclient_msg4', ' {recipients}'],
// "'" + name + "'", the question's two halves written against it.
'emailServer.confirmDelete': ['emailserver_msg11', '{name}', 'emailserver_msg12'],
};
/** Java's page for a server it cannot reach (sw_webbrowser_msg1): its title and its heading. */
const FROM_JAVA_PAGE: Readonly<Record<string, readonly [string, RegExp]>> = {
'browser.unreachableTitle': ['sw_webbrowser_msg1', /<title>(.*)<\/title>/],
'browser.unreachable': ['sw_webbrowser_msg1', /<h1>(.*)<\/h1>/],
};
const templates = join(dirname(fileURLToPath(import.meta.url)), '../../../tools/java-oracle/.upstream/src/main/resources/tmpl');
describe('the catalogs', () => {
it('have the same keys in German and English, each with a text', () => {
expect(Object.keys(CATALOGS.en).sort()).toEqual(Object.keys(CATALOGS.de).sort());
for (const catalog of Object.values(CATALOGS)) for (const text of Object.values(catalog)) expect(text.trim()).not.toBe('');
});
it('fill placeholders, and show a key they lack', () => {
expect(translate('de', 'zoom.level', { percent: 75 })).toBe('75 %');
expect(translate('en', 'zoom.level')).toBe('{percent} %');
expect(translate('de', 'no.such.key')).toBe('no.such.key');
});
it('name every kind of device', () => {
for (const kind of ['pc', 'notebook', 'networkSwitch', 'router', 'gateway', 'remoteLink', 'unsupported']) expect(CATALOGS.de[`device.${kind}`]).toBeDefined();
// Java's Modem.TYPE, the same in every language.
expect([CATALOGS.de['device.remoteLink'], CATALOGS.en['device.remoteLink']]).toEqual(['Modem', 'Modem']);
});
it.skipIf(!existsSync(bundles))("use Java's words where Java has them (M11)", () => {
const [de, en] = [properties('MessagesBundle_de_DE.properties'), properties('MessagesBundle_en_GB.properties')];
for (const [key, javaKey] of Object.entries(FROM_JAVA)) {
expect(CATALOGS.de[key], key).toBe(de.get(javaKey));
expect(CATALOGS.en[key], key).toBe(en.get(javaKey));
}
for (const [key, [javaKey, mend]] of Object.entries(FROM_JAVA_MENDED)) {
expect(CATALOGS.de[key], key).toBe(mend(de.get(javaKey)!));
expect(CATALOGS.en[key], key).toBe(mend(en.get(javaKey)!));
}
for (const [key, [before, value, after]] of Object.entries(FROM_JAVA_JOINED)) {
expect(CATALOGS.de[key], key).toBe(`${de.get(before)} ${value} ${de.get(after)}`);
expect(CATALOGS.en[key], key).toBe(`${en.get(before)} ${value} ${en.get(after)}`);
}
for (const [key, [before, value, after]] of Object.entries(FROM_JAVA_BEFORE)) {
expect(CATALOGS.de[key], key).toBe(`${de.get(before)}${value}${after === undefined ? '' : de.get(after)}`);
expect(CATALOGS.en[key], key).toBe(`${en.get(before)}${value}${after === undefined ? '' : en.get(after)}`);
}
for (const [key, [javaKey, part]] of Object.entries(FROM_JAVA_PAGE)) {
expect(CATALOGS.de[key], key).toBe(part.exec(de.get(javaKey)!)![1]);
expect(CATALOGS.en[key], key).toBe(part.exec(en.get(javaKey)!)![1]);
}
});
it.skipIf(!existsSync(templates))("write the browser's error page as Java's template does (tmpl/http_fehler)", () => {
for (const [language, file] of [['de', 'http_fehler_de_DE.txt'], ['en', 'http_fehler_en_GB.txt']] as const) {
const template = readFileSync(join(templates, file), 'utf8').replaceAll(':meldung:', '{message}').replaceAll(':code:', '{code}');
expect(CATALOGS[language]['browser.errorTitle']).toBe(/<title>(.*)<\/title>/.exec(template)![1]);
expect(CATALOGS[language]['browser.errorText']).toBe(/<p>(.*)<\/p>/.exec(template)![1]!.trim());
expect(/<h1>(.*)<\/h1>/.exec(template)![1]).toBe('{message}');
}
});
});