#!/usr/bin/env node /** * Patches TriliumNext's bundled main.cjs to register Korean ("ko") as a * selectable UI language. * * Why this is needed: the list of supported UI languages is not derived * from the translations/ folders on disk — it's a hardcoded array literal * baked into the minified server bundle (variable name may change between * builds; as of triliumnext/notes:latest on 2026-08-25 it was `K5i`). * A second hardcoded map (`IMi` as of the same build) lazy-loads a * per-language resource (CKEditor's own locale bundle) and has no entry * for "ko" either — since that resource is genuinely not bundled for any * language we didn't already support, we alias it to the English loader * instead of trying to fabricate a missing chunk. * * Usage: node patch_main_cjs.js /path/to/main.cjs * * Run this against a FRESH copy of main.cjs extracted from the image * (`docker cp trilium:/usr/src/app/main.cjs .`) any time the image is * updated, since the minified variable names (K5i, IMi, xvr) and byte * offsets are not stable across TriliumNext releases. After patching, * always run `node --check main.cjs` before deploying it. */ const fs = require('fs'); const path = process.argv[2]; if (!path) { console.error('Usage: node patch_main_cjs.js /path/to/main.cjs'); process.exit(1); } let content = fs.readFileSync(path, 'utf8'); let patchedAnything = false; // --- Patch 1: register "ko" in the main supported-locales array --- // Original starts with: K5i=[{id:"en",name:"English",electronLocale:"en"},{id:"de" // We insert a new first element right after the opening `[`. { const marker = 'K5i=[{id:"en",name:"English",electronLocale:"en"},{id:"de"'; const idx = content.indexOf(marker); if (idx === -1) { console.log('[skip] locale-list marker not found (variable name may have changed, or already patched)'); } else { const insertPoint = idx + 'K5i=['.length; const insertion = '{id:"ko",name:"한국어",electronLocale:"ko"},'; content = content.slice(0, insertPoint) + insertion + content.slice(insertPoint); console.log('[ok] inserted "ko" into the supported-locales array'); patchedAnything = true; } } // --- Patch 2: alias "ko" to the English loader in the per-language resource map --- // Original: IMi={ar:...,cn:...,de:...,en:()=>Promise.resolve().then(()=>Xe(xvr())),es:... { const imiIdx = content.indexOf('IMi={ar:'); const marker = 'en:()=>Promise.resolve().then(()=>Xe(xvr())),es:'; const idx = content.indexOf(marker); if (imiIdx === -1 || idx === -1 || idx < imiIdx || idx > imiIdx + 700) { console.log('[skip] per-language resource map marker not found or not where expected (already patched, or minified names changed)'); } else { const insertion = 'en:()=>Promise.resolve().then(()=>Xe(xvr())),ko:()=>Promise.resolve().then(()=>Xe(xvr())),es:'; content = content.slice(0, idx) + insertion + content.slice(idx + marker.length); console.log('[ok] aliased "ko" to the English loader in the resource map'); patchedAnything = true; } } if (!patchedAnything) { console.log('Nothing patched (file may already be patched, or this is a different TriliumNext version — re-derive the markers manually).'); process.exit(0); } fs.writeFileSync(path, content, 'utf8'); console.log('Wrote', path, '— now run: node --check', path);