/** * 방문자에게 보이는 한국어 본문을 존댓말로 바꾼다. * * 제목(h1·h2·name·rule·caught)은 건드리지 않는다 — 단정문이 카피로서 힘을 갖는 자리다. * 바꾸는 것은 **설명하는 문장**과 **명령형**이다. * 방문자에게 "~해라" 라고 말하는 화면은 무례하다. */ import fs from "node:fs"; const FILE = "src/i18n/content.ts"; /** 이 키의 값만 바꾼다. 나머지는 그대로 둔다 */ const TARGET_KEYS = new Set([ "lead", "note", "how", "problem", "use", "what", "does", "becomes", "made", "alt", "sample", "why", "fixed", "caught", "caveat", "installNote", "description", "verdict", "caption", ]); /** 순서가 중요하다. 긴 패턴을 먼저 잡지 않으면 짧은 것이 먼저 먹는다 */ const RULES = [ // ── 명령형 — 방문자에게 명령하지 않는다 ── [/해라\./g, "하세요."], [/해라$/g, "하세요"], [/봐라\./g, "보세요."], [/봐라$/g, "보세요"], [/마라\./g, "마세요."], [/마라$/g, "마세요"], [/써라\./g, "쓰세요."], [/써라$/g, "쓰세요"], [/가라\./g, "가세요."], [/골라라/g, "고르세요"], // ── 서술 ── [/하지 않는다/g, "하지 않습니다"], [/되지 않는다/g, "되지 않습니다"], [/지 않는다/g, "지 않습니다"], [/않는다/g, "않습니다"], [/것이 아니다/g, "것이 아닙니다"], [/아니다/g, "아닙니다"], [/것이다/g, "것입니다"], [/뿐이다/g, "뿐입니다"], [/때문이다/g, "때문입니다"], [/없어진다/g, "없어집니다"], [/사라진다/g, "사라집니다"], [/달라진다/g, "달라집니다"], [/남는다/g, "남습니다"], [/걸린다/g, "걸립니다"], [/나온다/g, "나옵니다"], [/들어간다/g, "들어갑니다"], [/올라간다/g, "올라갑니다"], [/떨어진다/g, "떨어집니다"], [/무너진다/g, "무너집니다"], [/바뀐다/g, "바뀝니다"], [/이어진다/g, "이어집니다"], [/생긴다/g, "생깁니다"], [/보인다/g, "보입니다"], [/읽힌다/g, "읽힙니다"], [/잡힌다/g, "잡힙니다"], [/쓰인다/g, "쓰입니다"], [/맡긴다/g, "맡깁니다"], [/만든다/g, "만듭니다"], [/막는다/g, "막습니다"], [/줄인다/g, "줄입니다"], [/센다/g, "셉니다"], [/짠다/g, "짭니다"], [/뺀다/g, "뺍니다"], [/둔다/g, "둡니다"], [/한다/g, "합니다"], [/된다/g, "됩니다"], [/있다/g, "있습니다"], [/없다/g, "없습니다"], [/같다/g, "같습니다"], [/좁다/g, "좁습니다"], [/넓다/g, "넓습니다"], [/맞다/g, "맞습니다"], [/낫다/g, "낫습니다"], [/멈춘다/g, "멈춥니다"], [/이긴다/g, "이깁니다"], [/모른다/g, "모릅니다"], [/받는다/g, "받습니다"], [/걸었다/g, "걸었습니다"], [/바꿨다/g, "바꿨습니다"], [/했다/g, "했습니다"], [/였다/g, "였습니다"], [/었다/g, "었습니다"], [/았다/g, "았습니다"], [/린다/g, "립니다"], [/난다/g, "납니다"], [/쓴다/g, "씁니다"], [/본다/g, "봅니다"], [/간다/g, "갑니다"], [/온다/g, "옵니다"], [/골라준다/g, "골라줍니다"], [/고른다/g, "고릅니다"], [/넘긴다/g, "넘깁니다"], [/채운다/g, "채웁니다"], [/압축한다/g, "압축합니다"], [/판정한다/g, "판정합니다"], [/정한다/g, "정합니다"], [/확정한다/g, "확정합니다"], [/구분한다/g, "구분합니다"], [/합성한다/g, "합성합니다"], [/내린다/g, "내립니다"], [/열린다/g, "열립니다"], [/붙는다/g, "붙습니다"], [/넣는다/g, "넣습니다"], [/놓는다/g, "놓습니다"], [/찾는다/g, "찾습니다"], [/맞춘다/g, "맞춥니다"], [/갖춘다/g, "갖춥니다"], [/낮춘다/g, "낮춥니다"], [/높인다/g, "높입니다"], [/모은다/g, "모읍니다"], [/버린다/g, "버립니다"], [/살린다/g, "살립니다"], [/시킨다/g, "시킵니다"], [/지킨다/g, "지킵니다"], [/적는다/g, "적습니다"], [/삼는다/g, "삼습니다"], [/남긴다/g, "남깁니다"], [/옮긴다/g, "옮깁니다"], [/뒤집는다/g, "뒤집습니다"], [/따른다/g, "따릅니다"], [/부른다/g, "부릅니다"], [/누른다/g, "누릅니다"], [/자른다/g, "자릅니다"], [/오른다/g, "오릅니다"], [/미룬다/g, "미룹니다"], [/켠다/g, "켭니다"], [/편다/g, "폅니다"], [/센다/g, "셉니다"], [/건다/g, "겁니다"], [/푼다/g, "풉니다"], [/꾼다/g, "꿉니다"], [/띈다/g, "띕니다"], [/진다/g, "집니다"], [/킨다/g, "킵니다"], [/힌다/g, "힙니다"], [/빈다/g, "빕니다"], [/친다/g, "칩니다"], [/잘라낸다/g, "잘라냅니다"], [/잘린다/g, "잘립니다"], [/뭉개진다/g, "뭉개집니다"], [/건너뛴다/g, "건너뜁니다"], [/깎는다/g, "깎습니다"], [/죽는다/g, "죽습니다"], [/잰다/g, "잽니다"], [/낸다/g, "냅니다"], [/긴다/g, "깁니다"], [/없앴다/g, "없앴습니다"], [/걷어냈다/g, "걷어냈습니다"], [/남겼다/g, "남겼습니다"], [/뿌렸다/g, "뿌렸습니다"], [/넘쳤다/g, "넘쳤습니다"], [/늘렸다/g, "늘렸습니다"], [/신호다/g, "신호입니다"], [/결과다/g, "결과입니다"], [/길다/g, "깁니다"], [/그대로였다/g, "그대로였습니다"], [/보였다/g, "보였습니다"], [/튀고 있었다/g, "튀고 있었습니다"], [/어긋나 있었다/g, "어긋나 있었습니다"], [/적었는데/g, "적었는데"], ]; function polite(text) { let out = text; for (const [re, to] of RULES) out = out.replace(re, to); return out; } const src = fs.readFileSync(FILE, "utf8"); // STAGES_KO 는 `export const ko` 밖에 따로 선언돼 있다. 범위를 거기서 시작하지 않으면 // 파이프라인 여섯 단계의 설명이 통째로 빠진다 — 실측에서 37개가 반말로 남아 있었다. const koStart = src.indexOf("const STAGES_KO"); const koEnd = src.indexOf("const STAGES_EN"); const koStart2 = src.indexOf("export const ko"); const koEnd2 = src.indexOf("export const en"); let ko = src.slice(koStart, koEnd); let ko2 = src.slice(koStart2, koEnd2); let changed = 0; // `key: "..."` 와 `key:\n "..."` 를 모두 잡는다 ko = ko.replace(/(\b[a-zA-Z]+):(\s*)"((?:[^"\\]|\\.)*)"/g, (m, key, gap, val) => { if (!TARGET_KEYS.has(key)) return m; const next = polite(val); if (next !== val) changed++; return `${key}:${gap}"${next}"`; }); fs.writeFileSync(FILE, src.slice(0, koStart) + ko + src.slice(koEnd), "utf8"); console.log(`존댓말 변환: ${changed}개 문자열`);