#!/usr/bin/env ts-node import fs from 'fs'; // a sample tool that merge (zh|en)(sfw|nsfw) ver together for edit faster // for other language translator: if you need to use this script, just edit `targetLangFiles` and `workFile`. const targetLangFiles: LanguageInstance[] = [ {suffix: "en_us_nsfw", file: "NSFW (Default Pack)/en_us.json", overrideSuffix: "en_us_sfw", ro: true}, {suffix: "en_us_sfw", file: "SFW (baked in NoN)/en_us.json", ro: true}, {suffix: "zh_cn_nsfw", file: "NSFW (Default Pack)/zh_cn.json", overrideSuffix: "zh_cn_sfw"}, {suffix: "zh_cn_nsfw_meme", file: "zh_cn_meme.json", overrideSuffix: "zh_cn_sfw"}, {suffix: "zh_cn_sfw", file: "SFW (baked in NoN)/zh_cn.json"} ] const workFile = "zh_cn.json" type LanguageInstance = { suffix: string, file: string, data?: Record, outputBuffer?: KVPair[]; overrideSuffix?: string, override?: LanguageInstance, ro?: boolean // read only, don't edit. } const mainLangFile = "SFW (baked in NoN)/en_us.json"; const KEEP_SAME_OVERRIDE_LINES = !(process.env.KEEP_SAME_OVERRIDE_LINES ?? "").match(/^(0|false)?$/i) if(KEEP_SAME_OVERRIDE_LINES) console.warn("enabled KEEP_SAME_OVERRIDE_LINES, same lines will not be removed") const targetLangFilesBySuffix: Record = {} for (let l of targetLangFiles) { if (!l.suffix.match(/^[a-z0-9-_]+$/i)) throw new Error(`bad Suffix: ${JSON.stringify(l.suffix)} that not match ^[a-z0-9-_]+$ (ignore case)`) targetLangFilesBySuffix[l.suffix] = l } for (let l of targetLangFiles) { if (l.overrideSuffix) l.override = targetLangFilesBySuffix[l.overrideSuffix] } type KVPair = [string, string]; function parseOrdered(src: string): KVPair[] { const o: KVPair[] = []; JSON.parse(src, (k, v) => { if (k === '') return v if (typeof k !== "string" || typeof v !== "string") throw new Error(`unexpected k/v:${JSON.stringify([k, v])}`) o.push([k, v]) return v; }); return o; } function stringify(data: KVPair[]): string { const s = JSON.stringify const body = data.map(([k, v]) => ` ${s(k)}: ${s(v)}`).join(",\n") return `{\n${body}\n}\n` } const keyOrder = parseOrdered(fs.readFileSync(mainLangFile, "utf-8")).map(([k, v]) => k) function genMergedLang(): void { for (const l of targetLangFiles) { l.data = JSON.parse(fs.readFileSync(l.file, "utf-8")) as Record } const output: KVPair[] = [] for (let key of keyOrder) { for (let l of targetLangFiles) { let value = l.data?.[key]; if (l.override?.data?.[key] === value) value = undefined if (typeof value === "undefined" && KEEP_SAME_OVERRIDE_LINES) value = l.override?.data?.[key] if (value) output.push([`${key}.${l.suffix}`, value]) } } fs.writeFileSync(workFile, stringify(output)) } function writeBackLang() { const mergedKeys: Record = JSON.parse(fs.readFileSync(workFile, "utf-8")); for (let l of targetLangFiles) { l.outputBuffer = [] } for (let key of keyOrder) { for (let l of targetLangFiles) { let s = mergedKeys[`${key}.${l.suffix}`] if (typeof s !== "string" && KEEP_SAME_OVERRIDE_LINES && l.override?.suffix) s = mergedKeys[`${key}.${l.override.suffix}`] if (typeof s === "string") l.outputBuffer?.push([key, s]) } } for (let l of targetLangFiles) { if (l.ro || !l.outputBuffer) continue fs.writeFileSync(l.file, stringify(l.outputBuffer)) } } ;(() => { let files = [targetLangFiles.map(l => l.file), workFile].flat() let latestFile = files.reduce<{ mtime: Date, fileName: string } | null>( (latest, file) => { if (!fs.existsSync(file)) return latest let stat = fs.statSync(file); if (!latest) return {mtime: stat.mtime, fileName: file}; return stat.mtime > latest.mtime ? {mtime: stat.mtime, fileName: file} : latest }, null); if (!latestFile) return if (latestFile.fileName === workFile) { console.log("write back to split versions") writeBackLang() } else { console.log("generate the merge version"); genMergedLang() } })();