#!/usr/bin/env node /* * Embeds the console page's per-language strings in the helper: every * /.json (client/dist-console/strings/, written by * `npm run build:console`) gzip'd at level 9 (no name, mtime 0, so the output * is reproducible) into one C file with the table webui_strings.h declares: * { "", , }, sorted by language. * payload/Makefile runs it after the page build; the helper serves each entry * at GET /strings/.json (webui_api.c). * * Usage: node scripts/embed-console-strings.mjs */ import fs from "node:fs"; import path from "node:path"; import { fileURLToPath } from "node:url"; import { gzipSync } from "node:zlib"; const LANG_RE = /^[a-z]{2}(-[A-Z]{2})?$/; /** The C source for { lang: json text }. */ export function stringsTableC(files) { const langs = Object.keys(files).sort(); if (langs.length === 0) throw new Error("embed-console-strings: no strings files"); const out = [ "/* Generated by scripts/embed-console-strings.mjs from client/dist-console/strings: do not edit. */", '#include "webui_strings.h"', "", ]; langs.forEach((lang, i) => { if (!LANG_RE.test(lang)) throw new Error(`embed-console-strings: "${lang}" is not or -`); const gz = gzipSync(Buffer.from(files[lang], "utf8"), { level: 9 }); const rows = []; for (let at = 0; at < gz.length; at += 16) { rows.push(` ${Array.from(gz.subarray(at, at + 16), (b) => `0x${b.toString(16).padStart(2, "0")}`).join(", ")},`); } out.push(`static const unsigned char s_${i}[] = { /* ${lang}: ${gz.length} bytes */`, ...rows, "};"); }); out.push("", "const webui_strings_entry_t webui_strings_table[] = {"); langs.forEach((lang, i) => out.push(` { "${lang}", s_${i}, sizeof s_${i} },`)); out.push("};", "const size_t webui_strings_count = sizeof webui_strings_table / sizeof webui_strings_table[0];", ""); return out.join("\n"); } function main() { const [dir, outPath] = process.argv.slice(2); if (!dir || !outPath) { console.error("usage: node scripts/embed-console-strings.mjs "); process.exit(2); } const files = {}; for (const f of fs.readdirSync(dir).filter((n) => n.endsWith(".json"))) { files[f.slice(0, -".json".length)] = fs.readFileSync(path.join(dir, f), "utf8"); } const c = stringsTableC(files); fs.writeFileSync(`${outPath}.tmp`, c); fs.renameSync(`${outPath}.tmp`, outPath); console.log(`console strings embedded: ${Object.keys(files).length} languages`); } if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) main();