Files
triliumnext-korean-patch/tools/test-translation-upgrade.mjs
블리어 426a416e7b 버전 업데이트에 대비한 번역 비교 도구와 유지 절차 추가
새 원문과 이전 한국어를 키별로 비교해 추가와 변경 및 삭제를 구분한다. 배포 파일 변경 비교와 기준 해시 및 후속 작업 문서를 추가했다. 자동 검사 4개와 UI 문구 1496개 비교 및 기존 배포 파일 492개 무결성 검사를 통과했다. 운영 앱과 DB는 변경하지 않았으며 기존 배포 커밋 eddda22를 보존한다. 코드와 도움말 이식 및 새 버전 실행 검증은 대상 버전 작업 때 수행한다.
2026-09-20 20:30:00 +09:00

52 lines
2.9 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import { compare } from './translation-upgrade.mjs';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { spawnSync } from 'node:child_process';
import { fileURLToPath } from 'node:url';
test('추가와 변경 및 삭제를 구분하고 기존 번역을 검토 후보로 보존한다', () => {
const result = compare({ same: 'Hello', changed: 'Old', gone: 'Gone' }, { same: '안녕하세요', changed: '이전', gone: '삭제' }, { same: 'Hello', changed: 'New', added: 'Add' });
assert.deepEqual(result.map(x => x.status), ['reusable', 'source-changed', 'added', 'removed']);
assert.equal(result[1].korean, '이전');
});
test('자리표시자 누락과 미번역을 자동 재사용에서 제외한다', () => {
const en = { a: 'Hi {{name}}', b: 'Name', c: 'Value', d: 'Brand' };
assert.deepEqual(compare(en, { a: '안녕', b: '', d: 'Brand' }, en).map(x => x.status), ['placeholder-mismatch', 'missing', 'missing', 'review-identical']);
});
test('점이 포함된 키와 중첩 키 및 배열을 구분한다', () => {
const en = { 'a.b': 'One', a: { b: 'Two' }, list: ['Three'] };
const ko = { 'a.b': '하나', a: { b: '둘' }, list: ['셋'] };
assert.equal(compare(en, ko, en).filter(x => x.status === 'reusable').length, 3);
});
test('파일 비교는 변경과 삭제 및 추가를 구분하고 기존 보고서를 덮어쓰지 않는다', () => {
const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'trilium-translation-'));
try {
const old = path.join(temp, 'old'), next = path.join(temp, 'next');
fs.mkdirSync(old); fs.mkdirSync(next);
fs.writeFileSync(path.join(old, 'main.cjs'), 'old');
fs.writeFileSync(path.join(next, 'main.cjs'), 'next');
fs.mkdirSync(path.join(old, 'assets/db'), { recursive: true });
fs.writeFileSync(path.join(old, 'assets/db/demo.zip'), 'old-demo');
fs.mkdirSync(path.join(next, 'public/src'), { recursive: true });
fs.writeFileSync(path.join(next, 'public/src/ko.js'), 'next-ko');
const output = path.join(temp, 'report.json');
const tool = fileURLToPath(new URL('./translation-files.mjs', import.meta.url));
const run = () => spawnSync(process.execPath, [tool, old, next, output], { encoding: 'utf8' });
assert.equal(run().status, 0);
const saved = fs.readFileSync(output, 'utf8');
const entries = JSON.parse(saved).files;
assert.equal(entries.find(x => x.file === 'main.cjs').status, 'upstream-changed');
assert.equal(entries.find(x => x.file === 'assets/db/demo.zip').status, 'removed-or-moved');
assert.equal(entries.find(x => x.file === 'public/src/ko.js').status, 'new-upstream-path');
assert.notEqual(run().status, 0);
assert.equal(fs.readFileSync(output, 'utf8'), saved);
} finally {
// 이 검사에서 만든 임시 폴더만 정리한다. 사용자 자료 경로는 받지 않는다.
fs.rmSync(temp, { recursive: true, force: true });
}
});