// 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 { const text = new TextDecoder('latin1').decode(readFileSync(join(bundles, file))); const entries = new Map(); 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> = { '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', }; /** Java's words with an error of Java's mended: the prompt says "Vermittlungsrechnerns" (guicontainer_msg1). */ const FROM_JAVA_MENDED: Readonly string]>> = { 'router.prompt': ['guicontainer_msg1', (java) => java.replace(' \\n ', ' ').replace('Vermittlungsrechnerns', 'Vermittlungsrechners')], }; 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)!)); } }); });