한국어 배포판 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
+197
View File
@@ -0,0 +1,197 @@
# 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 본체와 동일한 라이선스를 따릅니다. 무보증 — 이 프로젝트는 컴파일된
바이너리를 난독화된 변수명 문자열 매칭 방식으로 패치하는 것이라, 버전이 올라가면
깨지기 쉬운 구조입니다.
@@ -0,0 +1,14 @@
services:
trilium:
image: triliumnext/notes:latest
container_name: trilium
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
+4088
View File
File diff suppressed because one or more lines are too long
+73
View File
@@ -0,0 +1,73 @@
#!/usr/bin/env node
/**
* Patches TriliumNext's bundled main.cjs to register Korean ("ko") as a
* selectable UI language.
*
* Why this is needed: the list of supported UI languages is not derived
* from the translations/ folders on disk — it's a hardcoded array literal
* baked into the minified server bundle (variable name may change between
* builds; as of triliumnext/notes:latest on 2026-08-25 it was `K5i`).
* A second hardcoded map (`IMi` as of the same build) lazy-loads a
* per-language resource (CKEditor's own locale bundle) and has no entry
* for "ko" either — since that resource is genuinely not bundled for any
* language we didn't already support, we alias it to the English loader
* instead of trying to fabricate a missing chunk.
*
* Usage: node patch_main_cjs.js /path/to/main.cjs
*
* Run this against a FRESH copy of main.cjs extracted from the image
* (`docker cp trilium:/usr/src/app/main.cjs .`) any time the image is
* updated, since the minified variable names (K5i, IMi, xvr) and byte
* offsets are not stable across TriliumNext releases. After patching,
* always run `node --check main.cjs` before deploying it.
*/
const fs = require('fs');
const path = process.argv[2];
if (!path) {
console.error('Usage: node patch_main_cjs.js /path/to/main.cjs');
process.exit(1);
}
let content = fs.readFileSync(path, 'utf8');
let patchedAnything = false;
// --- Patch 1: register "ko" in the main supported-locales array ---
// Original starts with: K5i=[{id:"en",name:"English",electronLocale:"en"},{id:"de"
// We insert a new first element right after the opening `[`.
{
const marker = 'K5i=[{id:"en",name:"English",electronLocale:"en"},{id:"de"';
const idx = content.indexOf(marker);
if (idx === -1) {
console.log('[skip] locale-list marker not found (variable name may have changed, or already patched)');
} else {
const insertPoint = idx + 'K5i=['.length;
const insertion = '{id:"ko",name:"한국어",electronLocale:"ko"},';
content = content.slice(0, insertPoint) + insertion + content.slice(insertPoint);
console.log('[ok] inserted "ko" into the supported-locales array');
patchedAnything = true;
}
}
// --- Patch 2: alias "ko" to the English loader in the per-language resource map ---
// Original: IMi={ar:...,cn:...,de:...,en:()=>Promise.resolve().then(()=>Xe(xvr())),es:...
{
const imiIdx = content.indexOf('IMi={ar:');
const marker = 'en:()=>Promise.resolve().then(()=>Xe(xvr())),es:';
const idx = content.indexOf(marker);
if (imiIdx === -1 || idx === -1 || idx < imiIdx || idx > imiIdx + 700) {
console.log('[skip] per-language resource map marker not found or not where expected (already patched, or minified names changed)');
} else {
const insertion = 'en:()=>Promise.resolve().then(()=>Xe(xvr())),ko:()=>Promise.resolve().then(()=>Xe(xvr())),es:';
content = content.slice(0, idx) + insertion + content.slice(idx + marker.length);
console.log('[ok] aliased "ko" to the English loader in the resource map');
patchedAnything = true;
}
}
if (!patchedAnything) {
console.log('Nothing patched (file may already be patched, or this is a different TriliumNext version — re-derive the markers manually).');
process.exit(0);
}
fs.writeFileSync(path, content, 'utf8');
console.log('Wrote', path, '— now run: node --check', path);
+307
View File
@@ -0,0 +1,307 @@
{
"keyboard_actions": {
"back-in-note-history": "기록에서 이전 노트로 이동",
"forward-in-note-history": "기록에서 다음 노트로 이동",
"open-jump-to-note-dialog": "\"노트로 이동\" 대화상자 열기",
"scroll-to-active-note": "노트 트리를 활성 노트로 스크롤",
"quick-search": "빠른 검색 바 활성화",
"search-in-subtree": "활성 노트의 하위 트리에서 노트 검색",
"expand-subtree": "현재 노트의 하위 트리 펼치기",
"collapse-tree": "전체 노트 트리 접기",
"collapse-subtree": "현재 노트의 하위 트리 접기",
"sort-child-notes": "하위 노트 정렬",
"creating-and-moving-notes": "노트 만들기 및 이동",
"create-note-after": "활성 노트 다음에 노트 만들기",
"create-note-into": "활성 노트의 하위로 노트 만들기",
"create-note-into-inbox": "받은편지함(정의된 경우) 또는 일일 노트에 노트 만들기",
"delete-note": "노트 삭제",
"move-note-up": "노트 위로 이동",
"move-note-down": "노트 아래로 이동",
"move-note-up-in-hierarchy": "계층 구조에서 노트 위로 이동",
"move-note-down-in-hierarchy": "계층 구조에서 노트 아래로 이동",
"edit-note-title": "트리에서 노트 상세로 이동해서 제목 편집",
"edit-branch-prefix": "\"브랜치 접두사 편집\" 대화상자 표시",
"cloneNotesTo": "선택한 노트 복제",
"moveNotesTo": "선택한 노트 이동",
"note-clipboard": "노트 클립보드",
"copy-notes-to-clipboard": "선택한 노트를 클립보드에 복사",
"paste-notes-from-clipboard": "클립보드의 노트를 활성 노트에 붙여넣기",
"cut-notes-to-clipboard": "선택한 노트를 클립보드로 잘라내기",
"select-all-notes-in-parent": "현재 노트 레벨의 모든 노트 선택",
"add-note-above-to-the-selection": "선택 영역에 위 노트 추가",
"add-note-below-to-selection": "선택 영역에 아래 노트 추가",
"duplicate-subtree": "하위 트리 복제",
"tabs-and-windows": "탭 및 창",
"open-new-tab": "새 탭 열기",
"close-active-tab": "활성 탭 닫기",
"reopen-last-tab": "마지막으로 닫은 탭 다시 열기",
"activate-next-tab": "오른쪽 탭 활성화",
"activate-previous-tab": "왼쪽 탭 활성화",
"open-new-window": "새 빈 창 열기",
"toggle-tray": "시스템 트레이에서 애플리케이션 표시/숨김",
"first-tab": "목록의 첫 번째 탭 활성화",
"second-tab": "목록의 두 번째 탭 활성화",
"third-tab": "목록의 세 번째 탭 활성화",
"fourth-tab": "목록의 네 번째 탭 활성화",
"fifth-tab": "목록의 다섯 번째 탭 활성화",
"sixth-tab": "목록의 여섯 번째 탭 활성화",
"seventh-tab": "목록의 일곱 번째 탭 활성화",
"eight-tab": "목록의 여덟 번째 탭 활성화",
"ninth-tab": "목록의 아홉 번째 탭 활성화",
"last-tab": "목록의 마지막 탭 활성화",
"dialogs": "대화상자",
"show-note-source": "\"노트 소스\" 대화상자 표시",
"show-options": "\"옵션\" 페이지 열기",
"show-revisions": "\"노트 리비전\" 대화상자 표시",
"show-recent-changes": "\"최근 변경 내역\" 대화상자 표시",
"show-sql-console": "\"SQL 콘솔\" 페이지 열기",
"show-backend-log": "\"백엔드 로그\" 페이지 열기",
"show-help": "내장 사용자 가이드 열기",
"show-cheatsheet": "일반적인 키보드 작업 모달 표시",
"text-note-operations": "텍스트 노트 작업",
"add-link-to-text": "텍스트에 링크를 추가하는 대화상자 열기",
"follow-link-under-cursor": "캐럿이 위치한 링크 따라가기",
"insert-date-and-time-to-text": "텍스트에 현재 날짜 및 시간 삽입",
"paste-markdown-into-text": "클립보드의 Markdown을 텍스트 노트에 붙여넣기",
"cut-into-note": "현재 노트에서 선택 영역을 잘라내서 선택한 텍스트로 하위 노트 만들기",
"add-include-note-to-text": "노트를 포함하는 대화상자 열기",
"edit-readonly-note": "읽기 전용 노트 편집",
"attributes-labels-and-relations": "속성 (라벨 및 관계)",
"add-new-label": "새 라벨 만들기",
"create-new-relation": "새 관계 만들기",
"ribbon-tabs": "리본 탭",
"toggle-basic-properties": "기본 속성 전환",
"toggle-file-properties": "파일 속성 전환",
"toggle-image-properties": "이미지 속성 전환",
"toggle-owned-attributes": "소유한 속성 전환",
"toggle-inherited-attributes": "상속된 속성 전환",
"toggle-promoted-attributes": "승격된 속성 전환",
"toggle-link-map": "링크 지도 전환",
"toggle-note-info": "노트 정보 전환",
"toggle-note-paths": "노트 경로 전환",
"toggle-similar-notes": "유사한 노트 전환",
"other": "기타",
"toggle-right-pane": "목차와 하이라이트가 포함된 오른쪽 패널 표시 전환",
"print-active-note": "활성 노트 인쇄",
"open-note-externally": "기본 애플리케이션으로 노트를 파일로 열기",
"render-active-note": "활성 노트 렌더링(다시 렌더링)",
"run-active-note": "활성 JavaScript(프론트엔드/백엔드) 코드 노트 실행",
"toggle-note-hoisting": "활성 노트의 노트 호이스팅 전환",
"unhoist": "어디서든 호이스팅 해제",
"reload-frontend-app": "프론트엔드 다시 로드",
"open-dev-tools": "개발자 도구 열기",
"find-in-text": "검색 패널 전환",
"toggle-left-note-tree-panel": "왼쪽(노트 트리) 패널 전환",
"toggle-full-screen": "전체 화면 전환",
"zoom-out": "축소",
"zoom-in": "확대",
"note-navigation": "노트 탐색",
"reset-zoom-level": "확대/축소 수준 초기화",
"copy-without-formatting": "서식 없이 선택한 텍스트 복사",
"force-save-revision": "활성 노트의 새 리비전을 강제로 생성/저장",
"toggle-book-properties": "북 속성 전환",
"toggle-classic-editor-toolbar": "고정 도구모음이 있는 편집기의 서식 탭 전환",
"export-as-pdf": "현재 노트를 PDF로 내보내기",
"toggle-zen-mode": "젠 모드 활성화/비활성화 (더 집중된 편집을 위한 최소 UI)"
},
"login": {
"title": "로그인",
"heading": "Trilium 로그인",
"incorrect-totp": "TOTP가 올바르지 않습니다. 다시 시도하세요.",
"incorrect-password": "비밀번호가 올바르지 않습니다. 다시 시도하세요.",
"password": "비밀번호",
"remember-me": "로그인 상태 유지",
"button": "로그인",
"sign_in_with_sso": "{{ ssoIssuerName }}(으)로 로그인"
},
"set_password": {
"title": "비밀번호 설정",
"heading": "비밀번호 설정",
"description": "웹에서 Trilium을 사용하려면 먼저 비밀번호를 설정해야 합니다. 이후 이 비밀번호로 로그인합니다.",
"password": "비밀번호",
"password-confirmation": "비밀번호 확인",
"button": "비밀번호 설정"
},
"javascript-required": "Trilium을 사용하려면 JavaScript가 활성화되어 있어야 합니다.",
"setup": {
"heading": "TriliumNext Notes 설정",
"new-document": "신규 사용자이며, 노트를 위한 새 Trilium 문서를 만들고 싶습니다",
"sync-from-desktop": "이미 데스크톱 인스턴스가 있으며, 동기화를 설정하고 싶습니다",
"sync-from-server": "이미 서버 인스턴스가 있으며, 동기화를 설정하고 싶습니다",
"next": "다음",
"init-in-progress": "문서 초기화 진행 중",
"redirecting": "곧 애플리케이션으로 이동합니다.",
"title": "설정"
},
"setup_sync-from-desktop": {
"heading": "데스크톱에서 동기화",
"description": "이 설정은 데스크톱 인스턴스에서 시작해야 합니다:",
"step1": "TriliumNext Notes 데스크톱 인스턴스를 여세요.",
"step2": "Trilium 메뉴에서 옵션을 클릭하세요.",
"step3": "동기화 카테고리를 클릭하세요.",
"step4": "서버 인스턴스 주소를 {{- host}}로 변경하고 저장을 클릭하세요.",
"step5": "\"동기화 테스트\" 버튼을 클릭해서 연결이 성공하는지 확인하세요.",
"step6": "이 단계를 완료했으면 {{- link}}를 클릭하세요.",
"step6-here": "여기"
},
"setup_sync-from-server": {
"heading": "서버에서 동기화",
"instructions": "아래에 Trilium 서버 주소와 자격 증명을 입력하세요. 서버에서 전체 Trilium 문서를 다운로드하고 이에 대한 동기화를 설정합니다. 문서 크기와 연결 속도에 따라 시간이 걸릴 수 있습니다.",
"server-host": "Trilium 서버 주소",
"server-host-placeholder": "https://<hostname>:<port>",
"proxy-server": "프록시 서버 (선택 사항)",
"proxy-server-placeholder": "https://<hostname>:<port>",
"note": "참고:",
"proxy-instruction": "프록시 설정을 비워두면 시스템 프록시가 사용됩니다(데스크톱 애플리케이션에만 적용)",
"password": "비밀번호",
"password-placeholder": "비밀번호",
"back": "뒤로",
"finish-setup": "설정 완료"
},
"setup_sync-in-progress": {
"heading": "동기화 진행 중",
"successful": "동기화가 올바르게 설정되었습니다. 초기 동기화가 완료되기까지 시간이 걸립니다. 완료되면 로그인 페이지로 이동합니다.",
"outstanding-items": "미완료 동기화 항목:",
"outstanding-items-default": "해당 없음"
},
"share_404": {
"title": "찾을 수 없음",
"heading": "찾을 수 없음"
},
"share_page": {
"parent": "상위:",
"clipped-from": "이 노트는 원래 {{- url}}에서 클립되었습니다",
"child-notes": "하위 노트:",
"no-content": "이 노트에는 내용이 없습니다."
},
"weekdays": {
"monday": "월요일",
"tuesday": "화요일",
"wednesday": "수요일",
"thursday": "목요일",
"friday": "금요일",
"saturday": "토요일",
"sunday": "일요일"
},
"weekdayNumber": "{weekNumber}주차",
"months": {
"january": "1월",
"february": "2월",
"march": "3월",
"april": "4월",
"may": "5월",
"june": "6월",
"july": "7월",
"august": "8월",
"september": "9월",
"october": "10월",
"november": "11월",
"december": "12월"
},
"quarterNumber": "{quarterNumber}분기",
"special_notes": {
"search_prefix": "검색:"
},
"test_sync": {
"not-configured": "동기화 서버 호스트가 구성되지 않았습니다. 먼저 동기화를 구성하세요.",
"successful": "동기화 서버 핸드셰이크가 성공했으며, 동기화가 시작되었습니다."
},
"hidden-subtree": {
"root-title": "숨겨진 노트",
"search-history-title": "검색 기록",
"note-map-title": "노트 지도",
"sql-console-history-title": "SQL 콘솔 기록",
"shared-notes-title": "공유된 노트",
"bulk-action-title": "일괄 작업",
"backend-log-title": "백엔드 로그",
"user-hidden-title": "사용자 숨김",
"launch-bar-templates-title": "런치바 템플릿",
"base-abstract-launcher-title": "기본 추상 런처",
"command-launcher-title": "명령 런처",
"note-launcher-title": "노트 런처",
"script-launcher-title": "스크립트 런처",
"built-in-widget-title": "내장 위젯",
"spacer-title": "여백",
"custom-widget-title": "사용자 지정 위젯",
"launch-bar-title": "런치바",
"available-launchers-title": "사용 가능한 런처",
"go-to-previous-note-title": "이전 노트로 이동",
"go-to-next-note-title": "다음 노트로 이동",
"new-note-title": "새 노트",
"search-notes-title": "노트 검색",
"jump-to-note-title": "노트로 이동",
"calendar-title": "캘린더",
"recent-changes-title": "최근 변경 내역",
"bookmarks-title": "북마크",
"open-today-journal-note-title": "오늘의 일지 노트 열기",
"quick-search-title": "빠른 검색",
"protected-session-title": "보호된 세션",
"sync-status-title": "동기화 상태",
"settings-title": "설정",
"llm-chat-title": "노트와 채팅",
"options-title": "옵션",
"appearance-title": "외관",
"shortcuts-title": "단축키",
"text-notes": "텍스트 노트",
"code-notes-title": "코드 노트",
"images-title": "이미지",
"spellcheck-title": "맞춤법 검사",
"password-title": "비밀번호",
"multi-factor-authentication-title": "MFA",
"etapi-title": "ETAPI",
"backup-title": "백업",
"sync-title": "동기화",
"ai-llm-title": "AI/LLM",
"other": "기타",
"advanced-title": "고급",
"visible-launchers-title": "표시된 런처",
"user-guide": "사용자 가이드",
"localization": "언어 및 지역",
"inbox-title": "받은편지함"
},
"notes": {
"new-note": "새 노트",
"duplicate-note-suffix": "(사본)",
"duplicate-note-title": "{{- noteTitle }} {{ duplicateNoteSuffix }}"
},
"backend_log": {
"log-does-not-exist": "백엔드 로그 파일 '{{ fileName }}'이(가) (아직) 존재하지 않습니다.",
"reading-log-failed": "백엔드 로그 파일 '{{ fileName }}'을(를) 읽지 못했습니다."
},
"content_renderer": {
"note-cannot-be-displayed": "이 노트 유형은 표시할 수 없습니다."
},
"pdf": {
"export_filter": "PDF 문서 (*.pdf)",
"unable-to-export-message": "현재 노트를 PDF로 내보낼 수 없습니다.",
"unable-to-export-title": "PDF로 내보낼 수 없음",
"unable-to-save-message": "선택한 파일에 쓸 수 없습니다. 다시 시도하거나 다른 위치를 선택하세요."
},
"tray": {
"tooltip": "TriliumNext Notes",
"close": "Trilium 종료",
"recents": "최근 노트",
"bookmarks": "북마크",
"today": "오늘의 일지 노트 열기",
"new-note": "새 노트",
"show-windows": "창 표시",
"open_new_window": "새 창 열기"
},
"migration": {
"old_version": "현재 버전에서 직접 마이그레이션은 지원되지 않습니다. 먼저 최신 v0.60.4로 업그레이드한 후 이 버전으로 업그레이드하세요.",
"error_message": "버전 {{version}}(으)로 마이그레이션하는 중 오류: {{stack}}",
"wrong_db_version": "데이터베이스 버전({{version}})이 애플리케이션이 예상하는 버전({{targetVersion}})보다 최신입니다. 즉 더 새롭고 호환되지 않는 버전의 Trilium에서 생성되었다는 뜻입니다. 이 문제를 해결하려면 최신 버전의 Trilium으로 업그레이드하세요."
},
"modals": {
"error_title": "오류"
},
"share_theme": {
"site-theme": "사이트 테마",
"search_placeholder": "검색...",
"image_alt": "글 이미지",
"last-updated": "{{- date}}에 마지막으로 업데이트됨",
"subpages": "하위 페이지:",
"on-this-page": "이 페이지에서",
"expand": "펼치기"
}
}
File diff suppressed because it is too large Load Diff