한국어 배포판 2.0.0 통합과 신규 설치 및 업데이트 복구 검증

This commit is contained in:
Codex
2026-09-13 18:56:00 +09:00
parent 46b8dc6717
commit eddda22eb6
526 changed files with 27479 additions and 218 deletions
+58 -168
View File
@@ -1,197 +1,87 @@
# TriliumNext Notes 한국어 패치 (번역 + main.cjs 패치)
# Trilium 이스톰 한국어판 2.0.0
최신 진행 상황: [2026-09-13 작업 기록](updates/2026-09-05/PROGRESS.md). 도움말 본문 173개와 제목 181개를 운영 서버에 반영했습니다. 전체 한글화는 추가 점검 중입니다.
Trilium 0.95.0용 한국어 배포판입니다. UI와 편집기 및 도움말과 API 참고 문서를 포함합니다. 새 문서에는 한국어 기본 예제와 한국어 PDF가 들어갑니다. 이미지 원본은 유지하고 한국어 설명을 제공합니다.
## 2026-09-05 후속 작업
Dockerfile과 설치 스크립트가 최신 배포 파일을 사용하도록 통합했습니다. `latest` 대신 검증한 이미지 다이제스트를 고정합니다. 다른 Trilium 버전에 이 서버 번들을 덮어쓰지 마세요.
[최신 작업 상태와 파일](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 플러그인만 설치되어 있으면 됩니다:
Linux 서버의 Docker Engine과 Docker Compose 플러그인이 필요합니다. Compose는 `up --wait`를 지원해야 합니다. 저장소를 내려받을 때는 Git도 필요합니다. Docker 명령을 실행할 권한이 있는 계정으로 진행하세요.
```bash
curl -fsSL https://gitea.itosm.co.kr/syskiller/triliumnext-korean-patch/raw/branch/main/install.sh | bash
git clone https://gitea.itosm.co.kr/syskiller/triliumnext-korean-patch.git
cd triliumnext-korean-patch
cp .env.example .env
bash install.sh
```
기본적으로 `./trilium-korean` 폴더에 저장소를 내려받고, 한국어가 내장된 이미지를 빌드해서
`http://localhost:8082`로 띄웁니다. 포트를 바꾸고 싶으면:
기본 주소는 `http://127.0.0.1:8082`입니다. 서버에 리버스 프록시가 있다면 이 주소로 연결하세요. 직접 외부 접속을 허용하려면 `.env`의 `TRILIUM_KO_BIND`를 서버의 수신 주소로 변경하세요. 모든 인터페이스를 사용할 값은 `0.0.0.0`입니다. 포트는 `TRILIUM_KO_PORT`에서 바꿉니다.
브라우저에서 새 문서를 만들고 비밀번호를 설정하세요. 언어 및 지역 설정에서 한국어를 선택하고 새로 고칩니다. 기존 계정의 언어 설정은 업데이트 때 유지합니다.
Docker 이미지는 설치 중 로컬에서 빌드합니다. 이 저장소는 공개 컨테이너 레지스트리에 이미지를 올렸다고 가정하지 않습니다. 최초 빌드에는 고정된 기반 이미지 다운로드가 필요할 수 있습니다.
## 업데이트
현재 설치 폴더에서 실행합니다.
```bash
TRILIUM_KO_PORT=9000 curl -fsSL https://gitea.itosm.co.kr/syskiller/triliumnext-korean-patch/raw/branch/main/install.sh | bash
git pull --ff-only
bash install.sh
```
설치가 끝나면 브라우저로 접속해서 초기 비밀번호를 설정한 뒤, **옵션 → 언어 및 지역**에서
"한국어"를 선택하고 페이지를 새로고침하면 됩니다 (본문 텍스트까지 전부 한국어로 바뀌려면
새로고침이 한 번 필요합니다 — 앱 자체의 동작이며 이 패치의 문제는 아닙니다).
스크립트는 새 이미지를 먼저 빌드합니다. 이후 이 Compose 프로젝트의 Trilium을 중지하고 데이터 전체를 `backups/날짜-번호/data.tar.gz`로 백업합니다. 새 컨테이너의 상태 검사를 통과해야 배포 성공으로 표시합니다. 기동 실패 시 이전 이미지로 복귀를 시도하며 백업은 보존합니다. 데이터베이스는 실패 시 자동으로 덮어쓰지 않습니다.
업데이트하려면 같은 명령어를 같은 폴더에서 다시 실행하면 됩니다.
새 설치용 예제 압축 파일을 바꿔도 기존 노트는 다시 가져오거나 덮어쓰지 않습니다. 기존 영어 예제나 사용자가 수정한 노트의 본문을 이 설치 스크립트가 임의로 번역하지 않습니다. 이스톰 운영 서버의 기존 노트 번역 기록은 `updates/2026-09-05`에 별도로 남아 있습니다.
## 설치 방법 — 이미 떠 있는 컨테이너에 추가하고 싶은 경우
## 기존 다른 컨테이너에서 이전
이미지를 새로 빌드하지 않고, 이미 쓰고 있는 공식 `triliumnext/notes` 컨테이너에 파일만
얹고 싶다면:
이 배포판은 Trilium 0.95.0과 같은 데이터 형식으로 검사했습니다. 더 최신 버전에서 쓰던 DB를 이전 버전으로 되돌리는 용도로 사용하지 마세요.
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. 앱 안에서 **옵션 → 언어 및 지역**에서 "한국어" 선택 후 새로고침.
1. 기존 Trilium을 중지하고 데이터 폴더 전체를 백업합니다.
2. 기존 데이터를 별도 복사한 경로를 `.env`의 `TRILIUM_KO_DATA_DIR`로 지정합니다.
3. 다른 포트로 이 배포판을 설치해 노트와 첨부 파일을 확인합니다.
4. 확인 후 리버스 프록시의 연결 대상을 변경합니다.
## 설치 방법 — 다른 이미지 버전을 쓰는 경우 (직접 패치)
하나의 데이터 폴더를 두 컨테이너에서 동시에 열지 마세요. 설치 스크립트는 같은 데이터 경로를 사용 중인 다른 컨테이너가 있으면 중단합니다. 기존 컨테이너의 bind mount 패치 설정은 새 컨테이너에 추가하지 않습니다. 모든 패치는 이미지 안에 포함돼 있습니다.
이미지 버전이 다르면 `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. 컨테이너 시작 후 앱 안에서 **옵션 → 언어 및 지역**에서 "한국어" 선택.
복원 전 현재 컨테이너를 중지하세요. 백업을 새 빈 데이터 폴더에 풀고 `.env`의 데이터 경로를 그 폴더로 바꾸는 방식을 권장합니다. 원래 폴더는 확인이 끝날 때까지 보존하세요. 백업 파일은 컨테이너의 root 권한으로 생성돼 `sudo`가 필요할 수 있습니다.
## 겪었던 문제와 해결 (설치 전에 꼭 읽어보세요)
```bash
docker compose stop trilium
sudo mkdir /srv/trilium-restored
sudo tar -xzpf backups/복원할-백업/data.tar.gz -C /srv/trilium-restored
# .env의 TRILIUM_KO_DATA_DIR을 /srv/trilium-restored로 수정한 뒤 실행
bash install.sh
```
### 문제 1 — DB에서 `locale`을 직접 `'ko'`로 바꾸면 크래시
이전 이미지의 복구용 태그는 `previous-image.txt`에 있으며 원래 ID는 `previous-image-id.txt`에 있습니다. 이미지 복귀만으로 DB 형식이 되돌아가지는 않으므로 다른 버전 사이의 복원에서는 해당 버전의 데이터 백업을 함께 사용하세요.
지원 언어 목록에 없는 값을 옵션 DB에 직접 넣으면 앱이 시작하다가 죽습니다. 이 방법으로는
안 되고, 반드시 아래처럼 서버 번들 자체를 패치해야 합니다.
## 포함 범위
### 문제 2 — `main.cjs` 패치 위치를 잘못 잡으면 문법 자체가 깨짐
| 항목 | 내용 |
|---|---|
| 기반 앱 | Trilium 0.95.0 |
| 기반 이미지 | `triliumnext/notes@sha256:611a430016585d35b170eb9a0fa300ce76318f04a8ec0067549c4c52561b0c36` |
| UI | 한국어 사전과 편집기 및 지도·달력·마인드맵 수정 |
| 도움말 | 본문 173개와 제목 181개 |
| 이미지 설명 | 영문이 감지된 이미지 206개에 한국어 설명 |
| API 참고 화면 | 5개와 Swagger 정적 파일 |
| 신규 기본 예제 | 노트 170개 대응 및 번역 수정 148개와 한국어 PDF |
| 배포 파일 | `release/manifest.json`의 492개 파일 |
지원 언어 배열(테스트한 빌드에서 변수명 `K5i`)에 새 항목을 삽입할 때, 배열의 여는 대괄호
`[` **바로 뒤**가 아니라 그 앞(변수 선언문 쪽)에 잘못 삽입하면 JS 문법 자체가 깨져서 앱이
아예 뜨지 못하고 크래시를 반복합니다. `patch_main_cjs.js`는 이 위치를 정확히 계산해서
삽입하지만, **패치 후에는 항상 `node --check`로 문법을 먼저 확인**하고 나서 컨테이너를
재시작하세요.
함수 이름과 코드 문법 및 URL과 제품 이름은 원문을 유지합니다. 연결된 외부 사이트 전체를 번역한 것은 아닙니다. 외부 스크립트 API 사본은 운영 버전과 지원 범위가 다를 수 있음을 문서에 표시했습니다.
### 문제 3 — 완전 재생성(`docker compose down && up`) 시에만 나타나는 크래시
## 검증과 재생성
지원 언어 배열만 고치면 `docker restart`로는 잘 동작하는 것처럼 보이지만, 컨테이너를 완전히
내렸다 올리면(`down && up`) 다시 크래시합니다. 원인은 Trilium 자체 번역과는 별개로,
**CKEditor 내장 다국어 리소스를 지연 로드하는 두 번째 하드코딩 맵**(테스트한 빌드에서
변수명 `IMi`)에도 `ko` 항목이 없어서 발생하는 `TypeError`입니다. 이 리소스는 애초에
한국어용 청크가 빌드에 포함되어 있지 않아 새로 만들 수 없으므로, `patch_main_cjs.js`는
이 항목을 영어 로더로 대체(alias)해서 우회합니다. **`restart`뿐 아니라 완전 재생성까지
반드시 테스트**하세요 — 재시작만으로는 이 문제가 드러나지 않습니다.
검증 결과는 [배포 검증 기록](docs/DEPLOYMENT-TESTS.ko.md)에 있습니다. 배포 파일은 Docker 빌드 중 SHA-256 검사와 JavaScript 구문 검사를 통과해야 합니다. 개발 환경에 Node.js가 있다면 다음 명령으로도 확인할 수 있습니다.
### 문제 4 — 번역이 배포 후 시간이 지나서 "모바일에서만" 다시 영어로 보임
```bash
node tools/verify-release.mjs
```
가장 까다로웠던 문제입니다. 번역을 배포하고 정상 동작까지 확인했는데, 이후 **모바일
기기에서만** 옵션 페이지 등의 본문 텍스트가 다시 영어로 나오는 현상이 발생했습니다
(페이지 제목이나 "한국어"라는 언어 이름 자체는 정상). 데스크톱에서는 동일 페이지가
100% 정상이었습니다.
기록된 번역 단계와 `release/demo-ko.zip`에서 배포 트리를 다시 모으려면 `node tools/build-release.mjs`를 실행합니다. 예제 압축 파일 생성 원본과 ID 대응 자료는 `tools/demo-source`에 보관했습니다. 과거 일회성 운영 DB 마이그레이션 코드는 일반 배포 번들에서 제거했습니다.
처음엔 모바일 브라우저 캐시 문제로 의심했지만, 캐시를 초기화하고 서로 다른 브라우저
엔진(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 본체와 동일한 라이선스를 따릅니다. 무보증 — 이 프로젝트는 컴파일된
바이너리를 난독화된 변수명 문자열 매칭 방식으로 패치하는 것이라, 버전이 올라가면
깨지기 쉬운 구조입니다.
`legacy/v1`과 `patch-only` 및 기존 v1.0.0 첨부 파일은 과거 배포판입니다. 신규 설치에는 이 문서와 루트의 Dockerfile·설치 스크립트를 사용하세요. 상세 번역 내역은 [변경 기록](updates/2026-09-05/CHANGELOG.ko.md)을 참고하세요.