mirror of
https://github.com/phantomptr/ps5upload.git
synced 2026-10-19 02:20:02 -05:00
The page embedded all 21 languages' cw_* strings (174 KiB of the 220 KiB gzip budget). Now it embeds English only; every other language is a separate build artifact (dist-console/strings/<lang>.json) gzip'd into the helper and served at GET /strings/<lang>.json (Host/Origin checked, no token, immutable year-long cache; the page asks with ?v=<hash of the strings>). The page shows English until the chosen language arrives, falls back to English per key, and stays in English (logged once) when a load fails. Page: 607.1 KiB raw / 174.4 KiB gzip -> 357.5 KiB raw / 112.5 KiB gzip. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RxCGb8Asp1A1AQYiv1kbgS
61 lines
2.6 KiB
JavaScript
61 lines
2.6 KiB
JavaScript
#!/usr/bin/env node
|
|
/*
|
|
* Embeds the console page's per-language strings in the helper: every
|
|
* <dir>/<lang>.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:
|
|
* { "<lang>", <gzip bytes>, <length> }, sorted by language.
|
|
* payload/Makefile runs it after the page build; the helper serves each entry
|
|
* at GET /strings/<lang>.json (webui_api.c).
|
|
*
|
|
* Usage: node scripts/embed-console-strings.mjs <strings dir> <out.c>
|
|
*/
|
|
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 <ll> or <ll>-<RR>`);
|
|
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 <strings dir> <out.c>");
|
|
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();
|