Measured first: SheetRun now types into FILIUS' DHCP dialog and keeps rows
in its port forwarding dialog. Java's DHCP server keeps its bounds as typed
(".0.0.1" too), never takes an empty gateway or DNS server, hands out the
device's gateway and DNS server unless its own (a home router always its
LAN address, where "manual settings" do nothing), drops a second static
assignment of a MAC address silently and lets "_" through its MAC pattern;
the port forwarding dialog keeps any row, its firmware forwards only the
valid ones. Here a value passes its rule or is not taken, with a word why.
- doc: DHCP server addresses and flags, static assignments (a MAC address
once, ignoring case), port forwarding rows (TCP or UDP, musterPort, the
LAN address); the sheet shows what the server hands out and which rows
Java's firmware forwards (the core's parsePortForwardingRow, exported)
- editor: Java's dialogs as pages of the sheet with a back button, the
three row tables on one RowsEditor (the forwarding table rebuilt on it);
a sheet per device, so an open page closes when another device is chosen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
132 lines
6.6 KiB
TypeScript
132 lines
6.6 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`. */
|
|
function properties(file: string): Map<string, string> {
|
|
const text = new TextDecoder('latin1').decode(readFileSync(join(bundles, file)));
|
|
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',
|
|
'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',
|
|
};
|
|
|
|
/** 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 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}`],
|
|
};
|
|
|
|
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)!));
|
|
}
|
|
});
|
|
});
|