/** * Baut scripts/ceb-patches/socialnetwork-patch.json für deepMerge in ceb/socialnetwork.json. * Benötigt: /tmp/vocab-patch-en.json (wird vom Aufrufer erzeugt) */ import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const root = path.resolve(__dirname, '..'); function readJson(p) { return JSON.parse(fs.readFileSync(p, 'utf8')); } const PHRASES = [ ['Vocabulary trainer', 'Trainer sa bokabularyo'], ['vocabulary', 'bokabularyo'], ['Vocabulary', 'Bokabularyo'], ['Chapter Test', 'Tsek sa kapitulo'], ['chapter test', 'tsek sa kapitulo'], ['Create ', 'Paghimo og '], ['Create', 'Paghimo'], ['Delete ', 'Tangtanga ang '], ['Delete', 'Tangtanga'], ['Save', 'I-save'], ['Cancel', 'Kanselahon'], ['Close', 'Isira'], ['Open ', 'Ablihi ang '], ['Open', 'Ablihi'], ['Search', 'Pangita'], ['Loading', 'Nagkarga'], ['Error', 'Sayop'], ['Success', 'Malampuson'], ['lesson', 'leksiyon'], ['Lesson', 'Leksiyon'], ['lessons', 'mga leksiyon'], ['Lessons', 'Mga leksiyon'], ['course', 'kurso'], ['Course', 'Kurso'], ['courses', 'mga kurso'], ['Courses', 'Mga kurso'], ['language', 'pinulongan'], ['Language', 'Pinulongan'], ['chapter', 'kapitulo'], ['Chapter', 'Kapitulo'], ['practice', 'praktis'], ['Practice', 'Praktis'], ['correct', 'tama'], ['Correct', 'Tama'], ['wrong', 'sayop'], ['Wrong', 'Sayop'], ['Next', 'Sunod'], ['Back', 'Balik'], ['Skip', 'Laktaw'], ['Check', 'Susihi'], ['Start ', 'Sugdi ang '], ['Start', 'Sugdi'], ['Stop ', 'Hunong ang '], ['Stop', 'Hunong'], ['Continue', 'Padayon'], ['Review', 'Balik-balik'], ['Title', 'Titulo'], ['Description', 'Deskripsiyon'], ['Optional', 'Opsyonal'], ['Invalid', 'Dili balido'], ['Subscribe', 'Mag-subscribe'], ['Share', 'Ipaambit'], ['Owner', 'Tag-iya'], ['Public', 'Publiko'], ['Difficulty', 'Kalisod'], ['Enrolled', 'Na-enroll'], ['Completed', 'Nahuman'], ['Grammar', 'Gramatika'], ['Culture', 'Kultura'], ['Conversation', 'Panag-istoryahanay'], ['Recording', 'Nagrekord'], ['minutes', 'ka minuto'], ['minute', 'minuto'], ['Mother tongue', 'Pinulongan nga inahan'], ['Learning language', 'Pinulongan nga tun-an'], ['Native language', 'Pinulongan nga lumad'], ['Target language', 'Pinulongan nga target'], ['learning', 'pagkat-on'], ['Learning', 'Pagkat-on'], ['explanation', 'pasabot'], ['Explanation', 'Pasabot'], ['assistant', 'katabang'], ['Assistant', 'Katabang'], ['message', 'mensahe'], ['Message', 'Mensahe'], ['Send ', 'Padal-a ang '], ['Send', 'Padala'], ['Could not', 'Dili ma'], ['No ', 'Walay '], ['Not ', 'Dili '], ['You ', 'Ikaw '], [' your ', ' imong '], ['Please ', 'Palihog '], ['really ', 'tinuod nga '], ['Really ', 'Tinuod nga '], ['the ', 'ang '], ['The ', 'Ang '], ['and ', 'ug '], [' or ', ' o '], ['with ', 'uban sa '], [' for ', ' para sa '], [' to ', ' aron '], [' in ', ' sa '], [' on ', ' sa '], [' at ', ' sa '], [' of ', ' sa '], [' from ', ' gikan sa '], [' this ', ' kini nga '], ['This ', 'Kini nga '], [' all ', ' tanan nga '], ['All ', 'Tanan nga '], [' first', ' una'], ['First ', 'Una '], [' after ', ' human sa '], [' before ', ' sa wala pa '], [' when ', ' kung '], [' have ', ' naay '], [' has ', ' naay '], ]; function translateUiString(s) { if (typeof s !== 'string') return s; let out = s; for (const [en, ceb] of PHRASES) { if (out.includes(en)) out = out.split(en).join(ceb); } return out; } function mapStringsDeep(node) { if (typeof node === 'string') return translateUiString(node); if (node === null || typeof node !== 'object' || Array.isArray(node)) return node; const out = {}; for (const k of Object.keys(node)) { out[k] = mapStringsDeep(node[k]); } return out; } const vocabEnPath = '/tmp/vocab-patch-en.json'; if (!fs.existsSync(vocabEnPath)) { console.error('Missing', vocabEnPath, '— run vocab key export first'); process.exit(1); } const vocabMapped = mapStringsDeep(readJson(vocabEnPath)); const profilePart = { values: { pubichair: { none: 'Wala', short: 'Mubo', medium: 'Tunga-tunga', long: 'Taas', hairy: 'Natural', waxed: 'Wax', landingstrip: 'Landing strip', other: 'Uban', bikinizone: 'Zona sa bikini lamang', }, eyecolor: { blue: 'Asul', green: 'Berde', brown: 'Brown', black: 'Itom', grey: 'Abohon', hazel: 'Hazel', amber: 'Amber', red: 'Pula', other: 'Uban', }, haircolor: { black: 'Itom', brown: 'Brown', blonde: 'Blonde', red: 'Pula', grey: 'Abohon', white: 'Puti', other: 'Uban', }, hairlength: { short: 'Mubo', medium: 'Tunga-tunga', long: 'Taas', bald: 'Kalbo', other: 'Uban', }, skincolor: { light: 'Klaro', medium: 'Tunga-tunga', dark: 'Itom', other: 'Uban', }, freckles: { much: 'Daghan', medium: 'Tunga-tunga', less: 'Ubos', none: 'Wala', }, }, pubichair: 'Buhok sa pribado', penislength: 'Taas sa penis', brasize: 'Sukod sa bra', piercings: 'Mga piercing', tattoos: 'Mga tattoo', eyecolor: 'Kolor sa mata', haircolor: 'Kolor sa buhok', hairlength: 'Taas sa buhok', freckles: 'Mga batik', skincolor: 'Kolor sa panit', }; const forumPart = { pagination: { first: 'Unang panid', previous: 'Miaging panid', next: 'Sunod nga panid', last: 'Kataposang panid', page: 'Panid <> sa <>', }, }; const eroticPart = { requestInfoTitle: 'Gipasa nga prueba', documentLabel: 'Dokumento sa beripikasyon', noteLabel: 'Mubo nga nota para sa moderation', settingsLink: 'Ablihi ang account settings', verificationHintTitle: 'Nota sa beripikasyon', verificationHintBody: 'Mahimo kang magpadala og hulagway. Kung dili klaro ang imong edad didto, ibalibaran ang hangyo ug kinahanglan nimo og ID.', notifications: { approved: 'Gi-aprub sa moderation ang imong pag-abli sa erotik nga lugar.', rejected: 'Gibalibaran ang imong hangyo sa erotik. Kung dili klaro ang edad sa hulagway, palihog ipadala ang ID.', }, noVideos: 'Wala pa kay na-upload nga erotik nga mga video.', intro: 'Na-abli na ang lugar. Ang mga module sa hulagway ug video mosunod sa sunod nga lakang.', enabledTitle: 'Na-abli na ang access', enabledBody: 'Ang imong account na-enable na sa erotik nga lugar. Ang hiwalay nga mga view sa hulagway ug video himoon pa.', roadmapTitle: 'Sunod', roadmapModeration: 'hiwalay nga agianan sa moderation ug reporting', roadmapUpload: 'dedikadong mga view sa upload ug pagdumala', roadmapSeparation: 'klaro nga pagbulag gikan sa normal nga galeriya', status: { none: { title: 'Wala pa ma-abli', body: 'Makita ang lugar, pero naka-lock pa hangtod sa pag-aprub sa moderator.', }, pending: { title: 'Naghuwat sa pagsusi', body: 'Ang imong hangyo naghuwat sa moderation.', }, approved: { title: 'Na-abli na', body: 'Na-abli na ang erotik nga lugar para sa imong account.', }, rejected: { title: 'Gibalibaran ang hangyo', body: 'Ang kataposang hangyo wala ma-aprub. Mahimo kang magpadala og bag-o.', }, }, }; const patch = { socialnetwork: { profile: profilePart, forum: forumPart, erotic: eroticPart, vocab: vocabMapped, }, }; const outPath = path.join(root, 'scripts', 'ceb-patches', 'socialnetwork-patch.json'); fs.mkdirSync(path.dirname(outPath), { recursive: true }); fs.writeFileSync(outPath, JSON.stringify(patch, null, 2) + '\n', 'utf8'); console.log('Wrote', outPath);