Files

198 lines
14 KiB
Markdown

# TriliumNext Notes 한국어 패치 (번역 + main.cjs 패치)
최신 진행 상황: [2026-09-13 작업 기록](updates/2026-09-05/PROGRESS.md). 도움말 본문 173개와 제목 181개를 운영 서버에 반영했습니다. 전체 한글화는 추가 점검 중입니다.
## 2026-09-05 후속 작업
[최신 작업 상태와 파일](updates/2026-09-05/README.md) 및 [상세 변경 기록](updates/2026-09-05/CHANGELOG.ko.md)을 추가했습니다. 운영 서버에는 예제 노트 148개 수정과 편집기 한국어 사전 719개 문구 등을 반영했습니다. 2026-09-13에 기본 도움말 전체와 목록 제목을 서버에 반영했습니다. 전체 한글화는 진행 중입니다.
아래의 기존 설치 안내와 v1.0.0 다운로드는 이전 배포판에 대한 설명입니다. 이번 작업 폴더의 파일은 기존 설치 프로그램에 자동으로 포함되지 않습니다.
[TriliumNext Notes](https://github.com/TriliumNext/Notes)의 비공식 커뮤니티 한국어 번역입니다.
이 글을 쓰는 시점 기준으로 TriliumNext는 한국어 언어팩이 없고, 심지어 UI 언어 선택기에
뜨는 지원 언어 목록 자체가 `translations/` 폴더를 스캔해서 만들어지는 게 아니라 **컴파일된
서버 번들(`main.cjs`) 안에 하드코딩된 배열**이라서, 번역 파일만 올바른 경로에 넣는다고
"한국어"가 언어 선택기에 나타나지 않습니다. 그래서 번역 파일 외에 서버 번들을 패치하는
스크립트도 함께 제공합니다.
## 압축 파일로 받기
Git 없이 필요한 파일만 바로 받고 싶다면 압축된 배포판을 받으세요. 두 종류가 있습니다
([릴리스 페이지](https://gitea.itosm.co.kr/syskiller/triliumnext-korean-patch/releases/tag/v1.0.0)):
- **[triliumnext-korean-patch.zip 다운로드](https://gitea.itosm.co.kr/attachments/11f09ff6-4d85-4234-8360-a4ae968dd437)**
(2.5MB) — **처음 새로 설치하는 경우.** `Dockerfile`, `install.sh`, `docker-compose.yml`까지
전부 포함되어 있어서, 압축을 풀고 `./install.sh`를 실행하거나 `docker compose up -d --build`를
실행하면 한국어가 내장된 새 컨테이너가 만들어집니다.
- **[triliumnext-korean-patch-only.zip 다운로드](https://gitea.itosm.co.kr/attachments/679762e6-8b68-48e4-9954-82a2163750a8)**
(2.4MB) — **이미 Trilium을 운영 중인 경우.** 이미지를 새로 빌드하거나 컨테이너를 새로
만들지 않고, 기존 데이터/설정을 그대로 둔 채 파일 3개만 bind-mount로 추가합니다.
압축 안의 `README.md`에 기존 `docker-compose.yml`에 반영하는 방법이 자세히 적혀 있습니다.
## 포함된 파일
- `install.sh` — **원클릭 설치 스크립트**. 명령어 한 줄로 저장소를 내려받고, 한국어가
내장된 이미지를 빌드해서 바로 실행시킵니다.
- `Dockerfile` — `triliumnext/notes:latest` 위에 번역 파일과 패치된 `main.cjs`를
구워 넣어서, 별도 bind-mount 없이 한국어가 기본 내장된 이미지를 만듭니다.
- `docker-compose.yml` — 위 `Dockerfile`로 빌드해서 바로 띄우는 compose 파일
(`install.sh`가 내부적으로 이걸 사용합니다).
- `translation.json` — 클라이언트(브라우저) UI 문자열, 1,712개 키, 100% 번역 완료.
- `server.json` — 서버 문자열, 283개 키, 100% 번역 완료.
- `main.cjs` — **이미 패치가 적용된, 바로 쓸 수 있는 서버 번들** (`triliumnext/notes:latest`,
빌드일 2025-06-07, appVersion 0.95.0 기준).
- `patch_main_cjs.js` — 위 `main.cjs`를 만들어낸 패치 스크립트. 다른 버전의 이미지를 쓰거나
이미지가 업데이트된 경우, 이 스크립트를 새 원본 `main.cjs`에 다시 돌려서 직접 패치된
파일을 만들어야 합니다 (왜 이게 필요한지는 스크립트 상단 주석 참고).
- `docker-compose.bind-mount.yml.example` — 이미 떠 있는 공식 이미지 컨테이너에 파일만
bind-mount로 추가하고 싶을 때 쓰는 예시 (이미지를 새로 빌드하지 않는 방식).
`triliumnext/notes:latest` (빌드일 2025-06-07, appVersion 0.95.0) 기준으로 테스트했습니다.
`main.cjs` 안의 변수명은 전부 난독화(minify)되어 있고 **빌드마다 이름이 바뀔 수 있습니다** —
`patch_main_cjs.js`를 새 이미지에 돌렸을 때 `[skip]`이 출력되면, 스크립트가 찾는 문자열
패턴이 그 빌드에서 바뀐 것이니 새 빌드에서 같은 패턴을 다시 찾아 스크립트를 갱신해야 합니다.
## 설치 방법 — 명령어 한 줄 (추천)
Docker와 Docker Compose 플러그인만 설치되어 있으면 됩니다:
```bash
curl -fsSL https://gitea.itosm.co.kr/syskiller/triliumnext-korean-patch/raw/branch/main/install.sh | bash
```
기본적으로 `./trilium-korean` 폴더에 저장소를 내려받고, 한국어가 내장된 이미지를 빌드해서
`http://localhost:8082`로 띄웁니다. 포트를 바꾸고 싶으면:
```bash
TRILIUM_KO_PORT=9000 curl -fsSL https://gitea.itosm.co.kr/syskiller/triliumnext-korean-patch/raw/branch/main/install.sh | bash
```
설치가 끝나면 브라우저로 접속해서 초기 비밀번호를 설정한 뒤, **옵션 → 언어 및 지역**에서
"한국어"를 선택하고 페이지를 새로고침하면 됩니다 (본문 텍스트까지 전부 한국어로 바뀌려면
새로고침이 한 번 필요합니다 — 앱 자체의 동작이며 이 패치의 문제는 아닙니다).
업데이트하려면 같은 명령어를 같은 폴더에서 다시 실행하면 됩니다.
## 설치 방법 — 이미 떠 있는 컨테이너에 추가하고 싶은 경우
이미지를 새로 빌드하지 않고, 이미 쓰고 있는 공식 `triliumnext/notes` 컨테이너에 파일만
얹고 싶다면:
1. **번역 파일 + `main.cjs`를 `docker-compose.yml`에 bind-mount로 등록**
(`docker cp`로만 넣지 말 것 — 아래 "문제 4" 참고):
- `main.cjs` → `/usr/src/app/main.cjs`
- `translation.json` → `/usr/src/app/public/translations/ko/translation.json`
- `server.json` → `/usr/src/app/assets/translations/ko/server.json`
2. `docker-compose.bind-mount.yml.example`을 참고해서 그대로 적용, 컨테이너 재시작.
3. 앱 안에서 **옵션 → 언어 및 지역**에서 "한국어" 선택 후 새로고침.
## 설치 방법 — 다른 이미지 버전을 쓰는 경우 (직접 패치)
이미지 버전이 다르면 `main.cjs`의 난독화된 변수명/위치가 달라 이 저장소의 `main.cjs`가
그대로 안 맞을 수 있습니다. 이 경우 직접 패치해야 합니다:
1. 번역 파일은 위와 동일하게 bind-mount.
2. **컨테이너의 원본(패치 안 된) `main.cjs`를 추출**하고 패치 스크립트 실행:
```bash
docker create --name trilium-tmp triliumnext/notes:latest
docker cp trilium-tmp:/usr/src/app/main.cjs ./main.cjs
docker rm trilium-tmp
node patch_main_cjs.js ./main.cjs
node --check ./main.cjs # 반드시 배포 전에 문법 검사
```
`[skip]`이 출력되면 스크립트가 찾는 문자열 패턴이 그 빌드에서 바뀐 것이니, 새 빌드에서
같은 패턴을 다시 찾아 스크립트를 갱신해야 합니다 (아래 "빌드마다 달라짐" 참고).
3. **패치된 `main.cjs`를 `docker-compose.yml`에서 원본 위치에 bind-mount** —
`docker-compose.bind-mount.yml.example` 참고:
```yaml
services:
trilium:
image: triliumnext/notes:latest
restart: unless-stopped
ports:
- '127.0.0.1:18082:8080'
environment:
- TZ=Asia/Seoul
volumes:
- ./data:/home/node/trilium-data
- ./main.cjs:/usr/src/app/main.cjs:ro
- ./translation.json:/usr/src/app/public/translations/ko/translation.json:ro
- ./server.json:/usr/src/app/assets/translations/ko/server.json:ro
```
4. 컨테이너 시작 후 앱 안에서 **옵션 → 언어 및 지역**에서 "한국어" 선택.
## 겪었던 문제와 해결 (설치 전에 꼭 읽어보세요)
### 문제 1 — DB에서 `locale`을 직접 `'ko'`로 바꾸면 크래시
지원 언어 목록에 없는 값을 옵션 DB에 직접 넣으면 앱이 시작하다가 죽습니다. 이 방법으로는
안 되고, 반드시 아래처럼 서버 번들 자체를 패치해야 합니다.
### 문제 2 — `main.cjs` 패치 위치를 잘못 잡으면 문법 자체가 깨짐
지원 언어 배열(테스트한 빌드에서 변수명 `K5i`)에 새 항목을 삽입할 때, 배열의 여는 대괄호
`[` **바로 뒤**가 아니라 그 앞(변수 선언문 쪽)에 잘못 삽입하면 JS 문법 자체가 깨져서 앱이
아예 뜨지 못하고 크래시를 반복합니다. `patch_main_cjs.js`는 이 위치를 정확히 계산해서
삽입하지만, **패치 후에는 항상 `node --check`로 문법을 먼저 확인**하고 나서 컨테이너를
재시작하세요.
### 문제 3 — 완전 재생성(`docker compose down && up`) 시에만 나타나는 크래시
지원 언어 배열만 고치면 `docker restart`로는 잘 동작하는 것처럼 보이지만, 컨테이너를 완전히
내렸다 올리면(`down && up`) 다시 크래시합니다. 원인은 Trilium 자체 번역과는 별개로,
**CKEditor 내장 다국어 리소스를 지연 로드하는 두 번째 하드코딩 맵**(테스트한 빌드에서
변수명 `IMi`)에도 `ko` 항목이 없어서 발생하는 `TypeError`입니다. 이 리소스는 애초에
한국어용 청크가 빌드에 포함되어 있지 않아 새로 만들 수 없으므로, `patch_main_cjs.js`는
이 항목을 영어 로더로 대체(alias)해서 우회합니다. **`restart`뿐 아니라 완전 재생성까지
반드시 테스트**하세요 — 재시작만으로는 이 문제가 드러나지 않습니다.
### 문제 4 — 번역이 배포 후 시간이 지나서 "모바일에서만" 다시 영어로 보임
가장 까다로웠던 문제입니다. 번역을 배포하고 정상 동작까지 확인했는데, 이후 **모바일
기기에서만** 옵션 페이지 등의 본문 텍스트가 다시 영어로 나오는 현상이 발생했습니다
(페이지 제목이나 "한국어"라는 언어 이름 자체는 정상). 데스크톱에서는 동일 페이지가
100% 정상이었습니다.
처음엔 모바일 브라우저 캐시 문제로 의심했지만, 캐시를 초기화하고 서로 다른 브라우저
엔진(Chrome, 삼성인터넷, 네이버) 세 개로 테스트해도 완전히 동일한 증상이 재현되어
캐시 이론은 기각했습니다.
**진짜 원인**: 번역 파일(`translation.json`, `server.json`)을 `docker cp`로 컨테이너
내부에 직접 복사만 하고 `docker-compose.yml`에는 bind-mount로 등록하지 않았던 것이
원인이었습니다. `docker cp`로 넣은 파일은 컨테이너의 쓰기 가능 레이어에만 존재하기 때문에,
이후 `main.cjs` 패치가 완전 재생성에도 살아남는지 테스트하려고 `docker compose down && up`을
실행했을 때 번역 파일 두 개가 컨테이너와 함께 통째로 사라졌습니다 (bind-mount 되어 있던
`main.cjs`만 살아남음). 서버가 `translations/ko/*.json` 요청에 404를 반환하기 시작했고,
i18next의 `fallbackLng:"en"` 설정 때문에 본문 텍스트가 조용히 영어로 대체됐습니다.
"한국어"라는 언어 이름만 정상이었던 이유는, 그 값이 이 JSON 파일이 아니라 별도의 DB 기반
API(`options/locales`)에서 오기 때문에 영향을 받지 않았던 것입니다.
데스크톱이 여전히 정상으로 보였던 이유는 단순히 파일이 사라지기 전에 브라우저가 이미
받아둔 번역 응답을 캐시하고 있었기 때문입니다 — 즉 데스크톱 쪽이 오히려 "낡은 캐시를
보여주던 쪽"이었고, 매번 새로 서버에 요청하는 모바일 쪽이 서버의 실제(망가진) 상태를
정확히 반영하고 있었던 것입니다. 세 개의 다른 모바일 브라우저에서 전부 동일한 증상이
나온 것도 이걸로 설명됩니다 — 캐시 종류와 무관하게 서버에 파일 자체가 없었으니까요.
**교훈**: `docker cp`로 컨테이너 안에 넣은 파일은 컨테이너가 사라지면 함께 사라집니다.
번역 파일도 `main.cjs`와 마찬가지로 **반드시 `docker-compose.yml`의 `volumes:`에
bind-mount로 선언**하세요 (위 설치 방법 3번, `docker-compose.yml.example` 참고). 그리고
증상이 "특정 기기에서만 재현됨", "캐시를 지워도 재현됨"처럼 보이더라도, 실제 원인은
클라이언트가 아니라 서버 쪽 데이터 유실일 수 있으므로 클라이언트 가설을 세우기 전에
서버가 실제로 무엇을 응답하는지(`curl`로 정확한 URL 직접 확인)부터 검증하는 게 우선입니다.
## 이전 배포판의 미해결 항목 — CKEditor 자체 툴바
2026-09-05 후속 패치에서는 한국어 사전 719개를 적용하고 운영 화면을 확인했습니다. 다음 문단은 이전 배포판의 기록입니다.
CKEditor5 자체의 UI 문자열(툴바 버튼 이름 — "Paragraph", "Heading 2", "Bold" 등)은
이 프로젝트가 건드리는 번역 시스템과 완전히 별개인 `window.CKEDITOR_TRANSLATIONS`라는
자체 시스템에서 옵니다. 테스트한 빌드 기준으로, 독일어·프랑스어·스페인어·중국어를
포함해 이미 "지원"되는 언어 **어느 것도** 실제 CKEditor 사전을 갖고 있지 않아서 전부
영어 툴바로 나옵니다 — 한국어만의 문제가 아니라 업스트림 빌드 자체에 이미 있던 공백입니다.
## 라이선스
TriliumNext Notes 본체와 동일한 라이선스를 따릅니다. 무보증 — 이 프로젝트는 컴파일된
바이너리를 난독화된 변수명 문자열 매칭 방식으로 패치하는 것이라, 버전이 올라가면
깨지기 쉬운 구조입니다.