#!/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_sfw", file: "SFW (baked in NoN)/zh_cn.json"} ] const workFile = "zh_cn.json" type LanguageInstance = { suffix: string, file: string, data?: Record, overrideSuffix?: string, override?: LanguageInstance, ro?: boolean // read only, don't edit. } const mainLangFile = "SFW (baked in NoN)/en_us.json"; 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 (value) output.push([`${key}.${l.suffix}`, value]) } } fs.writeFileSync(workFile, stringify(output)) } function writeBackLang() { let mixed = parseOrdered(fs.readFileSync(workFile, "utf-8")); const buffer: Record = {} for (const key of Object.keys(targetLangFilesBySuffix)) buffer[key] = [] for (const [k, v] of mixed) { const [key, suffix] = k.split(/\.(?=[^.]*$)/); if (!buffer[suffix]) throw new Error(`can't parse the suffix: ${JSON.stringify(suffix)} from key: ${JSON.stringify(k)}`) buffer[suffix].push([key, v]) } for (let suffix in buffer) { if (targetLangFilesBySuffix[suffix].ro) continue fs.writeFileSync(targetLangFilesBySuffix[suffix].file, stringify(buffer[suffix])) } } ;(() => { 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) writeBackLang() else genMergedLang() })();