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>
387 lines
20 KiB
TypeScript
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}');
|
|
}
|
|
});
|
|
});
|