node-red-contrib-knx-ultimate
Version:
Control your KNX and KNX Secure intallation via Node-Red! A bunch of KNX nodes, with integrated Philips HUE control and ETS group address importer. Easy to use and highly configurable.
129 lines (114 loc) • 5.07 kB
JavaScript
/*
Migrate inline node help to localized files under nodes/locales/<lang>/<node>.html
- For each nodes/*.html with a <script type="text/markdown" data-help-name="...">
- Remove the inline help block from the node file
- Create 4 locale files (en-US, it-IT, de-DE, zh-CN)
- Content source: corresponding wiki page for each language; if not found, fall back to current inline help
*/
const fs = require('fs');
const path = require('path');
const REPO = process.cwd();
const NODES_DIR = path.join(REPO, 'nodes');
const WIKI_DIR = path.resolve(REPO, '..', 'node-red-contrib-knx-ultimate.wiki');
const LANGS = [
{ key: 'en', dir: 'en-US', prefix: '' },
{ key: 'it', dir: 'it-IT', prefix: 'it-' },
{ key: 'de', dir: 'de-DE', prefix: 'de-' },
{ key: 'zh', dir: 'zh-CN', prefix: 'zh-CN-' },
];
// Map help-name (or file base) to wiki title
const HELP_TO_WIKI = new Map([
['knxUltimate-config', 'Gateway-configuration'],
['knxUltimate', 'KNX Node Configuration'],
['knxUltimateLogger', 'Logger-Configuration'],
['knxUltimateGlobalContext', 'GlobalVariable'],
['knxUltimateWatchDog', 'WatchDog-Configuration'],
['knxUltimateAlerter', 'Alerter-Configuration'],
['knxUltimateLoadControl', 'LoadControl-Configuration'],
['knxUltimateSceneController', 'SceneController-Configuration'],
['knxUltimateViewer', 'knxUltimateViewer'],
['knxUltimateAutoResponder', 'KNXAutoResponder'],
['knxUltimateHATranslator', 'HATranslator'],
['knxUltimateHueLight', 'HUE Light'],
['knxUltimateHueBattery', 'HUE Battery'],
['knxUltimateHueButton', 'HUE Button'],
['knxUltimateHueContactSensor', 'HUE Contact sensor'],
['knxUltimateHuedevice_software_update', 'HUE Device software update'],
['knxUltimateHueLightSensor', 'HUE Light sensor'],
['knxUltimateHueMotion', 'HUE Motion'],
['knxUltimateHueScene', 'HUE Scene'],
['knxUltimateHueTapDial', 'HUE Tapdial'],
['knxUltimateHueTemperatureSensor', 'HUE Temperature sensor'],
['knxUltimateHueZigbeeConnectivity', 'HUE Zigbee connectivity'],
// hue-config handled separately already
// Unknown in wiki -> fallback to inline
['knxUltimateGarageDoorBarrierOpener', null],
]);
function readFileSafe(p) { try { return fs.readFileSync(p, 'utf8'); } catch { return null; } }
function extractInlineHelp(html) {
const start = html.indexOf('<script type="text/markdown" data-help-name=');
if (start === -1) return { before: html, help: null, after: '' };
const end = html.indexOf('</script>', start);
if (end === -1) return { before: html, help: null, after: '' };
const before = html.slice(0, start);
const help = html.slice(start, end + '</script>'.length);
const after = html.slice(end + '</script>'.length);
return { before, help, after };
}
function stripHelpWrapper(helpBlock) {
const m = helpBlock.match(/<script[^>]*data-help-name=\"[^\"]+\"[^>]*>([\s\S]*?)<\/script>/);
return m ? m[1].trim() : null;
}
function extractWikiContent(md) {
if (!md) return null;
// Remove first language bar and optional NAV block, then keep from first --- separator onward
const lines = md.split(/\r?\n/);
let i = 0;
// language bar line
if (lines[i] && lines[i].startsWith('🌐 Language:')) i++;
// optional NAV block until '---'
while (i < lines.length && lines[i].trim() !== '---') i++;
if (i < lines.length && lines[i].trim() === '---') i++;
return lines.slice(i).join('\n').trim();
}
function writeLocaleHelp(destDir, helpName, content) {
if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
const out = `<script type="text/markdown" data-help-name="${helpName}">\n${content}\n</script>\n`;
fs.writeFileSync(path.join(destDir, `${helpName}.html`), out, 'utf8');
}
function migrateFile(f) {
const html = readFileSafe(f);
if (!html) return false;
const { before, help, after } = extractInlineHelp(html);
if (!help) return false; // no inline help
const helpNameMatch = help.match(/data-help-name=\"([^\"]+)\"/);
if (!helpNameMatch) return false;
const helpName = helpNameMatch[1];
const fallbackContent = stripHelpWrapper(help) || '';
const wikiTitle = HELP_TO_WIKI.get(helpName);
for (const lang of LANGS) {
let content = fallbackContent;
if (wikiTitle) {
const base = `${lang.prefix}${wikiTitle}.md`;
const p = path.join(WIKI_DIR, base);
const md = readFileSafe(p);
const extracted = extractWikiContent(md || '');
if (extracted && extracted.length > 0) content = extracted;
}
writeLocaleHelp(path.join(NODES_DIR, 'locales', lang.dir), helpName, content);
}
// remove inline help from node file
fs.writeFileSync(f, before + after, 'utf8');
return true;
}
function main() {
const files = fs.readdirSync(NODES_DIR).filter(n => n.endsWith('.html')).map(n => path.join(NODES_DIR, n));
let changed = 0;
for (const f of files) {
if (path.basename(f) === 'hue-config.html') continue; // already migrated
if (migrateFile(f)) changed++;
}
console.log(`Migrated ${changed} node help blocks to localized files.`);
}
main();