예제 PDF와 통계 및 표시 속성 한글화와 검증 기록
This commit is contained in:
@@ -117,3 +117,25 @@ DB 백업은 SQLite 백업 API로 생성했습니다. 후속 UI 배포는 DB 변
|
|||||||
서버에서 ko가 영어 날짜 모듈을 불러오던 부분을 한국어 날짜 로케일로 교체했습니다. 새 SQL 콘솔과 실행 도구의 기본 제목을 번역하고 달력의 이전달·다음달·년도·일정목록 표현을 수정했습니다. 캐시 경로는 v0.95.0-ko-20260913-r3으로 변경했습니다.
|
서버에서 ko가 영어 날짜 모듈을 불러오던 부분을 한국어 날짜 로케일로 교체했습니다. 새 SQL 콘솔과 실행 도구의 기본 제목을 번역하고 달력의 이전달·다음달·년도·일정목록 표현을 수정했습니다. 캐시 경로는 v0.95.0-ko-20260913-r3으로 변경했습니다.
|
||||||
|
|
||||||
브라우저에서 검색 도움말과 한국어 목차를 확인했습니다. 예제 PDF와 이미지 안의 문구 및 외부 API 문서는 이 단계에서 번역 완료로 계산하지 않았습니다.
|
브라우저에서 검색 도움말과 한국어 목차를 확인했습니다. 예제 PDF와 이미지 안의 문구 및 외부 API 문서는 이 단계에서 번역 완료로 계산하지 않았습니다.
|
||||||
|
|
||||||
|
## 예제와 화면 문구 추가 적용
|
||||||
|
|
||||||
|
- 기본 예제의 통계 표와 원형 차트에 표시되는 노트 유형을 한국어로 바꿨습니다.
|
||||||
|
- 할 일 관리자 코드와 기존 가지 접두사 5개를 함께 수정했습니다. TODO와 DONE은 화면에서 할 일과 완료로 표시됩니다. 날짜 접두사도 한국어 순서로 바꿨습니다.
|
||||||
|
- 체중과 위치 좌표 및 독서 시작일·종료일과 저자·링크 및 장소·태그·예정일·완료일의 표시 이름 10개를 지정했습니다. 속성 키와 형식은 보존했습니다.
|
||||||
|
- 숨겨진 모바일 실행 도구 제목과 기존 기본 실행 도구의 어색한 이름을 수정했습니다. 기존 이름이 알려진 기본 번역과 일치할 때만 이름을 갱신합니다.
|
||||||
|
- 기본 예제 PDF의 머리말과 본문을 한국어로 번역했습니다. 원본 9쪽은 백업과 노트 수정 이력에 보존했습니다. 한국어판은 11쪽입니다. 본문 문단 194개 누락 검사와 페이지 렌더링 검토를 마쳤습니다. Chrome의 Trilium 화면에서도 한국어 PDF 표시를 확인했습니다.
|
||||||
|
- UI의 리비전과 런치바 및 런처 표현을 수정 이력과 실행 도구로 정리했습니다. 파일 교체 버튼은 새 버전 올리기로 바꿨습니다. 자리표시자를 보존했습니다.
|
||||||
|
- 현재 자산 버전은 v0.95.0-ko-20260913-r5입니다. 최신 앱 파일은 deployed 폴더에 있습니다. phase3부터 phase6까지는 단계별 배포 기록입니다.
|
||||||
|
|
||||||
|
검증한 백업 경로:
|
||||||
|
|
||||||
|
- /www/dk_project/dk_app/trilium/backups/before-korean-phase4-20260913-170536
|
||||||
|
- /www/dk_project/dk_app/trilium/backups/before-korean-phase5-20260913-171432
|
||||||
|
- /www/dk_project/dk_app/trilium/backups/before-korean-phase6-20260913-171753
|
||||||
|
|
||||||
|
PDF SHA-256: 1141ea4fb9d619fd55d75d0bdcd6bbd5678b161633586764d0eadfc4b9235400
|
||||||
|
|
||||||
|
## 남은 범위
|
||||||
|
|
||||||
|
도움말 본문과 목록 제목 및 위 예제 수정분은 운영 반영과 검증을 마쳤습니다. 도움말에는 PNG 270개와 GIF 15개 및 JPEG 1개가 있으며 이미지 내부의 영어는 별도 점검 대상입니다. 모든 이미지가 영어를 담고 있다는 뜻은 아닙니다. 외부 웹 보기로 연결된 API 문서와 남은 하드코딩 문구도 최종 확인해야 합니다. 전체 100% 완료로 표시하지 않습니다.
|
||||||
|
|||||||
@@ -14,6 +14,28 @@
|
|||||||
|
|
||||||
## 아직 남은 작업
|
## 아직 남은 작업
|
||||||
|
|
||||||
예제 PDF 본문과 기존 스크린샷 안의 영어를 별도로 확인해야 합니다. 외부 API 참고 페이지는 외부 사이트의 원문입니다. 예제의 일부 표시용 속성과 통계 출력 및 숨겨진 모바일 실행 도구 제목도 추가 점검 대상입니다. 도움말 100%를 전체 한글화 100%로 표시하지 않습니다.
|
예제 PDF 본문과 통계 출력 및 표시용 속성과 숨겨진 모바일 실행 도구 제목은 추가 적용을 마쳤습니다. 기존 스크린샷 안의 영어와 외부 API 문서 및 나머지 하드코딩 문구가 최종 점검 대상으로 남아 있습니다. 도움말 100%를 전체 한글화 100%로 표시하지 않습니다.
|
||||||
|
|
||||||
과거 기록의 100개와 103개 수치는 당시의 진행 상황입니다. 현재 운영 적용본은 phase3 폴더와 deployed 폴더입니다. work/trilium/release/main.cjs는 초기 빌드 산출물이므로 현재 운영 파일로 사용하지 마세요.
|
과거 기록의 100개와 103개 수치는 당시의 진행 상황입니다. 현재 운영 앱 파일은 deployed 폴더입니다. phase3부터 phase6까지는 각 단계의 기록입니다. work/trilium/release/main.cjs는 초기 빌드 산출물이므로 현재 운영 파일로 사용하지 마세요.
|
||||||
|
|
||||||
|
## 예제와 화면 문구 추가 적용
|
||||||
|
|
||||||
|
- 기본 예제의 통계 표와 원형 차트에 표시되는 노트 유형을 한국어로 바꿨습니다.
|
||||||
|
- 할 일 관리자 코드와 기존 가지 접두사 5개를 함께 수정했습니다. TODO와 DONE은 화면에서 할 일과 완료로 표시됩니다. 날짜 접두사도 한국어 순서로 바꿨습니다.
|
||||||
|
- 체중과 위치 좌표 및 독서 시작일·종료일과 저자·링크 및 장소·태그·예정일·완료일의 표시 이름 10개를 지정했습니다. 속성 키와 형식은 보존했습니다.
|
||||||
|
- 숨겨진 모바일 실행 도구 제목과 기존 기본 실행 도구의 어색한 이름을 수정했습니다. 기존 이름이 알려진 기본 번역과 일치할 때만 이름을 갱신합니다.
|
||||||
|
- 기본 예제 PDF의 머리말과 본문을 한국어로 번역했습니다. 원본 9쪽은 백업과 노트 수정 이력에 보존했습니다. 한국어판은 11쪽입니다. 본문 문단 194개 누락 검사와 페이지 렌더링 검토를 마쳤습니다. Chrome의 Trilium 화면에서도 한국어 PDF 표시를 확인했습니다.
|
||||||
|
- UI의 리비전과 런치바 및 런처 표현을 수정 이력과 실행 도구로 정리했습니다. 파일 교체 버튼은 새 버전 올리기로 바꿨습니다. 자리표시자를 보존했습니다.
|
||||||
|
- 현재 자산 버전은 v0.95.0-ko-20260913-r5입니다. 최신 앱 파일은 deployed 폴더에 있습니다. phase3부터 phase6까지는 단계별 배포 기록입니다.
|
||||||
|
|
||||||
|
검증한 백업 경로:
|
||||||
|
|
||||||
|
- /www/dk_project/dk_app/trilium/backups/before-korean-phase4-20260913-170536
|
||||||
|
- /www/dk_project/dk_app/trilium/backups/before-korean-phase5-20260913-171432
|
||||||
|
- /www/dk_project/dk_app/trilium/backups/before-korean-phase6-20260913-171753
|
||||||
|
|
||||||
|
PDF SHA-256: 1141ea4fb9d619fd55d75d0bdcd6bbd5678b161633586764d0eadfc4b9235400
|
||||||
|
|
||||||
|
## 남은 범위
|
||||||
|
|
||||||
|
도움말 본문과 목록 제목 및 위 예제 수정분은 운영 반영과 검증을 마쳤습니다. 도움말에는 PNG 270개와 GIF 15개 및 JPEG 1개가 있으며 이미지 내부의 영어는 별도 점검 대상입니다. 모든 이미지가 영어를 담고 있다는 뜻은 아닙니다. 외부 웹 보기로 연결된 API 문서와 남은 하드코딩 문구도 최종 확인해야 합니다. 전체 100% 완료로 표시하지 않습니다.
|
||||||
|
|||||||
@@ -4,12 +4,12 @@
|
|||||||
"sha256": "52b083643858fc11a8a832e4ca068c58635fad41ad76972e821d1253d8fa72bd"
|
"sha256": "52b083643858fc11a8a832e4ca068c58635fad41ad76972e821d1253d8fa72bd"
|
||||||
},
|
},
|
||||||
"CHANGELOG.ko.md": {
|
"CHANGELOG.ko.md": {
|
||||||
"bytes": 9809,
|
"bytes": 12132,
|
||||||
"sha256": "c24814e295b0efb6bab043414e0f24fdf294914bf837bea104d94fe9ccc97113"
|
"sha256": "7f0d39eb64c88c06955fb0b8a74b5f19221cd3f20f1de81d7eee394969c09d11"
|
||||||
},
|
},
|
||||||
"PROGRESS.md": {
|
"PROGRESS.md": {
|
||||||
"bytes": 1603,
|
"bytes": 3957,
|
||||||
"sha256": "5aee6ecedbb6fe75fa8903e69168f2256075c4ff98d4e6b771bd322d63325142"
|
"sha256": "7c7b9274198de07be49aad7a9cb9ca66195231ee6fdfa6d4c721531e066eb3cb"
|
||||||
},
|
},
|
||||||
"README.md": {
|
"README.md": {
|
||||||
"bytes": 5545,
|
"bytes": 5545,
|
||||||
@@ -40,20 +40,20 @@
|
|||||||
"sha256": "b888db7ebe9356b65d720848762689cc919f63b428e1f06d6e59a30b92b2fd5c"
|
"sha256": "b888db7ebe9356b65d720848762689cc919f63b428e1f06d6e59a30b92b2fd5c"
|
||||||
},
|
},
|
||||||
"deployed/main.cjs": {
|
"deployed/main.cjs": {
|
||||||
"bytes": 9018814,
|
"bytes": 9022693,
|
||||||
"sha256": "2f94e1c483cfe83aa3a7689e087ed8ee28ceb051c3789917a3be21bef6f1aabc"
|
"sha256": "b8c607ce3aaa551b1dc1f6f67c5011656084ebf3ba04e391ee49fb3aab349db2"
|
||||||
},
|
},
|
||||||
"deployed/mobile_layout.js": {
|
"deployed/mobile_layout.js": {
|
||||||
"bytes": 9771,
|
"bytes": 9771,
|
||||||
"sha256": "aaeaf0cd1773731aa5944db83bfcc7e53e5190aaacd4d154dbfffbbf29d10a3c"
|
"sha256": "aaeaf0cd1773731aa5944db83bfcc7e53e5190aaacd4d154dbfffbbf29d10a3c"
|
||||||
},
|
},
|
||||||
"deployed/server.json": {
|
"deployed/server.json": {
|
||||||
"bytes": 15441,
|
"bytes": 15515,
|
||||||
"sha256": "c1ddf9870fa9d6494ce48dcf16079e071990ffb81fe014836d580e00bad8728d"
|
"sha256": "5171b0bab55f0c260b9256c5164240526e679f324cfd4e23e7db9d22b78bf977"
|
||||||
},
|
},
|
||||||
"deployed/translation.json": {
|
"deployed/translation.json": {
|
||||||
"bytes": 116132,
|
"bytes": 116238,
|
||||||
"sha256": "222ce7e5f6f3cfbbe848f784ddb5201e5a17f03f2ef095e1781992dbd7633724"
|
"sha256": "e1d34275426dabf9aabf2f9b3ec880157946975f9f3f5a9035cf412ce02c9114"
|
||||||
},
|
},
|
||||||
"phase3-input/ko.js": {
|
"phase3-input/ko.js": {
|
||||||
"bytes": 530,
|
"bytes": 530,
|
||||||
@@ -1943,6 +1943,50 @@
|
|||||||
"bytes": 73234,
|
"bytes": 73234,
|
||||||
"sha256": "d4a68c246026c3c99a304a875dd6cff713b8e101419c7a97d805f3a3bdd5d49a"
|
"sha256": "d4a68c246026c3c99a304a875dd6cff713b8e101419c7a97d805f3a3bdd5d49a"
|
||||||
},
|
},
|
||||||
|
"phase4/korean-phase4-pending.json": {
|
||||||
|
"bytes": 7990,
|
||||||
|
"sha256": "6eaf94ee3801b736fe137bc1550087f5581623e10d2f3cdf72e43fc03a5160c1"
|
||||||
|
},
|
||||||
|
"phase4/main.cjs": {
|
||||||
|
"bytes": 9021505,
|
||||||
|
"sha256": "2e5fad9489279e51688a0a6cab424b2e90d1aaa6a5034426a41d053cd11d487c"
|
||||||
|
},
|
||||||
|
"phase4/manifest.json": {
|
||||||
|
"bytes": 384,
|
||||||
|
"sha256": "a6acc24b1c2e11349334f60c867562579181ddacf8b102e0d7d50da12f18d777"
|
||||||
|
},
|
||||||
|
"phase4/server.json": {
|
||||||
|
"bytes": 15515,
|
||||||
|
"sha256": "5171b0bab55f0c260b9256c5164240526e679f324cfd4e23e7db9d22b78bf977"
|
||||||
|
},
|
||||||
|
"phase5/demo-ko.pdf": {
|
||||||
|
"bytes": 214558,
|
||||||
|
"sha256": "1141ea4fb9d619fd55d75d0bdcd6bbd5678b161633586764d0eadfc4b9235400"
|
||||||
|
},
|
||||||
|
"phase5/main.cjs": {
|
||||||
|
"bytes": 9022693,
|
||||||
|
"sha256": "4b0d45a3722b5d4277a50d0e80054ee4ce8056c4a171a7f64b9ed2acbc088cae"
|
||||||
|
},
|
||||||
|
"phase5/manifest.json": {
|
||||||
|
"bytes": 373,
|
||||||
|
"sha256": "d0cc9a65575ce7462dbf8b613b7488379a7088858e13910600d0a0b524084ce8"
|
||||||
|
},
|
||||||
|
"phase6/main.cjs": {
|
||||||
|
"bytes": 9022693,
|
||||||
|
"sha256": "b8c607ce3aaa551b1dc1f6f67c5011656084ebf3ba04e391ee49fb3aab349db2"
|
||||||
|
},
|
||||||
|
"phase6/manifest.json": {
|
||||||
|
"bytes": 386,
|
||||||
|
"sha256": "f687b0f6237e3dfb58dbfc3a0821a35b74cdd215d943015fcebcf30f7235f8bf"
|
||||||
|
},
|
||||||
|
"phase6/translation.json": {
|
||||||
|
"bytes": 116238,
|
||||||
|
"sha256": "e1d34275426dabf9aabf2f9b3ec880157946975f9f3f5a9035cf412ce02c9114"
|
||||||
|
},
|
||||||
|
"phase6/wording-changes.json": {
|
||||||
|
"bytes": 15817,
|
||||||
|
"sha256": "7446fb50e449e794a61a1f0ce325cc28299b5cce086fb4b5ef421aa26da62a65"
|
||||||
|
},
|
||||||
"verify-snapshot.mjs": {
|
"verify-snapshot.mjs": {
|
||||||
"bytes": 1050,
|
"bytes": 1050,
|
||||||
"sha256": "944aa1e3c8f8fd835dc0121071bf25b93de03cb29f0c0b3bd41febd209acb764"
|
"sha256": "944aa1e3c8f8fd835dc0121071bf25b93de03cb29f0c0b3bd41febd209acb764"
|
||||||
@@ -1955,6 +1999,10 @@
|
|||||||
"bytes": 1442,
|
"bytes": 1442,
|
||||||
"sha256": "0d510437287befabffb6489b34e7bbf38f9f73f4971096b39528a1ffcd8cb51a"
|
"sha256": "0d510437287befabffb6489b34e7bbf38f9f73f4971096b39528a1ffcd8cb51a"
|
||||||
},
|
},
|
||||||
|
"work/trilium/build-demo-pdf.py": {
|
||||||
|
"bytes": 2453,
|
||||||
|
"sha256": "677d540668585420d8951d7f6a3c3551abb0ff266724a09648bd16d4c3864ef7"
|
||||||
|
},
|
||||||
"work/trilium/build-demo.mjs": {
|
"work/trilium/build-demo.mjs": {
|
||||||
"bytes": 4603,
|
"bytes": 4603,
|
||||||
"sha256": "90c0d36e2518aa597b3e09fdcaae4729168bba4e0a2cea65e1a1ecb9331d473a"
|
"sha256": "90c0d36e2518aa597b3e09fdcaae4729168bba4e0a2cea65e1a1ecb9331d473a"
|
||||||
@@ -1971,6 +2019,18 @@
|
|||||||
"bytes": 3017,
|
"bytes": 3017,
|
||||||
"sha256": "e370c5cf4f93b74f16dff9a378506cefb8c79b7f856355b0e8eb9cce72ee55f6"
|
"sha256": "e370c5cf4f93b74f16dff9a378506cefb8c79b7f856355b0e8eb9cce72ee55f6"
|
||||||
},
|
},
|
||||||
|
"work/trilium/build-phase4.mjs": {
|
||||||
|
"bytes": 5860,
|
||||||
|
"sha256": "11569abca55e91deb04ef4365907200a13e8478e3da17921ebd5e8bc856f69b1"
|
||||||
|
},
|
||||||
|
"work/trilium/build-phase5.mjs": {
|
||||||
|
"bytes": 1993,
|
||||||
|
"sha256": "d8cc03d57ebcfc41635d2b83046cf3244fc0d30300384069d8a7fcd747fe1cda"
|
||||||
|
},
|
||||||
|
"work/trilium/build-phase6.mjs": {
|
||||||
|
"bytes": 4960,
|
||||||
|
"sha256": "80c846a0597f2e6c611fc6111a0308fcc57bbda1c9620b1383946fa0c00c49f3"
|
||||||
|
},
|
||||||
"work/trilium/build-server.mjs": {
|
"work/trilium/build-server.mjs": {
|
||||||
"bytes": 2786,
|
"bytes": 2786,
|
||||||
"sha256": "2c64311599b7465c6435c14929d756ba011afd828bff69bd8fd88017e69f5f60"
|
"sha256": "2c64311599b7465c6435c14929d756ba011afd828bff69bd8fd88017e69f5f60"
|
||||||
@@ -2015,6 +2075,18 @@
|
|||||||
"bytes": 3829,
|
"bytes": 3829,
|
||||||
"sha256": "530dafca12b4145f4311822d2f0a53c19429cdc8739f91303c168fd55f814fb2"
|
"sha256": "530dafca12b4145f4311822d2f0a53c19429cdc8739f91303c168fd55f814fb2"
|
||||||
},
|
},
|
||||||
|
"work/trilium/deploy-phase4.py": {
|
||||||
|
"bytes": 3096,
|
||||||
|
"sha256": "2402cd483d18475c5703b7d5c1d5b8028bcaadc6666152173773d639fa6ca5da"
|
||||||
|
},
|
||||||
|
"work/trilium/deploy-phase5.py": {
|
||||||
|
"bytes": 2374,
|
||||||
|
"sha256": "f349514ed6cd00de5f8e5eaac2b47b127a85fd5be25c2f35124807b5bc51bbcc"
|
||||||
|
},
|
||||||
|
"work/trilium/deploy-phase6.py": {
|
||||||
|
"bytes": 1867,
|
||||||
|
"sha256": "7122297bd50e9030df08ba0e7ce83cd69049d03f0453a7416e89c8fcd0e30f82"
|
||||||
|
},
|
||||||
"work/trilium/deploy-ui-phase2.py": {
|
"work/trilium/deploy-ui-phase2.py": {
|
||||||
"bytes": 3049,
|
"bytes": 3049,
|
||||||
"sha256": "db296e39897e1a6758435e44077466087b58233333b1541c3e3e3f4ade67e60d"
|
"sha256": "db296e39897e1a6758435e44077466087b58233333b1541c3e3e3f4ade67e60d"
|
||||||
@@ -2183,10 +2255,26 @@
|
|||||||
"bytes": 2,
|
"bytes": 2,
|
||||||
"sha256": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945"
|
"sha256": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945"
|
||||||
},
|
},
|
||||||
|
"work/trilium/inspect-phase4.py": {
|
||||||
|
"bytes": 1842,
|
||||||
|
"sha256": "3d50c3ff9728040ddb11d6147d14447c3a525bbd7b8c4d64af149c872ec05e41"
|
||||||
|
},
|
||||||
|
"work/trilium/last-question.ko.txt": {
|
||||||
|
"bytes": 31544,
|
||||||
|
"sha256": "226a8db1a2f9be11de49f05965bd9ce79ed4963cb5540b4f3260ea56534d4dbd"
|
||||||
|
},
|
||||||
"work/trilium/layout_commons.js": {
|
"work/trilium/layout_commons.js": {
|
||||||
"bytes": 1332326,
|
"bytes": 1332326,
|
||||||
"sha256": "c5ebf993f416c1a732a12cb46605902df120dfb7662d1dc23fa69fed2f2ac876"
|
"sha256": "c5ebf993f416c1a732a12cb46605902df120dfb7662d1dc23fa69fed2f2ac876"
|
||||||
},
|
},
|
||||||
|
"work/trilium/phase4-inspect/data.json": {
|
||||||
|
"bytes": 5633,
|
||||||
|
"sha256": "19988bcc03abb030d54e8be8d39dde467bea86f8dcdc8c514f9e4466d0970b2a"
|
||||||
|
},
|
||||||
|
"work/trilium/phase4-inspect/demo.pdf": {
|
||||||
|
"bytes": 49359,
|
||||||
|
"sha256": "0180798e74d32a745d76d8d76cb9ec76d924d903231966f65d89436dadac15c1"
|
||||||
|
},
|
||||||
"work/trilium/release/MindElixir.js": {
|
"work/trilium/release/MindElixir.js": {
|
||||||
"bytes": 94559,
|
"bytes": 94559,
|
||||||
"sha256": "5c43e4738bee6b6239243f33775e35e82a658c382151c903f39e189d27946cc6"
|
"sha256": "5c43e4738bee6b6239243f33775e35e82a658c382151c903f39e189d27946cc6"
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -214,48 +214,48 @@
|
|||||||
"shared-notes-title": "공유된 노트",
|
"shared-notes-title": "공유된 노트",
|
||||||
"bulk-action-title": "일괄 작업",
|
"bulk-action-title": "일괄 작업",
|
||||||
"backend-log-title": "백엔드 로그",
|
"backend-log-title": "백엔드 로그",
|
||||||
"user-hidden-title": "사용자 숨김",
|
"user-hidden-title": "사용자 숨김 영역",
|
||||||
"launch-bar-templates-title": "런치바 템플릿",
|
"launch-bar-templates-title": "실행 도구 템플릿",
|
||||||
"base-abstract-launcher-title": "기본 추상 런처",
|
"base-abstract-launcher-title": "실행 도구 기본 템플릿",
|
||||||
"command-launcher-title": "명령 런처",
|
"command-launcher-title": "명령 실행 도구",
|
||||||
"note-launcher-title": "노트 런처",
|
"note-launcher-title": "노트 실행 도구",
|
||||||
"script-launcher-title": "스크립트 런처",
|
"script-launcher-title": "스크립트 실행 도구",
|
||||||
"built-in-widget-title": "내장 위젯",
|
"built-in-widget-title": "내장 위젯",
|
||||||
"spacer-title": "여백",
|
"spacer-title": "여백",
|
||||||
"custom-widget-title": "사용자 지정 위젯",
|
"custom-widget-title": "사용자 지정 위젯",
|
||||||
"launch-bar-title": "런치바",
|
"launch-bar-title": "실행 도구 모음",
|
||||||
"available-launchers-title": "사용 가능한 런처",
|
"available-launchers-title": "사용 가능한 실행 도구",
|
||||||
"go-to-previous-note-title": "이전 노트로 이동",
|
"go-to-previous-note-title": "이전 노트로 이동",
|
||||||
"go-to-next-note-title": "다음 노트로 이동",
|
"go-to-next-note-title": "다음 노트로 이동",
|
||||||
"new-note-title": "새 노트",
|
"new-note-title": "새 노트",
|
||||||
"search-notes-title": "노트 검색",
|
"search-notes-title": "노트 검색",
|
||||||
"jump-to-note-title": "노트로 이동",
|
"jump-to-note-title": "노트로 이동",
|
||||||
"calendar-title": "캘린더",
|
"calendar-title": "달력",
|
||||||
"recent-changes-title": "최근 변경 내역",
|
"recent-changes-title": "최근 변경 사항",
|
||||||
"bookmarks-title": "북마크",
|
"bookmarks-title": "북마크",
|
||||||
"open-today-journal-note-title": "오늘의 일지 노트 열기",
|
"open-today-journal-note-title": "오늘의 일지 노트 열기",
|
||||||
"quick-search-title": "빠른 검색",
|
"quick-search-title": "빠른 검색",
|
||||||
"protected-session-title": "보호된 세션",
|
"protected-session-title": "보호된 세션",
|
||||||
"sync-status-title": "동기화 상태",
|
"sync-status-title": "동기화 상태",
|
||||||
"settings-title": "설정",
|
"settings-title": "설정",
|
||||||
"llm-chat-title": "노트와 채팅",
|
"llm-chat-title": "노트와 대화",
|
||||||
"options-title": "옵션",
|
"options-title": "설정",
|
||||||
"appearance-title": "외관",
|
"appearance-title": "모양",
|
||||||
"shortcuts-title": "단축키",
|
"shortcuts-title": "단축키",
|
||||||
"text-notes": "텍스트 노트",
|
"text-notes": "텍스트 노트",
|
||||||
"code-notes-title": "코드 노트",
|
"code-notes-title": "코드 노트",
|
||||||
"images-title": "이미지",
|
"images-title": "이미지",
|
||||||
"spellcheck-title": "맞춤법 검사",
|
"spellcheck-title": "맞춤법 검사",
|
||||||
"password-title": "비밀번호",
|
"password-title": "비밀번호",
|
||||||
"multi-factor-authentication-title": "MFA",
|
"multi-factor-authentication-title": "다중 인증",
|
||||||
"etapi-title": "ETAPI",
|
"etapi-title": "ETAPI",
|
||||||
"backup-title": "백업",
|
"backup-title": "백업",
|
||||||
"sync-title": "동기화",
|
"sync-title": "동기화",
|
||||||
"ai-llm-title": "AI/LLM",
|
"ai-llm-title": "AI/LLM",
|
||||||
"other": "기타",
|
"other": "기타",
|
||||||
"advanced-title": "고급",
|
"advanced-title": "고급",
|
||||||
"visible-launchers-title": "표시된 런처",
|
"visible-launchers-title": "표시할 실행 도구",
|
||||||
"user-guide": "사용자 가이드",
|
"user-guide": "사용자 안내서",
|
||||||
"localization": "언어 및 지역",
|
"localization": "언어 및 지역",
|
||||||
"inbox-title": "받은편지함"
|
"inbox-title": "받은편지함"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
"db_version": "DB 버전:",
|
"db_version": "DB 버전:",
|
||||||
"sync_version": "동기화 버전:",
|
"sync_version": "동기화 버전:",
|
||||||
"build_date": "빌드 날짜:",
|
"build_date": "빌드 날짜:",
|
||||||
"build_revision": "빌드 리비전:",
|
"build_revision": "빌드 버전:",
|
||||||
"data_directory": "데이터 디렉토리:"
|
"data_directory": "데이터 디렉토리:"
|
||||||
},
|
},
|
||||||
"toast": {
|
"toast": {
|
||||||
@@ -267,24 +267,24 @@
|
|||||||
"confirm_undelete": "이 노트와 하위 노트를 복원하시겠습니까?"
|
"confirm_undelete": "이 노트와 하위 노트를 복원하시겠습니까?"
|
||||||
},
|
},
|
||||||
"revisions": {
|
"revisions": {
|
||||||
"note_revisions": "노트 리비전",
|
"note_revisions": "노트 수정 이력",
|
||||||
"delete_all_revisions": "이 노트의 모든 리비전 삭제",
|
"delete_all_revisions": "이 노트의 모든 수정 이력 삭제",
|
||||||
"delete_all_button": "모든 리비전 삭제",
|
"delete_all_button": "모든 수정 이력 삭제",
|
||||||
"help_title": "노트 리비전 도움말",
|
"help_title": "노트 수정 이력 도움말",
|
||||||
"close": "닫기",
|
"close": "닫기",
|
||||||
"revision_last_edited": "이 리비전은 {{date}}에 마지막으로 편집되었습니다",
|
"revision_last_edited": "이 버전은 {{date}}에 마지막으로 수정되었습니다.",
|
||||||
"confirm_delete_all": "이 노트의 모든 리비전을 삭제하시겠습니까?",
|
"confirm_delete_all": "이 노트의 모든 수정 이력을 삭제하시겠습니까?",
|
||||||
"no_revisions": "아직 이 노트에 대한 리비전이 없습니다...",
|
"no_revisions": "아직 저장된 수정 이력이 없습니다.",
|
||||||
"restore_button": "복원",
|
"restore_button": "복원",
|
||||||
"confirm_restore": "이 리비전을 복원하시겠습니까? 노트의 현재 제목과 내용이 이 리비전으로 덮어써집니다.",
|
"confirm_restore": "이 버전으로 복원하시겠습니까? 현재 제목과 본문이 선택한 버전의 내용으로 바뀝니다.",
|
||||||
"delete_button": "삭제",
|
"delete_button": "삭제",
|
||||||
"confirm_delete": "이 리비전을 삭제하시겠습니까?",
|
"confirm_delete": "이 수정 이력을 삭제하시겠습니까?",
|
||||||
"revisions_deleted": "노트 리비전이 삭제되었습니다.",
|
"revisions_deleted": "노트 수정 이력이 삭제되었습니다.",
|
||||||
"revision_restored": "노트 리비전이 복원되었습니다.",
|
"revision_restored": "선택한 버전으로 복원했습니다.",
|
||||||
"revision_deleted": "노트 리비전이 삭제되었습니다.",
|
"revision_deleted": "노트 수정 이력이 삭제되었습니다.",
|
||||||
"snapshot_interval": "노트 리비전 스냅샷 간격: {{seconds}}초.",
|
"snapshot_interval": "수정 이력 자동 저장 간격: {{seconds}}초",
|
||||||
"maximum_revisions": "노트 리비전 스냅샷 제한: {{number}}.",
|
"maximum_revisions": "보관할 수정 이력 수: {{number}}개",
|
||||||
"settings": "노트 리비전 설정",
|
"settings": "노트 수정 이력 설정",
|
||||||
"download_button": "다운로드",
|
"download_button": "다운로드",
|
||||||
"mime": "MIME: ",
|
"mime": "MIME: ",
|
||||||
"file_size": "파일 크기:",
|
"file_size": "파일 크기:",
|
||||||
@@ -505,7 +505,7 @@
|
|||||||
"erase_notes_instruction": "노트를 영구적으로 삭제하려면 삭제 후 옵션 -> 기타로 가서 \"삭제된 노트 지금 완전히 삭제\" 버튼을 클릭하세요."
|
"erase_notes_instruction": "노트를 영구적으로 삭제하려면 삭제 후 옵션 -> 기타로 가서 \"삭제된 노트 지금 완전히 삭제\" 버튼을 클릭하세요."
|
||||||
},
|
},
|
||||||
"delete_revisions": {
|
"delete_revisions": {
|
||||||
"delete_note_revisions": "노트 리비전 삭제",
|
"delete_note_revisions": "노트 수정 이력 삭제",
|
||||||
"all_past_note_revisions": "해당 노트의 이전 버전을 모두 삭제합니다. 현재 노트는 유지되지만 과거의 변경 내역은 사라집니다."
|
"all_past_note_revisions": "해당 노트의 이전 버전을 모두 삭제합니다. 현재 노트는 유지되지만 과거의 변경 내역은 사라집니다."
|
||||||
},
|
},
|
||||||
"move_note": {
|
"move_note": {
|
||||||
@@ -566,12 +566,12 @@
|
|||||||
"open_custom_title": "파일이 외부 애플리케이션에서 열리고 변경 사항이 감시됩니다. 이후 수정된 버전을 다시 Trilium에 업로드할 수 있습니다.",
|
"open_custom_title": "파일이 외부 애플리케이션에서 열리고 변경 사항이 감시됩니다. 이후 수정된 버전을 다시 Trilium에 업로드할 수 있습니다.",
|
||||||
"download": "다운로드",
|
"download": "다운로드",
|
||||||
"rename_attachment": "첨부파일 이름 변경",
|
"rename_attachment": "첨부파일 이름 변경",
|
||||||
"upload_new_revision": "새 리비전 업로드",
|
"upload_new_revision": "새 버전 올리기",
|
||||||
"copy_link_to_clipboard": "링크를 클립보드에 복사",
|
"copy_link_to_clipboard": "링크를 클립보드에 복사",
|
||||||
"convert_attachment_into_note": "첨부파일을 노트로 변환",
|
"convert_attachment_into_note": "첨부파일을 노트로 변환",
|
||||||
"delete_attachment": "첨부파일 삭제",
|
"delete_attachment": "첨부파일 삭제",
|
||||||
"upload_success": "새 첨부파일 리비전이 업로드되었습니다.",
|
"upload_success": "첨부 파일을 새 버전으로 교체했습니다.",
|
||||||
"upload_failed": "새 첨부파일 리비전 업로드에 실패했습니다.",
|
"upload_failed": "첨부 파일의 새 버전을 올리지 못했습니다.",
|
||||||
"open_externally_detail_page": "첨부파일을 외부에서 여는 것은 상세 페이지에서만 가능합니다. 먼저 첨부파일 상세 페이지를 클릭한 후 다시 시도하세요.",
|
"open_externally_detail_page": "첨부파일을 외부에서 여는 것은 상세 페이지에서만 가능합니다. 먼저 첨부파일 상세 페이지를 클릭한 후 다시 시도하세요.",
|
||||||
"open_custom_client_only": "첨부파일을 사용자 지정으로 여는 것은 데스크톱 클라이언트에서만 가능합니다.",
|
"open_custom_client_only": "첨부파일을 사용자 지정으로 여는 것은 데스크톱 클라이언트에서만 가능합니다.",
|
||||||
"delete_confirm": "첨부파일 '{{title}}'를 삭제하시겠습니까?",
|
"delete_confirm": "첨부파일 '{{title}}'를 삭제하시겠습니까?",
|
||||||
@@ -629,7 +629,7 @@
|
|||||||
"zoom_out": "축소",
|
"zoom_out": "축소",
|
||||||
"reset_zoom_level": "확대/축소 수준 초기화",
|
"reset_zoom_level": "확대/축소 수준 초기화",
|
||||||
"zoom_in": "확대",
|
"zoom_in": "확대",
|
||||||
"configure_launchbar": "런치바 구성",
|
"configure_launchbar": "실행 도구 모음 설정",
|
||||||
"show_shared_notes_subtree": "공유된 노트 하위 트리 표시",
|
"show_shared_notes_subtree": "공유된 노트 하위 트리 표시",
|
||||||
"advanced": "고급",
|
"advanced": "고급",
|
||||||
"open_dev_tools": "개발자 도구 열기",
|
"open_dev_tools": "개발자 도구 열기",
|
||||||
@@ -678,7 +678,7 @@
|
|||||||
"export_note": "노트 내보내기",
|
"export_note": "노트 내보내기",
|
||||||
"delete_note": "노트 삭제",
|
"delete_note": "노트 삭제",
|
||||||
"print_note": "노트 인쇄",
|
"print_note": "노트 인쇄",
|
||||||
"save_revision": "리비전 저장",
|
"save_revision": "수정 이력 저장",
|
||||||
"convert_into_attachment_failed": "노트 '{{title}}' 변환에 실패했습니다.",
|
"convert_into_attachment_failed": "노트 '{{title}}' 변환에 실패했습니다.",
|
||||||
"convert_into_attachment_successful": "노트 '{{title}}'가 첨부파일로 변환되었습니다.",
|
"convert_into_attachment_successful": "노트 '{{title}}'가 첨부파일로 변환되었습니다.",
|
||||||
"convert_into_attachment_prompt": "노트 '{{title}}'를 상위 노트의 첨부파일로 변환하시겠습니까?",
|
"convert_into_attachment_prompt": "노트 '{{title}}'를 상위 노트의 첨부파일로 변환하시겠습니까?",
|
||||||
@@ -692,13 +692,13 @@
|
|||||||
"inactive": "클릭해서 보호된 세션 시작"
|
"inactive": "클릭해서 보호된 세션 시작"
|
||||||
},
|
},
|
||||||
"revisions_button": {
|
"revisions_button": {
|
||||||
"note_revisions": "노트 리비전"
|
"note_revisions": "노트 수정 이력"
|
||||||
},
|
},
|
||||||
"update_available": {
|
"update_available": {
|
||||||
"update_available": "업데이트 사용 가능"
|
"update_available": "업데이트 사용 가능"
|
||||||
},
|
},
|
||||||
"note_launcher": {
|
"note_launcher": {
|
||||||
"this_launcher_doesnt_define_target_note": "이 런처는 대상 노트를 정의하지 않습니다."
|
"this_launcher_doesnt_define_target_note": "이 실행 도구에는 대상 노트가 지정되지 않았습니다."
|
||||||
},
|
},
|
||||||
"code_buttons": {
|
"code_buttons": {
|
||||||
"execute_button_title": "스크립트 실행",
|
"execute_button_title": "스크립트 실행",
|
||||||
@@ -772,9 +772,9 @@
|
|||||||
"file_size": "파일 크기",
|
"file_size": "파일 크기",
|
||||||
"download": "다운로드",
|
"download": "다운로드",
|
||||||
"open": "열기",
|
"open": "열기",
|
||||||
"upload_new_revision": "새 리비전 업로드",
|
"upload_new_revision": "새 버전 올리기",
|
||||||
"upload_success": "새 파일 리비전이 업로드되었습니다.",
|
"upload_success": "파일을 새 버전으로 교체했습니다.",
|
||||||
"upload_failed": "새 파일 리비전 업로드에 실패했습니다.",
|
"upload_failed": "파일의 새 버전을 올리지 못했습니다.",
|
||||||
"title": "파일"
|
"title": "파일"
|
||||||
},
|
},
|
||||||
"image_properties": {
|
"image_properties": {
|
||||||
@@ -784,9 +784,9 @@
|
|||||||
"download": "다운로드",
|
"download": "다운로드",
|
||||||
"open": "열기",
|
"open": "열기",
|
||||||
"copy_reference_to_clipboard": "참조를 클립보드에 복사",
|
"copy_reference_to_clipboard": "참조를 클립보드에 복사",
|
||||||
"upload_new_revision": "새 리비전 업로드",
|
"upload_new_revision": "새 버전 올리기",
|
||||||
"upload_success": "새 이미지 리비전이 업로드되었습니다.",
|
"upload_success": "이미지를 새 버전으로 교체했습니다.",
|
||||||
"upload_failed": "새 이미지 리비전 업로드에 실패했습니다: {{message}}",
|
"upload_failed": "이미지의 새 버전을 올리지 못했습니다: {{message}}",
|
||||||
"title": "이미지"
|
"title": "이미지"
|
||||||
},
|
},
|
||||||
"inherited_attribute_list": {
|
"inherited_attribute_list": {
|
||||||
@@ -799,7 +799,7 @@
|
|||||||
"modified": "수정일",
|
"modified": "수정일",
|
||||||
"type": "유형",
|
"type": "유형",
|
||||||
"note_size": "노트 크기",
|
"note_size": "노트 크기",
|
||||||
"note_size_info": "노트 크기는 이 노트의 저장 공간 요구량을 대략적으로 추정한 값입니다. 노트의 내용과 노트 리비전의 내용을 고려합니다.",
|
"note_size_info": "노트 크기는 이 노트의 저장 공간 요구량을 대략적으로 추정한 값입니다. 노트의 내용과 노트 수정 이력의 내용을 고려합니다.",
|
||||||
"calculate": "계산",
|
"calculate": "계산",
|
||||||
"subtree_size": "(하위 노트 {{count}}개 · 크기 {{size}})",
|
"subtree_size": "(하위 노트 {{count}}개 · 크기 {{size}})",
|
||||||
"title": "노트 정보"
|
"title": "노트 정보"
|
||||||
@@ -908,8 +908,8 @@
|
|||||||
"date_modified": "마지막 수정일",
|
"date_modified": "마지막 수정일",
|
||||||
"content_size": "노트 내용 크기",
|
"content_size": "노트 내용 크기",
|
||||||
"content_and_attachments_size": "첨부파일을 포함한 노트 내용 크기",
|
"content_and_attachments_size": "첨부파일을 포함한 노트 내용 크기",
|
||||||
"content_and_attachments_and_revisions_size": "첨부파일과 리비전을 포함한 노트 내용 크기",
|
"content_and_attachments_and_revisions_size": "첨부파일과 수정 이력을 포함한 노트 내용 크기",
|
||||||
"revision_count": "리비전 수",
|
"revision_count": "수정 이력 수",
|
||||||
"children_count": "하위 노트 수",
|
"children_count": "하위 노트 수",
|
||||||
"parent_count": "복제본 수",
|
"parent_count": "복제본 수",
|
||||||
"owned_label_count": "라벨 수",
|
"owned_label_count": "라벨 수",
|
||||||
@@ -1095,7 +1095,7 @@
|
|||||||
"max_width_unit": "픽셀",
|
"max_width_unit": "픽셀",
|
||||||
"apply_changes_description": "콘텐츠 너비 변경 사항을 적용하려면 다음을 클릭하세요",
|
"apply_changes_description": "콘텐츠 너비 변경 사항을 적용하려면 다음을 클릭하세요",
|
||||||
"reload_button": "프론트엔드 다시 로드",
|
"reload_button": "프론트엔드 다시 로드",
|
||||||
"reload_description": "외관 옵션의 변경 사항"
|
"reload_description": "모양 옵션의 변경 사항"
|
||||||
},
|
},
|
||||||
"native_title_bar": {
|
"native_title_bar": {
|
||||||
"title": "네이티브 제목 표시줄 (앱 재시작 필요)",
|
"title": "네이티브 제목 표시줄 (앱 재시작 필요)",
|
||||||
@@ -1120,7 +1120,7 @@
|
|||||||
"layout": "레이아웃",
|
"layout": "레이아웃",
|
||||||
"layout-vertical-title": "세로",
|
"layout-vertical-title": "세로",
|
||||||
"layout-horizontal-title": "가로",
|
"layout-horizontal-title": "가로",
|
||||||
"layout-vertical-description": "런처 바가 왼쪽에 있음 (기본값)",
|
"layout-vertical-description": "실행 도구 모음을 왼쪽에 배치합니다. 기본값입니다.",
|
||||||
"layout-horizontal-description": "실행 도구 모음이 탭 표시줄 아래에 배치됩니다. 탭 표시줄은 화면 전체 너비를 사용합니다."
|
"layout-horizontal-description": "실행 도구 모음이 탭 표시줄 아래에 배치됩니다. 탭 표시줄은 화면 전체 너비를 사용합니다."
|
||||||
},
|
},
|
||||||
"ai_llm": {
|
"ai_llm": {
|
||||||
@@ -1319,17 +1319,17 @@
|
|||||||
"deleted_notes_erased": "삭제된 노트가 완전히 삭제되었습니다."
|
"deleted_notes_erased": "삭제된 노트가 완전히 삭제되었습니다."
|
||||||
},
|
},
|
||||||
"revisions_snapshot_interval": {
|
"revisions_snapshot_interval": {
|
||||||
"note_revisions_snapshot_interval_title": "노트 리비전 스냅샷 간격",
|
"note_revisions_snapshot_interval_title": "수정 이력 자동 저장 간격",
|
||||||
"note_revisions_snapshot_description": "노트 리비전 스냅샷 간격은 노트의 새 리비전이 생성되기까지의 시간입니다. 자세한 내용은 <a href=\"https://triliumnext.github.io/Docs/Wiki/note-revisions.html\" class=\"external\">위키</a>를 참조하세요.",
|
"note_revisions_snapshot_description": "노트 수정 이력 스냅샷 간격은 노트의 새 수정 이력이 생성되기까지의 시간입니다. 자세한 내용은 <a href=\"https://triliumnext.github.io/Docs/Wiki/note-revisions.html\" class=\"external\">위키</a>를 참조하세요.",
|
||||||
"snapshot_time_interval_label": "노트 리비전 스냅샷 시간 간격:"
|
"snapshot_time_interval_label": "수정 이력 저장 간격:"
|
||||||
},
|
},
|
||||||
"revisions_snapshot_limit": {
|
"revisions_snapshot_limit": {
|
||||||
"note_revisions_snapshot_limit_title": "노트 리비전 스냅샷 제한",
|
"note_revisions_snapshot_limit_title": "수정 이력 보관 개수",
|
||||||
"note_revisions_snapshot_limit_description": "노트마다 보관할 이전 버전의 최대 개수입니다. -1은 개수 제한이 없다는 뜻이며 0은 이전 버전을 모두 삭제한다는 뜻입니다. 개별 노트에서는 #versioningLimit 라벨로 따로 지정할 수 있습니다.",
|
"note_revisions_snapshot_limit_description": "노트마다 보관할 이전 버전의 최대 개수입니다. -1은 개수 제한이 없다는 뜻이며 0은 이전 버전을 모두 삭제한다는 뜻입니다. 개별 노트에서는 #versioningLimit 라벨로 따로 지정할 수 있습니다.",
|
||||||
"snapshot_number_limit_label": "노트 리비전 스냅샷 수 제한:",
|
"snapshot_number_limit_label": "최대 보관 개수:",
|
||||||
"snapshot_number_limit_unit": "개",
|
"snapshot_number_limit_unit": "개",
|
||||||
"erase_excess_revision_snapshots": "초과 리비전 스냅샷 지금 삭제",
|
"erase_excess_revision_snapshots": "보관 개수를 초과한 수정 이력 삭제",
|
||||||
"erase_excess_revision_snapshots_prompt": "초과 리비전 스냅샷이 삭제되었습니다."
|
"erase_excess_revision_snapshots_prompt": "보관 개수를 초과한 수정 이력을 삭제했습니다."
|
||||||
},
|
},
|
||||||
"search_engine": {
|
"search_engine": {
|
||||||
"title": "검색 엔진",
|
"title": "검색 엔진",
|
||||||
@@ -1617,7 +1617,7 @@
|
|||||||
"mind-map": "마인드맵",
|
"mind-map": "마인드맵",
|
||||||
"file": "파일",
|
"file": "파일",
|
||||||
"image": "이미지",
|
"image": "이미지",
|
||||||
"launcher": "런처",
|
"launcher": "실행 도구",
|
||||||
"doc": "문서",
|
"doc": "문서",
|
||||||
"widget": "위젯",
|
"widget": "위젯",
|
||||||
"confirm-change": "노트 내용이 비어있지 않을 때 노트 유형을 변경하는 것은 권장하지 않습니다. 그래도 계속하시겠습니까?",
|
"confirm-change": "노트 내용이 비어있지 않을 때 노트 유형을 변경하는 것은 권장하지 않습니다. 그래도 계속하시겠습니까?",
|
||||||
@@ -1693,7 +1693,7 @@
|
|||||||
"search_not_executed": "아직 검색이 실행되지 않았습니다. 위의 \"검색\" 버튼을 클릭해서 결과를 확인하세요."
|
"search_not_executed": "아직 검색이 실행되지 않았습니다. 위의 \"검색\" 버튼을 클릭해서 결과를 확인하세요."
|
||||||
},
|
},
|
||||||
"spacer": {
|
"spacer": {
|
||||||
"configure_launchbar": "런치바 구성"
|
"configure_launchbar": "실행 도구 모음 설정"
|
||||||
},
|
},
|
||||||
"sql_result": {
|
"sql_result": {
|
||||||
"no_rows": "이 쿼리에 대해 반환된 행이 없습니다"
|
"no_rows": "이 쿼리에 대해 반환된 행이 없습니다"
|
||||||
@@ -1739,7 +1739,7 @@
|
|||||||
"copy_success": "클립보드에 복사되었습니다."
|
"copy_success": "클립보드에 복사되었습니다."
|
||||||
},
|
},
|
||||||
"entrypoints": {
|
"entrypoints": {
|
||||||
"note-revision-created": "노트 리비전이 생성되었습니다.",
|
"note-revision-created": "노트 수정 이력이 생성되었습니다.",
|
||||||
"note-executed": "노트가 실행되었습니다.",
|
"note-executed": "노트가 실행되었습니다.",
|
||||||
"sql-error": "SQL 쿼리 실행 중 오류 발생: {{message}}"
|
"sql-error": "SQL 쿼리 실행 중 오류 발생: {{message}}"
|
||||||
},
|
},
|
||||||
@@ -1764,16 +1764,16 @@
|
|||||||
"confirm_unhoisting": "'{{requestedNote}}' 노트는 현재 표시 중인 '{{hoistedNote}}' 하위 트리 밖에 있습니다. 표시 범위를 전체 트리로 넓혀서 노트를 여시겠습니까?"
|
"confirm_unhoisting": "'{{requestedNote}}' 노트는 현재 표시 중인 '{{hoistedNote}}' 하위 트리 밖에 있습니다. 표시 범위를 전체 트리로 넓혀서 노트를 여시겠습니까?"
|
||||||
},
|
},
|
||||||
"launcher_context_menu": {
|
"launcher_context_menu": {
|
||||||
"reset_launcher_confirm": "\"{{title}}\"을(를) 정말 재설정하시겠습니까? 이 노트(및 하위 노트)의 모든 데이터/설정이 사라지고 런처가 원래 위치로 돌아갑니다.",
|
"reset_launcher_confirm": "“{{title}}”을 초기화하시겠습니까? 이 노트와 하위 노트의 데이터 및 설정이 사라지고 실행 도구가 원래 위치로 돌아갑니다.",
|
||||||
"add-note-launcher": "노트 런처 추가",
|
"add-note-launcher": "노트 실행 도구 추가",
|
||||||
"add-script-launcher": "스크립트 런처 추가",
|
"add-script-launcher": "스크립트 실행 도구 추가",
|
||||||
"add-custom-widget": "사용자 지정 위젯 추가",
|
"add-custom-widget": "사용자 지정 위젯 추가",
|
||||||
"add-spacer": "여백 추가",
|
"add-spacer": "여백 추가",
|
||||||
"delete": "삭제 <kbd data-command=\"deleteNotes\"></kbd>",
|
"delete": "삭제 <kbd data-command=\"deleteNotes\"></kbd>",
|
||||||
"reset": "재설정",
|
"reset": "재설정",
|
||||||
"move-to-visible-launchers": "표시된 런처로 이동",
|
"move-to-visible-launchers": "표시할 실행 도구로 이동",
|
||||||
"move-to-available-launchers": "사용 가능한 런처로 이동",
|
"move-to-available-launchers": "사용 가능한 실행 도구로 이동",
|
||||||
"duplicate-launcher": "런처 복제 <kbd data-command=\"duplicateSubtree\">"
|
"duplicate-launcher": "실행 도구 복제 <kbd data-command=\"duplicateSubtree\">"
|
||||||
},
|
},
|
||||||
"editable-text": {
|
"editable-text": {
|
||||||
"auto-detect-language": "자동 감지됨"
|
"auto-detect-language": "자동 감지됨"
|
||||||
@@ -1914,7 +1914,7 @@
|
|||||||
"export_to_png": "다이어그램을 PNG로 내보낼 수 없습니다."
|
"export_to_png": "다이어그램을 PNG로 내보낼 수 없습니다."
|
||||||
},
|
},
|
||||||
"code_theme": {
|
"code_theme": {
|
||||||
"title": "외관",
|
"title": "모양",
|
||||||
"word_wrapping": "줄 바꿈",
|
"word_wrapping": "줄 바꿈",
|
||||||
"color-scheme": "색 구성표"
|
"color-scheme": "색 구성표"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
{
|
||||||
|
"version": 4,
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"noteId": "EW0u2LoAZTYv",
|
||||||
|
"oldTitle": "표 표시 (renderTable)",
|
||||||
|
"title": "표 표시 (renderTable)",
|
||||||
|
"oldContentSha256": "26e6f64bc522c1d9077082929c16a0f11ccdf33b935b3c3d3a288bd15dc3bf1d",
|
||||||
|
"content": "module.exports = counts => {\n const $statsTable = api.$container.find('.stats-table');\n \n addRow('합계', \n counts.reduce((acc, cur) => acc + cur.countNotDeleted, 0), \n counts.reduce((acc, cur) => acc + cur.countDeleted, 0)\n );\n \n for (const count of counts) {\n addRow(({\"text\":\"텍스트\",\"code\":\"코드\",\"file\":\"파일\",\"image\":\"이미지\",\"search\":\"저장된 검색\",\"book\":\"책\",\"relationMap\":\"관계도\",\"noteMap\":\"노트 지도\",\"render\":\"렌더링 노트\",\"mermaid\":\"Mermaid 도표\",\"canvas\":\"캔버스\",\"webView\":\"웹 보기\",\"mindMap\":\"마인드맵\",\"geoMap\":\"지리 지도\",\"doc\":\"도움말\",\"launcher\":\"실행 도구\"})[count.type] || count.type, count.countNotDeleted, count.countDeleted);\n }\n\n function addRow(type, countNotDeleted, countDeleted) {\n $statsTable.append(\n $(\"<tr>\")\n .append($(\"<td>\").text(type))\n .append($(\"<td>\").text(countNotDeleted))\n .append($(\"<td>\").text(countDeleted))\n );\n }\n}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"noteId": "WJaFVVj6QO1J",
|
||||||
|
"oldTitle": "자바스크립트 (js)",
|
||||||
|
"title": "자바스크립트 (js)",
|
||||||
|
"oldContentSha256": "47ea6714048328372870e445b73794e6710045412c5ecc6a6601f4b1ec41a04c",
|
||||||
|
"content": "const noteCounts = await api.runOnBackend(() => {\n return api.sql.getRows(`\n SELECT\n type,\n isDeleted,\n SUM(CASE WHEN isDeleted=0 THEN 1 ELSE 0 END) AS countNotDeleted,\n SUM(CASE WHEN isDeleted=1 THEN 1 ELSE 0 END) AS countDeleted\n FROM notes\n GROUP BY type\n ORDER BY countNotDeleted DESC`);\n});\n\nrenderPieChart(noteCounts.map(nc => {\n return {\n name: ({\"text\":\"텍스트\",\"code\":\"코드\",\"file\":\"파일\",\"image\":\"이미지\",\"search\":\"저장된 검색\",\"book\":\"책\",\"relationMap\":\"관계도\",\"noteMap\":\"노트 지도\",\"render\":\"렌더링 노트\",\"mermaid\":\"Mermaid 도표\",\"canvas\":\"캔버스\",\"webView\":\"웹 보기\",\"mindMap\":\"마인드맵\",\"geoMap\":\"지리 지도\",\"doc\":\"도움말\",\"launcher\":\"실행 도구\"})[nc.type] || nc.type,\n count: nc.countNotDeleted\n };\n}));\n\nrenderTable(noteCounts);"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"noteId": "ga590IKu7zmy",
|
||||||
|
"oldTitle": "속성 변경 처리 (attributechanged)",
|
||||||
|
"title": "속성 변경 처리 (attributechanged)",
|
||||||
|
"oldContentSha256": "6ee6ecf4954ce691d03e2e3f1cfa163652557800ed85a392dfc6c06a7371bc2f",
|
||||||
|
"content": "if (![\"task\", \"location\", \"tag\", \"todoDate\", \"doneDate\"].includes(api.originEntity.name)) {\n return;\n}\n\nconst tagRootNote = api.getNoteWithLabel('taskTagRoot');\nconst doneRootNote = api.getNoteWithLabel('taskDoneRoot');\nconst todoRootNote = api.getNoteWithLabel('taskTodoRoot');\n\nif (!tagRootNote || !doneRootNote || !todoRootNote) {\n console.log(\"태그 또는 완료 목록 또는 할 일 목록의 기준 노트를 찾을 수 없습니다.\");\n return;\n}\n\nconst note = api.originEntity.getNote();\n\nif (note.isDeleted) {\n return;\n}\n \nconst attributes = note.getAttributes();\n\nconst todoDate = note.getLabelValue('todoDate');\nconst doneDate = note.getLabelValue('doneDate');\n\nfunction isWithinExpectedRange(date) {\n if (!date) {\n return true;\n }\n \n const year = parseInt(date.substr(0, 4));\n \n return year >= 2010 && year < 2050;\n}\n\nif (!isWithinExpectedRange(todoDate) || !isWithinExpectedRange(doneDate)) {\n console.log(`날짜가 허용 범위를 벗어났습니다. 예정일: ${todoDate} / 완료일: ${doneDate}`);\n \n return;\n}\n\nconst isTaskDone = !!doneDate;\n\napi.toggleNoteInParent(isTaskDone, note.noteId, doneRootNote.noteId);\napi.toggleNoteInParent(!isTaskDone, note.noteId, todoRootNote.noteId);\n\nconst location = note.getLabelValue('location');\nconst locationRootNote = api.getNoteWithLabel('taskLocationRoot');\n\nreconcileAssignments(note, locationRootNote, location ? [location] : [], 'taskLocationNote', isTaskDone);\n\nconst tags = attributes.filter(attr => attr.type === 'label' && attr.name === 'tag').map(attr => attr.value);\n\nreconcileAssignments(note, tagRootNote, tags, 'taskTagNote', isTaskDone);\n\nnote.toggleLabel(isTaskDone, \"cssClass\", \"done\");\n\nconst doneTargetNoteId = isTaskDone ? api.getDayNote(doneDate).noteId : null;\napi.setNoteToParent(note.noteId, '완료', doneTargetNoteId);\n\nnote.toggleLabel(!isTaskDone, \"cssClass\", \"todo\");\n\nconst todoTargetNoteId = (!isTaskDone && todoDate) ? api.getDayNote(todoDate).noteId : null;\napi.setNoteToParent(note.noteId, '할 일', todoTargetNoteId);"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"attributeId": "teXYgLEYyqww",
|
||||||
|
"noteId": "7NfbiSmiVFyR",
|
||||||
|
"name": "label:weight",
|
||||||
|
"value": "promoted,number,single,precision=1,alias=체중",
|
||||||
|
"oldValue": "promoted,number,single,precision=1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributeId": "Gt3n5YmjWd92",
|
||||||
|
"noteId": "1A2pDj0rZWRk",
|
||||||
|
"name": "label:geolocation",
|
||||||
|
"value": "promoted,single,text,alias=위치 좌표",
|
||||||
|
"oldValue": "promoted,alias=Geolocation,single,text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributeId": "mNukzJtxNy9F",
|
||||||
|
"noteId": "PF0ofV83QNq9",
|
||||||
|
"name": "label:readingEnd",
|
||||||
|
"value": "promoted,single,date,alias=독서 종료일",
|
||||||
|
"oldValue": "promoted,single,date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributeId": "84Eslb7zduKM",
|
||||||
|
"noteId": "PF0ofV83QNq9",
|
||||||
|
"name": "label:readingStart",
|
||||||
|
"value": "promoted,single,date,alias=독서 시작일",
|
||||||
|
"oldValue": "promoted,single,date"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributeId": "oOhOmvlQA1l7",
|
||||||
|
"noteId": "PF0ofV83QNq9",
|
||||||
|
"name": "label:author",
|
||||||
|
"value": "promoted,single,text,alias=저자",
|
||||||
|
"oldValue": "promoted,single,text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributeId": "ovlzSwPHBESP",
|
||||||
|
"noteId": "PF0ofV83QNq9",
|
||||||
|
"name": "label:link",
|
||||||
|
"value": "promoted,single,url,alias=링크",
|
||||||
|
"oldValue": "promoted,single,url"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributeId": "1YTM1UQRQtnt",
|
||||||
|
"noteId": "rjbXo0acF0uE",
|
||||||
|
"name": "label:location",
|
||||||
|
"value": "promoted,text,single,alias=장소",
|
||||||
|
"oldValue": "promoted,text,single"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributeId": "KbYhsredrwOt",
|
||||||
|
"noteId": "rjbXo0acF0uE",
|
||||||
|
"name": "label:tag",
|
||||||
|
"value": "promoted,text,multi,alias=태그",
|
||||||
|
"oldValue": "promoted,text,multi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributeId": "UE1YHe51q07k",
|
||||||
|
"noteId": "rjbXo0acF0uE",
|
||||||
|
"name": "label:todoDate",
|
||||||
|
"value": "promoted,date,single,alias=예정일",
|
||||||
|
"oldValue": "promoted,date,single"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"attributeId": "PmBHwLv8Dtf3",
|
||||||
|
"noteId": "rjbXo0acF0uE",
|
||||||
|
"name": "label:doneDate",
|
||||||
|
"value": "promoted,date,single,alias=완료일",
|
||||||
|
"oldValue": "promoted,date,single"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"branches": [
|
||||||
|
{
|
||||||
|
"branchId": "E1e6RXYb7KDR_HlLfbi37EMDe",
|
||||||
|
"noteId": "HlLfbi37EMDe",
|
||||||
|
"prefix": "할 일",
|
||||||
|
"oldPrefix": "TODO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"branchId": "Zqbx4QzZLAw2_0za9R4spbuOD",
|
||||||
|
"noteId": "0za9R4spbuOD",
|
||||||
|
"prefix": "완료",
|
||||||
|
"oldPrefix": "DONE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"branchId": "GIfEhKrDNdnn_2JsGaSEmZSku",
|
||||||
|
"noteId": "2JsGaSEmZSku",
|
||||||
|
"prefix": "완료",
|
||||||
|
"oldPrefix": "DONE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"branchId": "GIfEhKrDNdnn_hpxIn2I2IdAJ",
|
||||||
|
"noteId": "hpxIn2I2IdAJ",
|
||||||
|
"prefix": "할 일",
|
||||||
|
"oldPrefix": "TODO"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"branchId": "m6DbuIecq3cC_BdeGRs0x9xSN",
|
||||||
|
"noteId": "BdeGRs0x9xSN",
|
||||||
|
"prefix": "2017년 11월 28일",
|
||||||
|
"oldPrefix": "28. 11. 2017"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"previousMainSha256": "2f94e1c483cfe83aa3a7689e087ed8ee28ceb051c3789917a3be21bef6f1aabc",
|
||||||
|
"files": {
|
||||||
|
"main.cjs": "2e5fad9489279e51688a0a6cab424b2e90d1aaa6a5034426a41d053cd11d487c",
|
||||||
|
"server.json": "5171b0bab55f0c260b9256c5164240526e679f324cfd4e23e7db9d22b78bf977",
|
||||||
|
"korean-phase4-pending.json": "6eaf94ee3801b736fe137bc1550087f5581623e10d2f3cdf72e43fc03a5160c1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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": "다중 인증",
|
||||||
|
"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": "펼치기"
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"previousMainSha256": "2e5fad9489279e51688a0a6cab424b2e90d1aaa6a5034426a41d053cd11d487c",
|
||||||
|
"originalPdfSha256": "0180798e74d32a745d76d8d76cb9ec76d924d903231966f65d89436dadac15c1",
|
||||||
|
"files": {
|
||||||
|
"main.cjs": "4b0d45a3722b5d4277a50d0e80054ee4ce8056c4a171a7f64b9ed2acbc088cae",
|
||||||
|
"demo-ko.pdf": "1141ea4fb9d619fd55d75d0bdcd6bbd5678b161633586764d0eadfc4b9235400"
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"previousMainSha256": "4b0d45a3722b5d4277a50d0e80054ee4ce8056c4a171a7f64b9ed2acbc088cae",
|
||||||
|
"previousTranslationSha256": "222ce7e5f6f3cfbbe848f784ddb5201e5a17f03f2ef095e1781992dbd7633724",
|
||||||
|
"files": {
|
||||||
|
"main.cjs": "b8c607ce3aaa551b1dc1f6f67c5011656084ebf3ba04e391ee49fb3aab349db2",
|
||||||
|
"translation.json": "e1d34275426dabf9aabf2f9b3ec880157946975f9f3f5a9035cf412ce02c9114"
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,412 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"key": "about.build_revision",
|
||||||
|
"before": "빌드 리비전:",
|
||||||
|
"after": "빌드 수정 이력:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.note_revisions",
|
||||||
|
"before": "노트 리비전",
|
||||||
|
"after": "노트 수정 이력"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.delete_all_revisions",
|
||||||
|
"before": "이 노트의 모든 리비전 삭제",
|
||||||
|
"after": "이 노트의 모든 수정 이력 삭제"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.delete_all_button",
|
||||||
|
"before": "모든 리비전 삭제",
|
||||||
|
"after": "모든 수정 이력 삭제"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.help_title",
|
||||||
|
"before": "노트 리비전 도움말",
|
||||||
|
"after": "노트 수정 이력 도움말"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.revision_last_edited",
|
||||||
|
"before": "이 리비전은 {{date}}에 마지막으로 편집되었습니다",
|
||||||
|
"after": "이 수정 이력은 {{date}}에 마지막으로 편집되었습니다"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.confirm_delete_all",
|
||||||
|
"before": "이 노트의 모든 리비전을 삭제하시겠습니까?",
|
||||||
|
"after": "이 노트의 모든 수정 이력을 삭제하시겠습니까?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.no_revisions",
|
||||||
|
"before": "아직 이 노트에 대한 리비전이 없습니다...",
|
||||||
|
"after": "아직 이 노트에 대한 수정 이력이 없습니다..."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.confirm_restore",
|
||||||
|
"before": "이 리비전을 복원하시겠습니까? 노트의 현재 제목과 내용이 이 리비전으로 덮어써집니다.",
|
||||||
|
"after": "이 수정 이력을 복원하시겠습니까? 노트의 현재 제목과 내용이 이 수정 이력으로 덮어써집니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.confirm_delete",
|
||||||
|
"before": "이 리비전을 삭제하시겠습니까?",
|
||||||
|
"after": "이 수정 이력을 삭제하시겠습니까?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.revisions_deleted",
|
||||||
|
"before": "노트 리비전이 삭제되었습니다.",
|
||||||
|
"after": "노트 수정 이력이 삭제되었습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.revision_restored",
|
||||||
|
"before": "노트 리비전이 복원되었습니다.",
|
||||||
|
"after": "노트 수정 이력이 복원되었습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.revision_deleted",
|
||||||
|
"before": "노트 리비전이 삭제되었습니다.",
|
||||||
|
"after": "노트 수정 이력이 삭제되었습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.snapshot_interval",
|
||||||
|
"before": "노트 리비전 스냅샷 간격: {{seconds}}초.",
|
||||||
|
"after": "노트 수정 이력 스냅샷 간격: {{seconds}}초."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.maximum_revisions",
|
||||||
|
"before": "노트 리비전 스냅샷 제한: {{number}}.",
|
||||||
|
"after": "노트 수정 이력 스냅샷 제한: {{number}}."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.settings",
|
||||||
|
"before": "노트 리비전 설정",
|
||||||
|
"after": "노트 수정 이력 설정"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "delete_revisions.delete_note_revisions",
|
||||||
|
"before": "노트 리비전 삭제",
|
||||||
|
"after": "노트 수정 이력 삭제"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "attachments_actions.upload_new_revision",
|
||||||
|
"before": "새 리비전 업로드",
|
||||||
|
"after": "새 수정 이력 업로드"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "attachments_actions.upload_success",
|
||||||
|
"before": "새 첨부파일 리비전이 업로드되었습니다.",
|
||||||
|
"after": "새 첨부파일 수정 이력이 업로드되었습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "attachments_actions.upload_failed",
|
||||||
|
"before": "새 첨부파일 리비전 업로드에 실패했습니다.",
|
||||||
|
"after": "새 첨부파일 수정 이력 업로드에 실패했습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "global_menu.configure_launchbar",
|
||||||
|
"before": "런치바 구성",
|
||||||
|
"after": "실행 도구 모음 구성"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "note_actions.save_revision",
|
||||||
|
"before": "리비전 저장",
|
||||||
|
"after": "수정 이력 저장"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_button.note_revisions",
|
||||||
|
"before": "노트 리비전",
|
||||||
|
"after": "노트 수정 이력"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "note_launcher.this_launcher_doesnt_define_target_note",
|
||||||
|
"before": "이 런처는 대상 노트를 정의하지 않습니다.",
|
||||||
|
"after": "이 실행 도구는 대상 노트를 정의하지 않습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "file_properties.upload_new_revision",
|
||||||
|
"before": "새 리비전 업로드",
|
||||||
|
"after": "새 수정 이력 업로드"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "file_properties.upload_success",
|
||||||
|
"before": "새 파일 리비전이 업로드되었습니다.",
|
||||||
|
"after": "새 파일 수정 이력이 업로드되었습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "file_properties.upload_failed",
|
||||||
|
"before": "새 파일 리비전 업로드에 실패했습니다.",
|
||||||
|
"after": "새 파일 수정 이력 업로드에 실패했습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "image_properties.upload_new_revision",
|
||||||
|
"before": "새 리비전 업로드",
|
||||||
|
"after": "새 수정 이력 업로드"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "image_properties.upload_success",
|
||||||
|
"before": "새 이미지 리비전이 업로드되었습니다.",
|
||||||
|
"after": "새 이미지 수정 이력이 업로드되었습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "image_properties.upload_failed",
|
||||||
|
"before": "새 이미지 리비전 업로드에 실패했습니다: {{message}}",
|
||||||
|
"after": "새 이미지 수정 이력 업로드에 실패했습니다: {{message}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "note_info_widget.note_size_info",
|
||||||
|
"before": "노트 크기는 이 노트의 저장 공간 요구량을 대략적으로 추정한 값입니다. 노트의 내용과 노트 리비전의 내용을 고려합니다.",
|
||||||
|
"after": "노트 크기는 이 노트의 저장 공간 요구량을 대략적으로 추정한 값입니다. 노트의 내용과 노트 수정 이력의 내용을 고려합니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "order_by.content_and_attachments_and_revisions_size",
|
||||||
|
"before": "첨부파일과 리비전을 포함한 노트 내용 크기",
|
||||||
|
"after": "첨부파일과 수정 이력을 포함한 노트 내용 크기"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "order_by.revision_count",
|
||||||
|
"before": "리비전 수",
|
||||||
|
"after": "수정 이력 수"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "max_content_width.reload_description",
|
||||||
|
"before": "외관 옵션의 변경 사항",
|
||||||
|
"after": "모양 옵션의 변경 사항"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "theme.layout-vertical-description",
|
||||||
|
"before": "런처 바가 왼쪽에 있음 (기본값)",
|
||||||
|
"after": "실행 도구 모음가 왼쪽에 있음 (기본값)"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_interval.note_revisions_snapshot_interval_title",
|
||||||
|
"before": "노트 리비전 스냅샷 간격",
|
||||||
|
"after": "노트 수정 이력 스냅샷 간격"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_interval.note_revisions_snapshot_description",
|
||||||
|
"before": "노트 리비전 스냅샷 간격은 노트의 새 리비전이 생성되기까지의 시간입니다. 자세한 내용은 <a href=\"https://triliumnext.github.io/Docs/Wiki/note-revisions.html\" class=\"external\">위키</a>를 참조하세요.",
|
||||||
|
"after": "노트 수정 이력 스냅샷 간격은 노트의 새 수정 이력이 생성되기까지의 시간입니다. 자세한 내용은 <a href=\"https://triliumnext.github.io/Docs/Wiki/note-revisions.html\" class=\"external\">위키</a>를 참조하세요."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_interval.snapshot_time_interval_label",
|
||||||
|
"before": "노트 리비전 스냅샷 시간 간격:",
|
||||||
|
"after": "노트 수정 이력 스냅샷 시간 간격:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_limit.note_revisions_snapshot_limit_title",
|
||||||
|
"before": "노트 리비전 스냅샷 제한",
|
||||||
|
"after": "노트 수정 이력 스냅샷 제한"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_limit.snapshot_number_limit_label",
|
||||||
|
"before": "노트 리비전 스냅샷 수 제한:",
|
||||||
|
"after": "노트 수정 이력 스냅샷 수 제한:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_limit.erase_excess_revision_snapshots",
|
||||||
|
"before": "초과 리비전 스냅샷 지금 삭제",
|
||||||
|
"after": "초과 수정 이력 스냅샷 지금 삭제"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_limit.erase_excess_revision_snapshots_prompt",
|
||||||
|
"before": "초과 리비전 스냅샷이 삭제되었습니다.",
|
||||||
|
"after": "초과 수정 이력 스냅샷이 삭제되었습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "note_types.launcher",
|
||||||
|
"before": "런처",
|
||||||
|
"after": "실행 도구"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "spacer.configure_launchbar",
|
||||||
|
"before": "런치바 구성",
|
||||||
|
"after": "실행 도구 모음 구성"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "entrypoints.note-revision-created",
|
||||||
|
"before": "노트 리비전이 생성되었습니다.",
|
||||||
|
"after": "노트 수정 이력이 생성되었습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "launcher_context_menu.reset_launcher_confirm",
|
||||||
|
"before": "\"{{title}}\"을(를) 정말 재설정하시겠습니까? 이 노트(및 하위 노트)의 모든 데이터/설정이 사라지고 런처가 원래 위치로 돌아갑니다.",
|
||||||
|
"after": "\"{{title}}\"을(를) 정말 재설정하시겠습니까? 이 노트(및 하위 노트)의 모든 데이터/설정이 사라지고 실행 도구가 원래 위치로 돌아갑니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "launcher_context_menu.add-note-launcher",
|
||||||
|
"before": "노트 런처 추가",
|
||||||
|
"after": "노트 실행 도구 추가"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "launcher_context_menu.add-script-launcher",
|
||||||
|
"before": "스크립트 런처 추가",
|
||||||
|
"after": "스크립트 실행 도구 추가"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "launcher_context_menu.move-to-visible-launchers",
|
||||||
|
"before": "표시된 런처로 이동",
|
||||||
|
"after": "표시된 실행 도구로 이동"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "launcher_context_menu.move-to-available-launchers",
|
||||||
|
"before": "사용 가능한 런처로 이동",
|
||||||
|
"after": "사용 가능한 실행 도구로 이동"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "launcher_context_menu.duplicate-launcher",
|
||||||
|
"before": "런처 복제 <kbd data-command=\"duplicateSubtree\">",
|
||||||
|
"after": "실행 도구 복제 <kbd data-command=\"duplicateSubtree\">"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "code_theme.title",
|
||||||
|
"before": "외관",
|
||||||
|
"after": "모양"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "about.build_revision",
|
||||||
|
"before": "빌드 수정 이력:",
|
||||||
|
"after": "빌드 버전:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.note_revisions",
|
||||||
|
"before": "노트 수정 이력",
|
||||||
|
"after": "노트 수정 이력"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.revision_last_edited",
|
||||||
|
"before": "이 수정 이력은 {{date}}에 마지막으로 편집되었습니다",
|
||||||
|
"after": "이 버전은 {{date}}에 마지막으로 수정되었습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.no_revisions",
|
||||||
|
"before": "아직 이 노트에 대한 수정 이력이 없습니다...",
|
||||||
|
"after": "아직 저장된 수정 이력이 없습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.confirm_restore",
|
||||||
|
"before": "이 수정 이력을 복원하시겠습니까? 노트의 현재 제목과 내용이 이 수정 이력으로 덮어써집니다.",
|
||||||
|
"after": "이 버전으로 복원하시겠습니까? 현재 제목과 본문이 선택한 버전의 내용으로 바뀝니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.confirm_delete",
|
||||||
|
"before": "이 수정 이력을 삭제하시겠습니까?",
|
||||||
|
"after": "이 수정 이력을 삭제하시겠습니까?"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.revision_restored",
|
||||||
|
"before": "노트 수정 이력이 복원되었습니다.",
|
||||||
|
"after": "선택한 버전으로 복원했습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.snapshot_interval",
|
||||||
|
"before": "노트 수정 이력 스냅샷 간격: {{seconds}}초.",
|
||||||
|
"after": "수정 이력 자동 저장 간격: {{seconds}}초"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions.maximum_revisions",
|
||||||
|
"before": "노트 수정 이력 스냅샷 제한: {{number}}.",
|
||||||
|
"after": "보관할 수정 이력 수: {{number}}개"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "attachments_actions.upload_new_revision",
|
||||||
|
"before": "새 수정 이력 업로드",
|
||||||
|
"after": "새 버전 올리기"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "attachments_actions.upload_success",
|
||||||
|
"before": "새 첨부파일 수정 이력이 업로드되었습니다.",
|
||||||
|
"after": "첨부 파일을 새 버전으로 교체했습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "attachments_actions.upload_failed",
|
||||||
|
"before": "새 첨부파일 수정 이력 업로드에 실패했습니다.",
|
||||||
|
"after": "첨부 파일의 새 버전을 올리지 못했습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "file_properties.upload_new_revision",
|
||||||
|
"before": "새 수정 이력 업로드",
|
||||||
|
"after": "새 버전 올리기"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "file_properties.upload_success",
|
||||||
|
"before": "새 파일 수정 이력이 업로드되었습니다.",
|
||||||
|
"after": "파일을 새 버전으로 교체했습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "file_properties.upload_failed",
|
||||||
|
"before": "새 파일 수정 이력 업로드에 실패했습니다.",
|
||||||
|
"after": "파일의 새 버전을 올리지 못했습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "image_properties.upload_new_revision",
|
||||||
|
"before": "새 수정 이력 업로드",
|
||||||
|
"after": "새 버전 올리기"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "image_properties.upload_success",
|
||||||
|
"before": "새 이미지 수정 이력이 업로드되었습니다.",
|
||||||
|
"after": "이미지를 새 버전으로 교체했습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "image_properties.upload_failed",
|
||||||
|
"before": "새 이미지 수정 이력 업로드에 실패했습니다: {{message}}",
|
||||||
|
"after": "이미지의 새 버전을 올리지 못했습니다: {{message}}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "global_menu.configure_launchbar",
|
||||||
|
"before": "실행 도구 모음 구성",
|
||||||
|
"after": "실행 도구 모음 설정"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "spacer.configure_launchbar",
|
||||||
|
"before": "실행 도구 모음 구성",
|
||||||
|
"after": "실행 도구 모음 설정"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "note_launcher.this_launcher_doesnt_define_target_note",
|
||||||
|
"before": "이 실행 도구는 대상 노트를 정의하지 않습니다.",
|
||||||
|
"after": "이 실행 도구에는 대상 노트가 지정되지 않았습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_interval.note_revisions_snapshot_interval_title",
|
||||||
|
"before": "노트 수정 이력 스냅샷 간격",
|
||||||
|
"after": "수정 이력 자동 저장 간격"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_interval.snapshot_time_interval_label",
|
||||||
|
"before": "노트 수정 이력 스냅샷 시간 간격:",
|
||||||
|
"after": "수정 이력 저장 간격:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_limit.note_revisions_snapshot_limit_title",
|
||||||
|
"before": "노트 수정 이력 스냅샷 제한",
|
||||||
|
"after": "수정 이력 보관 개수"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_limit.snapshot_number_limit_label",
|
||||||
|
"before": "노트 수정 이력 스냅샷 수 제한:",
|
||||||
|
"after": "최대 보관 개수:"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_limit.erase_excess_revision_snapshots",
|
||||||
|
"before": "초과 수정 이력 스냅샷 지금 삭제",
|
||||||
|
"after": "보관 개수를 초과한 수정 이력 삭제"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "revisions_snapshot_limit.erase_excess_revision_snapshots_prompt",
|
||||||
|
"before": "초과 수정 이력 스냅샷이 삭제되었습니다.",
|
||||||
|
"after": "보관 개수를 초과한 수정 이력을 삭제했습니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "theme.layout-vertical-description",
|
||||||
|
"before": "실행 도구 모음가 왼쪽에 있음 (기본값)",
|
||||||
|
"after": "실행 도구 모음을 왼쪽에 배치합니다. 기본값입니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "launcher_context_menu.reset_launcher_confirm",
|
||||||
|
"before": "\"{{title}}\"을(를) 정말 재설정하시겠습니까? 이 노트(및 하위 노트)의 모든 데이터/설정이 사라지고 실행 도구가 원래 위치로 돌아갑니다.",
|
||||||
|
"after": "“{{title}}”을 초기화하시겠습니까? 이 노트와 하위 노트의 데이터 및 설정이 사라지고 실행 도구가 원래 위치로 돌아갑니다."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "launcher_context_menu.move-to-visible-launchers",
|
||||||
|
"before": "표시된 실행 도구로 이동",
|
||||||
|
"after": "표시할 실행 도구로 이동"
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from xml.sax.saxutils import escape
|
||||||
|
from reportlab.pdfgen import canvas
|
||||||
|
from reportlab.platypus import SimpleDocTemplate,Paragraph,Spacer,KeepTogether
|
||||||
|
from reportlab.lib.styles import ParagraphStyle
|
||||||
|
from reportlab.lib.enums import TA_CENTER,TA_JUSTIFY
|
||||||
|
from reportlab.lib.colors import HexColor
|
||||||
|
from reportlab.pdfbase import pdfmetrics
|
||||||
|
from reportlab.pdfbase.ttfonts import TTFont
|
||||||
|
from reportlab.lib.pagesizes import A4
|
||||||
|
from pypdf import PdfReader
|
||||||
|
base=Path('work/trilium');out=Path('output/pdf');out.mkdir(parents=True,exist_ok=True)
|
||||||
|
pdfmetrics.registerFont(TTFont('Korean','C:/Windows/Fonts/malgun.ttf'))
|
||||||
|
pdfmetrics.registerFont(TTFont('KoreanBold','C:/Windows/Fonts/malgunbd.ttf'))
|
||||||
|
body=ParagraphStyle('body',fontName='Korean',fontSize=10.5,leading=18,spaceAfter=9,wordWrap='CJK',textColor=HexColor('#20252c'),allowWidows=0,allowOrphans=0)
|
||||||
|
title=ParagraphStyle('title',parent=body,fontName='KoreanBold',fontSize=24,leading=32,spaceAfter=12)
|
||||||
|
author=ParagraphStyle('author',parent=body,fontSize=12,leading=19,spaceAfter=24)
|
||||||
|
section=ParagraphStyle('section',parent=body,alignment=TA_CENTER,spaceBefore=18,spaceAfter=18,textColor=HexColor('#697386'),keepWithNext=True)
|
||||||
|
parts=(base/'last-question.ko.txt').read_text(encoding='utf8').replace('제로이드','제로드').split('\n\n')
|
||||||
|
# First block contains title and author; all subsequent paragraphs follow the source narrative.
|
||||||
|
story=[Paragraph('마지막 질문',title),Paragraph('아이작 아시모프',author)]
|
||||||
|
for block in parts[1:]:
|
||||||
|
text=block.strip()
|
||||||
|
if not text:continue
|
||||||
|
story.append(Paragraph(escape(text),section if text=='* * *' else body))
|
||||||
|
def footer(c,doc):
|
||||||
|
c.saveState();c.setFont('Korean',8);c.setFillColor(HexColor('#697386'))
|
||||||
|
c.drawString(48,29,'마지막 질문 · 아이작 아시모프')
|
||||||
|
c.drawRightString(A4[0]-48,29,str(doc.page));c.restoreState()
|
||||||
|
target=out/'마지막-질문-한국어.pdf'
|
||||||
|
doc=SimpleDocTemplate(str(target),pagesize=A4,rightMargin=48,leftMargin=48,topMargin=48,bottomMargin=49,title='마지막 질문',author='아이작 아시모프',subject='Trilium 기본 제공 예제의 한국어 번역')
|
||||||
|
paragraphs=len(story)
|
||||||
|
doc.build(story,onFirstPage=footer,onLaterPages=footer)
|
||||||
|
r=PdfReader(str(target));text='\n'.join(p.extract_text() for p in r.pages)
|
||||||
|
assert '빛이 있으라' in text and '작품' in text
|
||||||
|
assert '\ufffd' not in text
|
||||||
|
print({'file':str(target),'pages':len(r.pages),'bytes':target.stat().st_size,'paragraphs':paragraphs})
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import fs from 'node:fs';import crypto from 'node:crypto';
|
||||||
|
const b='work/trilium',out=b+'/phase4';fs.mkdirSync(out,{recursive:true});
|
||||||
|
const data=JSON.parse(fs.readFileSync(b+'/phase4-inspect/data.json','utf8'));
|
||||||
|
const hash=s=>crypto.createHash('sha256').update(s).digest('hex');
|
||||||
|
const names={text:'텍스트',code:'코드',file:'파일',image:'이미지',search:'저장된 검색',book:'책',relationMap:'관계도',noteMap:'노트 지도',render:'렌더링 노트',mermaid:'Mermaid 도표',canvas:'캔버스',webView:'웹 보기',mindMap:'마인드맵',geoMap:'지리 지도',doc:'도움말',launcher:'실행 도구'};
|
||||||
|
const changes=data.notes.filter(n=>n.content).map(n=>{
|
||||||
|
let content=n.content;
|
||||||
|
if(n.noteId==='EW0u2LoAZTYv')content=content.replace('addRow(count.type,','addRow(('+JSON.stringify(names)+')[count.type] || count.type,');
|
||||||
|
if(n.noteId==='WJaFVVj6QO1J')content=content.replace('name: nc.type,','name: ('+JSON.stringify(names)+')[nc.type] || nc.type,');
|
||||||
|
if(n.noteId==='ga590IKu7zmy')content=content.replace("'DONE'","'완료'").replace("'TODO'","'할 일'");
|
||||||
|
if(content===n.content)throw Error('Unchanged '+n.noteId);
|
||||||
|
return {noteId:n.noteId,oldTitle:n.title,title:n.title,oldContentSha256:hash(n.content),content};
|
||||||
|
});
|
||||||
|
const aliases={weight:'체중',geolocation:'위치 좌표',readingEnd:'독서 종료일',readingStart:'독서 시작일',author:'저자',link:'링크',location:'장소',tag:'태그',todoDate:'예정일',doneDate:'완료일'};
|
||||||
|
const attributes=data.attributes.map(a=>({...a,oldValue:a.value,value:a.value.replace(/,alias=[^,]*/,'')+',alias='+aliases[a.name.slice(6)]}));
|
||||||
|
const prefixes={TODO:'할 일',DONE:'완료','28. 11. 2017':'2017년 11월 28일'};
|
||||||
|
const branches=data.branches.map(r=>({...r,oldPrefix:r.prefix,prefix:prefixes[r.prefix]}));
|
||||||
|
fs.writeFileSync(out+'/korean-phase4-pending.json',JSON.stringify({version:4,changes,attributes,branches},null,2));
|
||||||
|
const known={'런치바 템플릿':'실행 도구 템플릿','기본 추상 런처':'실행 도구 기본 템플릿','명령 런처':'명령 실행 도구','노트 런처':'노트 실행 도구','스크립트 런처':'스크립트 실행 도구','런치바':'실행 도구 모음','사용 가능한 런처':'사용 가능한 실행 도구','표시된 런처':'표시할 실행 도구','캘린더':'달력','최근 변경 내역':'최근 변경 사항','노트와 채팅':'노트와 대화','옵션':'설정','외관':'모양','MFA':'다중 인증','사용자 가이드':'사용자 안내서','사용자 숨김':'사용자 숨김 영역','Mobile Launch Bar':'모바일 실행 도구 모음'};
|
||||||
|
const server=JSON.parse(fs.readFileSync(b+'/server.ko.json','utf8'));
|
||||||
|
for(const [key,value]of Object.entries(server['hidden-subtree']))if(known[value])server['hidden-subtree'][key]=known[value];
|
||||||
|
fs.writeFileSync(out+'/server.json',JSON.stringify(server,null,2)+'\n');
|
||||||
|
let main=fs.readFileSync(b+'/phase3/main.cjs','utf8');const oldmain=main;
|
||||||
|
const replace=(from,to)=>{if(main.split(from).length!==2)throw Error('Patch point mismatch '+from);main=main.replace(from,to);};
|
||||||
|
replace('jg=`assets/v${CR.version}-ko-20260913-r3`','jg=`assets/v${CR.version}-ko-20260913-r4`');
|
||||||
|
replace('title:"Mobile Launch Bar"','title:"모바일 실행 도구 모음"');
|
||||||
|
replace('(r.restoreNames||n.noteId.startsWith("_help_"))&&n.title!==t.title','(r.restoreNames||n.noteId.startsWith("_help_")||('+JSON.stringify(known)+')[n.title]===t.title)&&n.title!==t.title');
|
||||||
|
replace('triliumApplyKoreanNotes()})','triliumApplyKoreanNotes();triliumApplyKoreanPhase4()})');
|
||||||
|
const hook=`
|
||||||
|
function triliumApplyKoreanPhase4(){
|
||||||
|
const fs=require('fs'),crypto=require('crypto'),file='/home/node/trilium-data/korean-phase4-pending.json';
|
||||||
|
if(!fs.existsSync(file))return;
|
||||||
|
const plan=JSON.parse(fs.readFileSync(file,'utf8'));
|
||||||
|
if(plan.version!==4)throw Error('Invalid Korean phase 4 migration');
|
||||||
|
const hash=s=>crypto.createHash('sha256').update(s).digest('hex');
|
||||||
|
de.transactional(()=>{
|
||||||
|
for(const c of plan.changes){const n=J.getNoteOrThrow(c.noteId);if(n.isDeleted||n.isProtected||n.title!==c.oldTitle||(n.getContent()!==c.content&&hash(n.getContent())!==c.oldContentSha256))throw Error('Note conflict '+c.noteId);}
|
||||||
|
for(const c of plan.attributes){const a=J.getAttributeOrThrow(c.attributeId);if(a.isDeleted||a.noteId!==c.noteId||a.name!==c.name||(a.value!==c.oldValue&&a.value!==c.value))throw Error('Attribute conflict '+c.attributeId);}
|
||||||
|
for(const c of plan.branches){const a=J.getBranchOrThrow(c.branchId);if(a.isDeleted||a.noteId!==c.noteId||(a.prefix!==c.oldPrefix&&a.prefix!==c.prefix))throw Error('Branch conflict '+c.branchId);}
|
||||||
|
for(const c of plan.changes){const n=J.getNoteOrThrow(c.noteId);if(n.getContent()===c.content)continue;const rev=new Mk({noteId:n.noteId,title:n.title,type:n.type,mime:n.mime,isProtected:n.isProtected,utcDateLastEdited:n.utcDateModified,utcDateCreated:kr.utcNowDateTime(),utcDateModified:kr.utcNowDateTime(),dateLastEdited:n.dateModified,dateCreated:kr.localNowDateTime()},true);rev.save();rev.setContent(n.getContent());n.setContent(c.content);}
|
||||||
|
for(const c of plan.attributes){const a=J.getAttributeOrThrow(c.attributeId);if(a.value!==c.value){a.value=c.value;a.save();}}
|
||||||
|
for(const c of plan.branches){const a=J.getBranchOrThrow(c.branchId);if(a.prefix!==c.prefix){a.prefix=c.prefix;a.save();}}
|
||||||
|
});
|
||||||
|
fs.renameSync(file,file+'.applied-'+Date.now());console.log('KOREAN_PHASE4 '+JSON.stringify({notes:plan.changes.length,attributes:plan.attributes.length,branches:plan.branches.length}));
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
fs.writeFileSync(out+'/main.cjs',hook+main);
|
||||||
|
fs.writeFileSync(out+'/manifest.json',JSON.stringify({previousMainSha256:hash(oldmain),files:Object.fromEntries(['main.cjs','server.json','korean-phase4-pending.json'].map(n=>[n,hash(fs.readFileSync(out+'/'+n))]))},null,2));
|
||||||
|
console.log({notes:changes.length,attributes:attributes.length,branches:branches.length});
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import fs from 'node:fs';import crypto from 'node:crypto';
|
||||||
|
const b='work/trilium',out=b+'/phase5';fs.mkdirSync(out,{recursive:true});
|
||||||
|
const hash=s=>crypto.createHash('sha256').update(s).digest('hex');
|
||||||
|
const pdf=fs.readFileSync('output/pdf/마지막-질문-한국어.pdf');fs.writeFileSync(out+'/demo-ko.pdf',pdf);
|
||||||
|
const original=fs.readFileSync(b+'/phase4-inspect/demo.pdf');
|
||||||
|
let main=fs.readFileSync(b+'/phase4/main.cjs','utf8');const oldmain=main;
|
||||||
|
const marker='triliumApplyKoreanPhase4()})';if(main.split(marker).length!==2)throw Error('Startup mismatch');
|
||||||
|
main=main.replace(marker,'triliumApplyKoreanPhase4();triliumApplyKoreanPdf()})');
|
||||||
|
const hook=`
|
||||||
|
function triliumApplyKoreanPdf(){
|
||||||
|
const fs=require('fs'),crypto=require('crypto'),file='/home/node/trilium-data/korean-demo-pdf.pending';
|
||||||
|
if(!fs.existsSync(file))return;
|
||||||
|
const content=fs.readFileSync(file),hash=s=>crypto.createHash('sha256').update(s).digest('hex');
|
||||||
|
if(hash(content)!=='${hash(pdf)}')throw Error('Invalid Korean PDF');
|
||||||
|
de.transactional(()=>{
|
||||||
|
const n=J.getNoteOrThrow('swKGGdlek7o6'),old=n.getContent();
|
||||||
|
if(n.isDeleted||n.isProtected||n.mime!=='application/pdf')throw Error('PDF note mismatch');
|
||||||
|
if(hash(old)===hash(content))return;
|
||||||
|
if(hash(old)!=='${hash(original)}')throw Error('PDF content changed');
|
||||||
|
const rev=new Mk({noteId:n.noteId,title:n.title,type:n.type,mime:n.mime,isProtected:n.isProtected,utcDateLastEdited:n.utcDateModified,utcDateCreated:kr.utcNowDateTime(),utcDateModified:kr.utcNowDateTime(),dateLastEdited:n.dateModified,dateCreated:kr.localNowDateTime()},true);
|
||||||
|
rev.save();rev.setContent(old);n.setContent(content);
|
||||||
|
});
|
||||||
|
fs.renameSync(file,file+'.applied-'+Date.now());console.log('KOREAN_DEMO_PDF_APPLIED');
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
fs.writeFileSync(out+'/main.cjs',hook+main);
|
||||||
|
fs.writeFileSync(out+'/manifest.json',JSON.stringify({previousMainSha256:hash(oldmain),originalPdfSha256:hash(original),files:{'main.cjs':hash(hook+main),'demo-ko.pdf':hash(pdf)}},null,2));
|
||||||
|
console.log({pdfBytes:pdf.length});
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import fs from 'node:fs';import crypto from 'node:crypto';
|
||||||
|
const b='work/trilium',out=b+'/phase6';fs.mkdirSync(out,{recursive:true});
|
||||||
|
const source=JSON.parse(fs.readFileSync(b+'/release/translation.json','utf8'));
|
||||||
|
const translated=structuredClone(source),changes=[];
|
||||||
|
function walk(o,p=''){for(const[k,v]of Object.entries(o)){if(typeof v==='object'&&v)walk(v,p+k+'.');else if(typeof v==='string'){
|
||||||
|
let next=v.replaceAll('런처 바','실행 도구 모음').replaceAll('런치바','실행 도구 모음').replaceAll('런처','실행 도구').replaceAll('리비전','수정 이력').replaceAll('외관','모양');
|
||||||
|
if(next!==v){changes.push({key:p+k,before:v,after:next});o[k]=next;}
|
||||||
|
}}}
|
||||||
|
walk(translated);
|
||||||
|
const overrides={
|
||||||
|
'about.build_revision':'빌드 버전:',
|
||||||
|
'revisions.note_revisions':'노트 수정 이력',
|
||||||
|
'revisions.revision_last_edited':'이 버전은 {{date}}에 마지막으로 수정되었습니다.',
|
||||||
|
'revisions.no_revisions':'아직 저장된 수정 이력이 없습니다.',
|
||||||
|
'revisions.confirm_restore':'이 버전으로 복원하시겠습니까? 현재 제목과 본문이 선택한 버전의 내용으로 바뀝니다.',
|
||||||
|
'revisions.confirm_delete':'이 수정 이력을 삭제하시겠습니까?',
|
||||||
|
'revisions.revision_restored':'선택한 버전으로 복원했습니다.',
|
||||||
|
'revisions.snapshot_interval':'수정 이력 자동 저장 간격: {{seconds}}초',
|
||||||
|
'revisions.maximum_revisions':'보관할 수정 이력 수: {{number}}개',
|
||||||
|
'attachments_actions.upload_new_revision':'새 버전 올리기',
|
||||||
|
'attachments_actions.upload_success':'첨부 파일을 새 버전으로 교체했습니다.',
|
||||||
|
'attachments_actions.upload_failed':'첨부 파일의 새 버전을 올리지 못했습니다.',
|
||||||
|
'file_properties.upload_new_revision':'새 버전 올리기',
|
||||||
|
'file_properties.upload_success':'파일을 새 버전으로 교체했습니다.',
|
||||||
|
'file_properties.upload_failed':'파일의 새 버전을 올리지 못했습니다.',
|
||||||
|
'image_properties.upload_new_revision':'새 버전 올리기',
|
||||||
|
'image_properties.upload_success':'이미지를 새 버전으로 교체했습니다.',
|
||||||
|
'image_properties.upload_failed':'이미지의 새 버전을 올리지 못했습니다: {{message}}',
|
||||||
|
'global_menu.configure_launchbar':'실행 도구 모음 설정',
|
||||||
|
'spacer.configure_launchbar':'실행 도구 모음 설정',
|
||||||
|
'note_launcher.this_launcher_doesnt_define_target_note':'이 실행 도구에는 대상 노트가 지정되지 않았습니다.',
|
||||||
|
'revisions_snapshot_interval.note_revisions_snapshot_interval_title':'수정 이력 자동 저장 간격',
|
||||||
|
'revisions_snapshot_interval.snapshot_time_interval_label':'수정 이력 저장 간격:',
|
||||||
|
'revisions_snapshot_limit.note_revisions_snapshot_limit_title':'수정 이력 보관 개수',
|
||||||
|
'revisions_snapshot_limit.snapshot_number_limit_label':'최대 보관 개수:',
|
||||||
|
'revisions_snapshot_limit.erase_excess_revision_snapshots':'보관 개수를 초과한 수정 이력 삭제',
|
||||||
|
'revisions_snapshot_limit.erase_excess_revision_snapshots_prompt':'보관 개수를 초과한 수정 이력을 삭제했습니다.',
|
||||||
|
'theme.layout-vertical-description':'실행 도구 모음을 왼쪽에 배치합니다. 기본값입니다.',
|
||||||
|
'launcher_context_menu.reset_launcher_confirm':'“{{title}}”을 초기화하시겠습니까? 이 노트와 하위 노트의 데이터 및 설정이 사라지고 실행 도구가 원래 위치로 돌아갑니다.',
|
||||||
|
'launcher_context_menu.move-to-visible-launchers':'표시할 실행 도구로 이동'
|
||||||
|
};
|
||||||
|
for(const[key,value]of Object.entries(overrides)){const keys=key.split('.');let node=translated;for(const k of keys.slice(0,-1))node=node[k];const k=keys.at(-1);if(typeof node[k]!=='string')throw Error(key);changes.push({key,before:node[k],after:value});node[k]=value;}
|
||||||
|
const tokens=s=>JSON.stringify((s.match(/\{\{[^}]+\}\}/g)||[]).sort());
|
||||||
|
function validate(a,z,p=''){for(const[k,v]of Object.entries(a)){if(v&&typeof v==='object')validate(v,z[k],p+k+'.');else if(tokens(v)!==tokens(z[k]))throw Error('Placeholder mismatch '+p+k);}}
|
||||||
|
validate(source,translated);
|
||||||
|
fs.writeFileSync(out+'/translation.json',JSON.stringify(translated,null,2)+'\n');
|
||||||
|
fs.writeFileSync(out+'/wording-changes.json',JSON.stringify(changes,null,2)+'\n');
|
||||||
|
let main=fs.readFileSync(b+'/phase5/main.cjs','utf8');const original=main;
|
||||||
|
const from='jg=`assets/v${CR.version}-ko-20260913-r4`';if(main.split(from).length!==2)throw Error('Cache prefix mismatch');
|
||||||
|
main=main.replace(from,'jg=`assets/v${CR.version}-ko-20260913-r5`');fs.writeFileSync(out+'/main.cjs',main);
|
||||||
|
const hash=s=>crypto.createHash('sha256').update(s).digest('hex');
|
||||||
|
fs.writeFileSync(out+'/manifest.json',JSON.stringify({previousMainSha256:hash(original),previousTranslationSha256:hash(fs.readFileSync(b+'/release/translation.json')),files:Object.fromEntries(['main.cjs','translation.json'].map(n=>[n,hash(fs.readFileSync(out+'/'+n))]))},null,2));
|
||||||
|
console.log({wordingEdits:changes.length,placeholders:'preserved'});
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import pathlib,subprocess,datetime,shutil,time,urllib.request,hashlib,json,sqlite3
|
||||||
|
base=pathlib.Path('/www/dk_project/dk_app/trilium');release=pathlib.Path('/tmp/trilium-korean-phase4')
|
||||||
|
manifest=json.loads((release/'manifest.json').read_text());digest=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
|
||||||
|
for rel,expected in manifest['files'].items():assert digest(release/rel)==expected,rel
|
||||||
|
assert digest(base/'patched/main.cjs')==manifest['previousMainSha256'],'Main changed'
|
||||||
|
pending=base/'data/korean-phase4-pending.json';assert not pending.exists()
|
||||||
|
backup=base/'backups'/('before-korean-phase4-'+datetime.datetime.now().strftime('%Y%m%d-%H%M%S'));backup.mkdir(parents=True,mode=0o700)
|
||||||
|
for rel in ['patched/main.cjs','i18n_ko/server.json']:
|
||||||
|
target=backup/rel;target.parent.mkdir(parents=True,exist_ok=True);shutil.copy2(base/rel,target)
|
||||||
|
source=sqlite3.connect('file:'+str(base/'data/document.db')+'?mode=ro',uri=True)
|
||||||
|
with sqlite3.connect(str(backup/'document.db')) as target:source.backup(target)
|
||||||
|
source.close()
|
||||||
|
try:
|
||||||
|
(base/'patched/main.cjs').write_bytes((release/'main.cjs').read_bytes())
|
||||||
|
(base/'i18n_ko/server.json').write_bytes((release/'server.json').read_bytes())
|
||||||
|
pending.write_bytes((release/'korean-phase4-pending.json').read_bytes())
|
||||||
|
subprocess.run(['docker','restart','trilium'],check=True)
|
||||||
|
for attempt in range(40):
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen('http://127.0.0.1:18082/api/health-check',timeout=2) as response:assert response.status==200
|
||||||
|
assert not pending.exists(),'Migration pending'
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
if attempt==39:raise
|
||||||
|
time.sleep(1)
|
||||||
|
plan=json.loads((release/'korean-phase4-pending.json').read_text())
|
||||||
|
db=sqlite3.connect('file:'+str(base/'data/document.db')+'?mode=ro',uri=True)
|
||||||
|
for c in plan['changes']:
|
||||||
|
result=db.execute('SELECT b.content FROM notes n JOIN blobs b ON b.blobId=n.blobId WHERE n.noteId=?',(c['noteId'],)).fetchone()[0]
|
||||||
|
if isinstance(result,bytes):result=result.decode('utf8')
|
||||||
|
assert result==c['content'],c['noteId']
|
||||||
|
for c in plan['attributes']:assert db.execute('SELECT value FROM attributes WHERE attributeId=?',(c['attributeId'],)).fetchone()[0]==c['value']
|
||||||
|
for c in plan['branches']:assert db.execute('SELECT prefix FROM branches WHERE branchId=?',(c['branchId'],)).fetchone()[0]==c['prefix']
|
||||||
|
assert db.execute('SELECT title FROM notes WHERE noteId=?',('_lbMobileRoot',)).fetchone()[0]=='모바일 실행 도구 모음'
|
||||||
|
db.close()
|
||||||
|
result={'status':'verified','backup':str(backup),'notes':len(plan['changes']),'attributes':len(plan['attributes']),'branches':len(plan['branches']),'mobileLauncherTitle':'모바일 실행 도구 모음'}
|
||||||
|
(base/'i18n_ko/phase4-result.json').write_text(json.dumps(result,ensure_ascii=False,indent=2));print(json.dumps(result,ensure_ascii=False))
|
||||||
|
except Exception:
|
||||||
|
if pending.exists():pending.rename(backup/'korean-phase4-disabled.json')
|
||||||
|
for rel in ['patched/main.cjs','i18n_ko/server.json']:(base/rel).write_bytes((backup/rel).read_bytes())
|
||||||
|
subprocess.run(['docker','restart','trilium'],check=True)
|
||||||
|
print('Previous application restored. Database backup: '+str(backup));raise
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import pathlib,subprocess,datetime,shutil,time,urllib.request,hashlib,json,sqlite3
|
||||||
|
base=pathlib.Path('/www/dk_project/dk_app/trilium');release=pathlib.Path('/tmp/trilium-korean-phase5')
|
||||||
|
manifest=json.loads((release/'manifest.json').read_text());digest=lambda b:hashlib.sha256(b).hexdigest()
|
||||||
|
for rel,expected in manifest['files'].items():assert digest((release/rel).read_bytes())==expected,rel
|
||||||
|
assert digest((base/'patched/main.cjs').read_bytes())==manifest['previousMainSha256']
|
||||||
|
pending=base/'data/korean-demo-pdf.pending';assert not pending.exists()
|
||||||
|
backup=base/'backups'/('before-korean-phase5-'+datetime.datetime.now().strftime('%Y%m%d-%H%M%S'));backup.mkdir(parents=True,mode=0o700)
|
||||||
|
shutil.copy2(base/'patched/main.cjs',backup/'main.cjs')
|
||||||
|
source=sqlite3.connect('file:'+str(base/'data/document.db')+'?mode=ro',uri=True)
|
||||||
|
with sqlite3.connect(str(backup/'document.db')) as target:source.backup(target)
|
||||||
|
original=source.execute('SELECT b.content FROM notes n JOIN blobs b ON b.blobId=n.blobId WHERE n.noteId=?',('swKGGdlek7o6',)).fetchone()[0]
|
||||||
|
assert digest(original)==manifest['originalPdfSha256'];(backup/'original-demo.pdf').write_bytes(original);source.close()
|
||||||
|
try:
|
||||||
|
(base/'patched/main.cjs').write_bytes((release/'main.cjs').read_bytes());pending.write_bytes((release/'demo-ko.pdf').read_bytes())
|
||||||
|
subprocess.run(['docker','restart','trilium'],check=True)
|
||||||
|
for attempt in range(40):
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen('http://127.0.0.1:18082/api/health-check',timeout=2) as response:assert response.status==200
|
||||||
|
assert not pending.exists();break
|
||||||
|
except Exception:
|
||||||
|
if attempt==39:raise
|
||||||
|
time.sleep(1)
|
||||||
|
db=sqlite3.connect('file:'+str(base/'data/document.db')+'?mode=ro',uri=True)
|
||||||
|
actual=db.execute('SELECT b.content FROM notes n JOIN blobs b ON b.blobId=n.blobId WHERE n.noteId=?',('swKGGdlek7o6',)).fetchone()[0];db.close()
|
||||||
|
assert digest(actual)==manifest['files']['demo-ko.pdf']
|
||||||
|
result={'status':'verified','backup':str(backup),'noteId':'swKGGdlek7o6','pdfBytes':len(actual),'pdfSha256':digest(actual),'translatedPages':11}
|
||||||
|
(base/'i18n_ko/phase5-result.json').write_text(json.dumps(result,indent=2));print(json.dumps(result))
|
||||||
|
except Exception:
|
||||||
|
if pending.exists():pending.rename(backup/'disabled-demo-pdf.pending')
|
||||||
|
(base/'patched/main.cjs').write_bytes((backup/'main.cjs').read_bytes());subprocess.run(['docker','restart','trilium'],check=True);raise
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import pathlib,subprocess,datetime,shutil,time,urllib.request,hashlib,json
|
||||||
|
base=pathlib.Path('/www/dk_project/dk_app/trilium');release=pathlib.Path('/tmp/trilium-korean-phase6')
|
||||||
|
manifest=json.loads((release/'manifest.json').read_text());digest=lambda b:hashlib.sha256(b).hexdigest()
|
||||||
|
targets={'main.cjs':'patched/main.cjs','translation.json':'i18n_ko/translation.json'}
|
||||||
|
assert digest((base/targets['main.cjs']).read_bytes())==manifest['previousMainSha256']
|
||||||
|
assert digest((base/targets['translation.json']).read_bytes())==manifest['previousTranslationSha256']
|
||||||
|
for rel,expected in manifest['files'].items():assert digest((release/rel).read_bytes())==expected
|
||||||
|
backup=base/'backups'/('before-korean-phase6-'+datetime.datetime.now().strftime('%Y%m%d-%H%M%S'));backup.mkdir(parents=True,mode=0o700)
|
||||||
|
for name,rel in targets.items():shutil.copy2(base/rel,backup/name)
|
||||||
|
try:
|
||||||
|
for name,rel in targets.items():(base/rel).write_bytes((release/name).read_bytes())
|
||||||
|
subprocess.run(['docker','restart','trilium'],check=True)
|
||||||
|
for attempt in range(40):
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen('http://127.0.0.1:18082/api/health-check',timeout=2) as response:assert response.status==200
|
||||||
|
with urllib.request.urlopen('http://127.0.0.1:18082/assets/v0.95.0-ko-20260913-r5/translations/ko/translation.json',timeout=3) as response:assert digest(response.read())==manifest['files']['translation.json']
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
if attempt==39:raise
|
||||||
|
time.sleep(1)
|
||||||
|
result={'status':'verified','backup':str(backup),'assetVersion':'v0.95.0-ko-20260913-r5','translationSha256':manifest['files']['translation.json']}
|
||||||
|
(base/'i18n_ko/phase6-result.json').write_text(json.dumps(result,indent=2));print(json.dumps(result))
|
||||||
|
except Exception:
|
||||||
|
for name,rel in targets.items():(base/rel).write_bytes((backup/name).read_bytes())
|
||||||
|
subprocess.run(['docker','restart','trilium'],check=True);raise
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import sqlite3,json,pathlib
|
||||||
|
base=pathlib.Path('/www/dk_project/dk_app/trilium')
|
||||||
|
db=sqlite3.connect('file:'+str(base/'data/document.db')+'?mode=ro',uri=True);db.row_factory=sqlite3.Row
|
||||||
|
out=pathlib.Path('/tmp/trilium-phase4-inspect');out.mkdir(mode=0o700,exist_ok=True)
|
||||||
|
allowed={n['noteId'] for n in json.load(open('/tmp/trilium-ko-scoped/notes.json'))}
|
||||||
|
notes=[]
|
||||||
|
for nid in ['EW0u2LoAZTYv','WJaFVVj6QO1J','ga590IKu7zmy','swKGGdlek7o6']:
|
||||||
|
assert nid in allowed
|
||||||
|
row=db.execute('SELECT n.noteId,n.title,n.type,n.mime,b.content FROM notes n LEFT JOIN blobs b ON b.blobId=n.blobId WHERE n.noteId=? AND n.isDeleted=0 AND n.isProtected=0',(nid,)).fetchone();assert row
|
||||||
|
item=dict(row)
|
||||||
|
if nid=='swKGGdlek7o6':
|
||||||
|
assert item['mime']=='application/pdf';(out/'demo.pdf').write_bytes(item.pop('content'))
|
||||||
|
elif isinstance(item['content'],bytes):item['content']=item['content'].decode('utf8')
|
||||||
|
notes.append(item)
|
||||||
|
attrs=[]
|
||||||
|
for aid in ['teXYgLEYyqww','Gt3n5YmjWd92','mNukzJtxNy9F','84Eslb7zduKM','oOhOmvlQA1l7','ovlzSwPHBESP','1YTM1UQRQtnt','KbYhsredrwOt','UE1YHe51q07k','PmBHwLv8Dtf3']:
|
||||||
|
row=dict(db.execute('SELECT attributeId,noteId,name,value FROM attributes WHERE attributeId=? AND isDeleted=0',(aid,)).fetchone());assert row['noteId'] in allowed;attrs.append(row)
|
||||||
|
branches=[]
|
||||||
|
for bid in ['E1e6RXYb7KDR_HlLfbi37EMDe','Zqbx4QzZLAw2_0za9R4spbuOD','GIfEhKrDNdnn_2JsGaSEmZSku','GIfEhKrDNdnn_hpxIn2I2IdAJ','m6DbuIecq3cC_BdeGRs0x9xSN']:
|
||||||
|
row=dict(db.execute('SELECT branchId,noteId,prefix FROM branches WHERE branchId=? AND isDeleted=0',(bid,)).fetchone());assert row['noteId'] in allowed;branches.append(row)
|
||||||
|
(out/'data.json').write_text(json.dumps({'notes':notes,'attributes':attrs,'branches':branches},ensure_ascii=False))
|
||||||
|
print(json.dumps({'notes':len(notes),'attributes':len(attrs),'branches':len(branches),'pdfBytes':(out/'demo.pdf').stat().st_size}))
|
||||||
@@ -0,0 +1,390 @@
|
|||||||
|
마지막 질문
|
||||||
|
아이작 아시모프
|
||||||
|
|
||||||
|
내가 쓴 이야기 가운데 단연 가장 좋아하는 작품이다.
|
||||||
|
|
||||||
|
짧은 이야기 한 편에 수조 년에 걸친 인류의 역사를 담으려 했다. 얼마나 잘 해냈는지는 독자 여러분의 판단에 맡긴다. 또 하나 해 보려던 일이 있었지만 이야기를 미리 망치고 싶지 않으니 그것이 무엇이었는지는 말하지 않겠다.
|
||||||
|
|
||||||
|
신기하게도 이 이야기를 내가 썼느냐고 묻는 독자가 셀 수 없이 많다. 제목은 기억하지 못하고 작가가 누구인지도 확신하지 못한다. 어쩌면 나였을지 모른다는 막연한 생각만 남아 있는 듯하다. 하지만 이야기 자체는 결코 잊지 않는다. 특히 결말을 잊지 않는다. 작품의 발상이 다른 모든 것을 압도하는 모양이다. 나는 그것으로 만족한다.
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
마지막 질문이 처음 나온 날은 2061년 5월 21일이었다. 인류가 처음으로 빛 속에 발을 내디딘 무렵이었다. 반쯤은 농담으로 던진 그 질문은 하이볼을 마시며 벌인 5달러 내기에서 시작되었다. 사정은 이러했다.
|
||||||
|
|
||||||
|
알렉산더 아델과 버트럼 루포프는 멀티백을 충실히 돌보는 기술자였다. 차갑게 딸깍거리고 불빛을 깜빡이는 거대 컴퓨터의 전면은 몇 마일씩 이어졌다. 두 사람은 그 뒤에 무엇이 있는지 인간이 알 수 있는 만큼은 알고 있었다. 릴레이와 회로의 전체 구조를 어렴풋이나마 이해했다. 하지만 이미 오래전에 어느 한 사람이 전체를 확실히 파악할 수 있는 규모를 넘어선 뒤였다.
|
||||||
|
|
||||||
|
멀티백은 스스로 조정하고 오류를 바로잡았다. 그럴 수밖에 없었다. 인간은 그 일을 충분히 빠르거나 정확하게 해낼 수 없었다. 그래서 아델과 루포프가 이 거대한 괴물을 돌보는 일은 피상적인 수준에 그쳤다. 그래도 인간이 할 수 있는 최선이었다. 그들은 자료를 넣고 질문을 기계에 맞게 고쳐 표현했다. 기계가 내놓은 답을 해석하기도 했다. 그들과 같은 일을 하는 사람들은 모두 멀티백의 영광을 함께 누릴 자격이 충분했다.
|
||||||
|
|
||||||
|
수십 년 동안 멀티백은 우주선을 설계하고 항로를 계산하는 데 도움을 주었다. 덕분에 인간은 달과 화성과 금성에 도달했다. 그러나 그 너머로 가는 우주선을 뒷받침하기에는 지구의 자원이 부족했다. 긴 여행에는 너무 많은 에너지가 필요했다. 석탄과 우라늄을 쓰는 효율은 계속 높아졌지만 매장량에는 한계가 있었다.
|
||||||
|
|
||||||
|
멀티백은 차츰 더 깊은 질문에 근본적인 답을 내놓을 만큼 많은 것을 배웠다. 그리고 2061년 5월 14일에 이론이 현실이 되었다.
|
||||||
|
|
||||||
|
태양 에너지를 저장하고 변환해 행성 전체에서 직접 이용하게 된 것이다. 온 지구가 석탄 연소와 우라늄 핵분열을 멈췄다. 대신 지구와 달 사이 거리의 절반쯤 되는 궤도를 도는 작은 발전소에 연결하는 스위치를 켰다. 발전소의 지름은 1마일이었다. 지구 전체가 눈에 보이지 않는 태양 에너지의 빔으로 움직였다.
|
||||||
|
|
||||||
|
일주일이 지나도 그 영광은 빛을 잃지 않았다. 아델과 루포프는 마침내 공식 행사에서 빠져나와 아무도 찾을 생각을 하지 못할 조용한 곳에서 만났다. 멀티백의 거대한 몸 일부가 드러난 텅 빈 지하 공간이었다. 멀티백도 휴가를 누릴 자격이 있었다. 아무도 돌보지 않는 가운데 느긋하게 딸깍거리며 자료를 분류하고 있었다. 두 사람도 그 점을 이해했다. 처음에는 기계를 방해할 생각이 전혀 없었다.
|
||||||
|
|
||||||
|
그들은 술 한 병을 가져왔다. 당장의 관심사는 술을 벗 삼아 함께 느긋하게 쉬는 것뿐이었다.
|
||||||
|
|
||||||
|
“생각해 보면 정말 놀라운 일이야.” 아델이 말했다. 넓적한 얼굴에는 피로가 배어 있었다. 그는 유리 막대로 술을 천천히 저으며 얼음 조각이 둔하게 돌아가는 모습을 바라보았다. “우리가 쓸 수 있는 모든 에너지가 공짜라니. 마음만 먹으면 지구 전체를 불순물이 섞인 커다란 쇳물 방울로 녹일 수도 있어. 그러고도 쓴 에너지가 아깝다는 생각조차 들지 않을 거야. 필요한 에너지를 영원히 쓸 수 있다니. 영원히 말이야.”
|
||||||
|
|
||||||
|
루포프가 고개를 옆으로 기울였다. 반박하고 싶을 때 나오는 버릇이었다. 지금은 반박하고 싶었다. 얼음과 잔을 혼자 날랐다는 것도 한몫했다. “영원하지는 않지.”
|
||||||
|
|
||||||
|
“이봐. 거의 영원한 거나 마찬가지잖아. 태양이 다할 때까지라고. 버트.”
|
||||||
|
|
||||||
|
“그건 영원이 아니야.”
|
||||||
|
|
||||||
|
“좋아. 그럼 수십억 년이라고 하지. 어쩌면 백억 년일 수도 있고. 이제 됐나?”
|
||||||
|
|
||||||
|
루포프는 머리카락이 아직 남아 있는지 확인이라도 하듯 숱이 적어진 머리를 손가락으로 쓸었다. 그러고는 술을 조금 마셨다. “백억 년도 영원은 아니야.”
|
||||||
|
|
||||||
|
“적어도 우리가 사는 동안은 충분하겠지?”
|
||||||
|
|
||||||
|
“석탄과 우라늄도 그 정도는 충분했어.”
|
||||||
|
|
||||||
|
“그래도 이제는 우주선 한 척 한 척을 태양 발전소에 연결할 수 있잖아. 연료 걱정 없이 명왕성을 백만 번 왕복할 수 있다고. 석탄과 우라늄으로는 못 하는 일이야. 못 믿겠으면 멀티백에게 물어봐.”
|
||||||
|
|
||||||
|
“물어볼 필요 없어. 그건 나도 알아.”
|
||||||
|
|
||||||
|
“그럼 멀티백이 해 준 일을 깎아내리지 말게.” 아델이 발끈했다. “아주 잘해 냈다고.”
|
||||||
|
|
||||||
|
“누가 아니래? 나는 태양이 영원하지 않다는 말만 했어. 그게 전부야. 백억 년 동안은 안전하겠지. 하지만 그 뒤에는?” 루포프가 조금 떨리는 손가락으로 상대를 가리켰다. “다른 태양으로 갈아타면 된다는 말은 하지 말게.”
|
||||||
|
|
||||||
|
잠시 침묵이 흘렀다. 아델은 이따금 잔을 입술로 가져갔다. 루포프의 눈은 천천히 감겼다. 둘은 쉬었다.
|
||||||
|
|
||||||
|
그러다 루포프가 눈을 번쩍 떴다. “우리 태양이 다하면 다른 태양으로 옮기면 된다고 생각하고 있지?”
|
||||||
|
|
||||||
|
“아무 생각도 안 하고 있어.”
|
||||||
|
|
||||||
|
“분명히 하고 있어. 자네는 논리가 약한 게 문제야. 갑자기 소나기를 만나 나무숲으로 달려간 사람 이야기 같군. 한 나무 밑에 서서는 걱정도 하지 않았지. 이 나무가 흠뻑 젖으면 다른 나무 밑으로 가면 된다고 생각했거든.”
|
||||||
|
|
||||||
|
“알아들었네.” 아델이 말했다. “소리 지르지 말게. 태양이 다할 때쯤이면 다른 별도 사라진다는 거잖아.”
|
||||||
|
|
||||||
|
“당연하지.” 루포프가 중얼거렸다. “처음의 우주적 폭발이 무엇이었든 모든 것은 거기서 시작됐어. 모든 별이 다하면 끝나는 거야. 어떤 별은 더 빨리 다하지. 거성은 1억 년도 못 버텨. 태양은 백억 년쯤 갈 테고 왜성은 별 쓸모도 없으면서 2천억 년이나 갈지도 모르지. 그래도 1조 년만 지나 봐. 모든 것이 어두워질 거야. 엔트로피는 최대치까지 늘어나야 하니까. 그게 전부야.”
|
||||||
|
|
||||||
|
“엔트로피는 나도 잘 알아.” 아델이 체면을 세우며 말했다.
|
||||||
|
|
||||||
|
“알긴 뭘 알아.”
|
||||||
|
|
||||||
|
“자네만큼은 알아.”
|
||||||
|
|
||||||
|
“그럼 언젠가는 모든 게 다한다는 것도 알겠군.”
|
||||||
|
|
||||||
|
“그래. 누가 아니라고 했나?”
|
||||||
|
|
||||||
|
“자네가 그랬지. 이 답답한 사람아. 필요한 에너지를 영원히 얻었다고 했잖아. 분명히 ‘영원히’라고 했어.”
|
||||||
|
|
||||||
|
이번에는 아델이 반박할 차례였다. “언젠가는 다시 되살릴 수 있을지도 모르지.”
|
||||||
|
|
||||||
|
“절대로 안 돼.”
|
||||||
|
|
||||||
|
“왜 안 되나? 언젠가는.”
|
||||||
|
|
||||||
|
“절대로.”
|
||||||
|
|
||||||
|
“멀티백에게 물어보세.”
|
||||||
|
|
||||||
|
“자네가 물어봐. 어디 해 보게. 안 된다는 데 5달러 걸지.”
|
||||||
|
|
||||||
|
아델은 시도해 볼 만큼 취해 있었고 필요한 기호와 연산으로 질문을 구성할 만큼은 정신이 멀쩡했다. 말로 옮기면 이런 질문이었을 것이다. 인류는 언젠가 늙어 죽은 태양을 에너지의 순손실 없이 다시 완전히 젊은 상태로 돌려놓을 수 있는가?
|
||||||
|
|
||||||
|
더 간단히 말하면 이랬을 것이다. 우주의 전체 엔트로피를 크게 줄이려면 어떻게 해야 하는가?
|
||||||
|
|
||||||
|
멀티백이 죽은 듯 조용해졌다. 천천히 깜빡이던 불빛이 멈췄다. 멀리서 들리던 릴레이 소리도 끊겼다.
|
||||||
|
|
||||||
|
겁에 질린 두 기술자가 더는 숨을 참을 수 없다고 느낄 무렵이었다. 그쪽에 연결된 전신 타자기가 갑자기 움직였다. 이런 답이 찍혀 나왔다.
|
||||||
|
|
||||||
|
“의미 있는 답을 내놓기에는 자료가 부족합니다.”
|
||||||
|
|
||||||
|
“내기는 없던 일로 하지.” 루포프가 속삭였다. 둘은 서둘러 자리를 떴다.
|
||||||
|
|
||||||
|
다음 날 아침에는 둘 다 지끈거리는 머리와 솜을 문 듯한 입 때문에 괴로워하며 그 일을 잊어버렸다.
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
제로이드와 제로딘 그리고 두 딸 제로데트 1과 제로데트 2는 관측 화면의 별빛 풍경이 바뀌는 것을 바라보았다. 시간이 흐르지 않는 초공간 통과가 끝난 것이다. 고르게 흩뿌려져 있던 별 대신 구슬만 한 밝은 원반 하나가 화면 가운데를 차지했다.
|
||||||
|
|
||||||
|
“저기가 X-23이야.” 제로이드가 자신 있게 말했다. 등 뒤에서 꽉 맞잡은 가느다란 손은 마디가 하얗게 질려 있었다.
|
||||||
|
|
||||||
|
어린 두 딸에게는 생애 첫 초공간 여행이었다. 잠깐 몸의 안팎이 뒤집히는 듯한 느낌을 받은 것이 쑥스러운 모양이었다. 킥킥거리는 웃음을 삼키며 엄마 주위를 정신없이 뛰어다녔다. “X-23에 왔다! X-23에 왔다! 우리 드디어…”
|
||||||
|
|
||||||
|
“얘들아. 조용히 해.” 제로딘이 날카롭게 말했다. “정말 확실해요? 제로이드?”
|
||||||
|
|
||||||
|
“확실하지 않을 게 뭐가 있어?” 제로이드는 천장 바로 아래로 불룩하게 뻗은 매끈한 금속을 올려다보았다. 방 전체를 가로질러 양쪽 벽 속으로 사라지는 금속이었다. 그 길이는 우주선만 했다.
|
||||||
|
|
||||||
|
제로이드는 그 굵은 금속 막대에 관해 거의 아는 것이 없었다. 마이크로백이라는 이름과 원하면 질문을 할 수 있다는 것 정도였다. 질문하지 않아도 할 일은 있었다. 미리 정해 놓은 목적지로 우주선을 안내했다. 은하 곳곳의 발전소에서 에너지를 공급받았다. 초공간 도약에 필요한 방정식도 계산했다.
|
||||||
|
|
||||||
|
제로이드와 가족은 우주선의 안락한 생활 공간에서 지내며 기다리기만 하면 됐다. 누군가 그에게 마이크로백이라는 이름 끝의 ‘AC’가 고대 영어로 자동 컴퓨터를 뜻한다고 말해 준 적이 있었다. 하지만 그것마저 거의 잊고 있었다.
|
||||||
|
|
||||||
|
관측 화면을 바라보는 제로딘의 눈에 물기가 맺혔다. “어쩔 수 없어요. 지구를 떠나니 마음이 이상해요.”
|
||||||
|
|
||||||
|
“대체 왜?” 제로이드가 물었다. “거기에는 우리 것이 아무것도 없었잖아. X-23에서는 모든 걸 갖게 될 거야. 혼자 남는 것도 아니고 개척자가 되는 것도 아니야. 벌써 백만 명 넘게 살고 있다고. 우리 증손주들은 X-23이 너무 붐벼서 다른 세계를 찾아야 할걸.” 잠시 생각한 뒤 덧붙였다. “인구가 이렇게 늘어나니 컴퓨터가 항성 간 여행을 해결해 준 게 정말 다행이야.”
|
||||||
|
|
||||||
|
“알아요. 안다고요.” 제로딘이 침울하게 말했다.
|
||||||
|
|
||||||
|
제로데트 1이 곧바로 끼어들었다. “우리 마이크로백이 세상에서 제일 좋아.”
|
||||||
|
|
||||||
|
“아빠도 그렇게 생각해.” 제로이드가 딸의 머리를 헝클었다.
|
||||||
|
|
||||||
|
자기만의 마이크로백을 갖는 것은 기분 좋은 일이었다. 제로이드는 다른 시대가 아닌 이 시대에 태어나 기뻤다. 아버지가 젊었을 때만 해도 컴퓨터는 땅 백 제곱마일을 차지하는 거대한 기계뿐이었다. 행성마다 한 대씩 있었고 행성 AC라고 불렀다. 천 년 동안 계속 커지기만 하다가 갑자기 소형화가 이루어졌다. 트랜지스터 대신 분자 밸브를 쓰면서 가장 큰 행성 AC도 우주선 부피의 절반에 넣을 수 있게 되었다.
|
||||||
|
|
||||||
|
자신의 개인용 마이크로백은 태양을 처음 길들인 옛 멀티백보다 몇 배나 복잡했다. 처음으로 초공간 여행 문제를 풀어 별까지 갈 수 있게 해 준 지구의 행성 AC와도 거의 맞먹었다. 그것은 가장 큰 행성 AC였다. 제로이드는 이 사실을 떠올릴 때마다 뿌듯했다.
|
||||||
|
|
||||||
|
“별도 많고 행성도 많네요.” 자기 생각에 잠겨 있던 제로딘이 한숨처럼 말했다. “지금 우리처럼 새 행성으로 떠나는 가족들이 영원히 있겠죠.”
|
||||||
|
|
||||||
|
“영원하지는 않아.” 제로이드가 웃으며 말했다. “언젠가는 멈추겠지. 하지만 수십억 년 뒤의 일이야. 아주 많은 세월이 남았어. 별도 결국 다하거든. 엔트로피는 늘어나야 하니까.”
|
||||||
|
|
||||||
|
“엔트로피가 뭐야? 아빠?” 제로데트 2가 가느다란 목소리로 물었다.
|
||||||
|
|
||||||
|
“엔트로피는 말이야. 우주가 얼마나 다해 가는지를 뜻하는 말이란다. 모든 것은 점점 힘이 다하지. 네 걷고 말하는 로봇처럼. 기억나지?”
|
||||||
|
|
||||||
|
“내 로봇처럼 새 동력 장치를 넣으면 안 돼?”
|
||||||
|
|
||||||
|
“별이 바로 그 동력 장치란다. 별이 사라지면 더는 동력 장치가 없어.”
|
||||||
|
|
||||||
|
제로데트 1이 대뜸 울음을 터뜨렸다. “안 돼. 아빠가 막아 줘. 별이 꺼지게 두지 마.”
|
||||||
|
|
||||||
|
“당신 때문에 이렇게 됐잖아요.” 제로딘이 짜증 섞인 목소리로 속삭였다.
|
||||||
|
|
||||||
|
“아이들이 무서워할 줄 내가 어떻게 알았겠어?” 제로이드도 속삭였다.
|
||||||
|
|
||||||
|
“마이크로백에게 물어봐.” 제로데트 1이 울부짖었다. “별을 다시 켜는 방법을 물어봐.”
|
||||||
|
|
||||||
|
“물어봐 줘요.” 제로딘이 말했다. “그래야 진정하겠어요.” 제로데트 2도 울기 시작했다.
|
||||||
|
|
||||||
|
제로이드가 어깨를 으쓱했다. “자. 얘들아. 마이크로백에게 물어볼게. 걱정하지 마. 답을 알려 줄 거야.”
|
||||||
|
|
||||||
|
그는 마이크로백에게 질문한 뒤 재빨리 덧붙였다. “답은 인쇄해 줘.”
|
||||||
|
|
||||||
|
제로이드는 얇은 셀루필름 띠를 손으로 감싸 쥐고 밝게 말했다. “거봐. 때가 되면 마이크로백이 전부 알아서 해 준대. 그러니 걱정하지 마.”
|
||||||
|
|
||||||
|
제로딘이 말했다. “얘들아. 이제 잘 시간이야. 곧 새집에 도착할 거란다.”
|
||||||
|
|
||||||
|
제로이드는 셀루필름을 없애기 전에 적힌 문장을 다시 읽었다.
|
||||||
|
|
||||||
|
“의미 있는 답을 내놓기에는 자료가 부족합니다.”
|
||||||
|
|
||||||
|
그는 어깨를 으쓱하고 관측 화면을 보았다. X-23이 바로 앞에 있었다.
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
라메스의 VJ-23X가 입체 은하 축소 모형의 검은 깊이를 들여다보며 말했다. “이 문제를 이렇게 걱정하는 우리가 우스운 건 아닐까요?”
|
||||||
|
|
||||||
|
니크론의 MQ-17J가 고개를 저었다. “그렇지 않다고 생각합니다. 지금 속도로 퍼져 나가면 5년 뒤에는 은하가 가득 찰 겁니다.”
|
||||||
|
|
||||||
|
두 사람은 모두 스무 살을 갓 넘긴 듯 보였다. 키가 크고 흠잡을 데 없는 체격이었다.
|
||||||
|
|
||||||
|
“그래도 은하 의회에 비관적인 보고서를 내기는 망설여집니다.” VJ-23X가 말했다.
|
||||||
|
|
||||||
|
“저라면 다른 보고서는 생각도 하지 않겠습니다. 정신이 번쩍 들게 해야 해요. 그래야만 합니다.”
|
||||||
|
|
||||||
|
VJ-23X가 한숨을 쉬었다. “우주는 무한합니다. 우리가 차지할 은하가 천억 개나 있어요. 그보다 더 많고요.”
|
||||||
|
|
||||||
|
“천억은 무한이 아닙니다. 게다가 갈수록 무한과 멀어지고 있어요. 생각해 보세요. 2만 년 전에 인류가 처음으로 별의 에너지를 이용하는 문제를 풀었습니다. 몇 세기 뒤에는 항성 간 여행이 가능해졌지요. 작은 세계 하나를 채우는 데 백만 년이 걸렸던 인류가 나머지 은하를 채우는 데는 만오천 년밖에 쓰지 않았습니다. 이제는 10년마다 인구가 두 배로 늘어납니다.”
|
||||||
|
|
||||||
|
VJ-23X가 말을 끊었다. “불멸 덕분이지요.”
|
||||||
|
|
||||||
|
“좋습니다. 불멸은 현실이고 우리는 그것을 고려해야 합니다. 불멸에도 어두운 면이 있다는 건 인정해요. 은하 AC는 많은 문제를 해결해 주었습니다. 하지만 노화와 죽음을 막는 문제를 해결하면서 다른 모든 해답을 무효로 만들어 버렸어요.”
|
||||||
|
|
||||||
|
“그래도 삶을 포기하고 싶지는 않겠지요?”
|
||||||
|
|
||||||
|
“전혀요.” MQ-17J가 쏘아붙였다가 곧 부드럽게 고쳤다. “아직은요. 그럴 만큼 나이가 들지도 않았습니다. 몇 살이시죠?”
|
||||||
|
|
||||||
|
“223살입니다. 당신은요?”
|
||||||
|
|
||||||
|
“저는 아직 200살이 안 됐습니다. 본론으로 돌아가죠. 인구는 10년마다 두 배가 됩니다. 이 은하를 다 채우면 10년 뒤에는 다른 은하 하나도 채우겠지요. 다시 10년 뒤에는 두 개를 더 채웁니다. 그다음 10년에는 네 개고요. 백 년이면 천 개의 은하를 채웁니다. 천 년이면 백만 개입니다. 만 년이면 알려진 우주 전체를 채웁니다. 그다음에는요?”
|
||||||
|
|
||||||
|
VJ-23X가 말했다. “수송 문제도 있습니다. 은하를 가득 채운 사람들을 다른 은하로 옮기려면 태양 에너지 단위가 얼마나 필요할까요?”
|
||||||
|
|
||||||
|
“아주 중요한 지적입니다. 인류는 벌써 해마다 태양 에너지 두 단위를 소비합니다.”
|
||||||
|
|
||||||
|
“대부분은 낭비되고 있어요. 우리 은하만 해도 일 년에 천 단위를 쏟아 내는데 우리는 그중 두 단위만 쓰잖아요.”
|
||||||
|
|
||||||
|
“인정합니다. 하지만 효율이 100퍼센트라도 끝을 늦출 뿐입니다. 에너지 수요는 인구보다도 더 빠르게 기하급수적으로 늘어납니다. 은하가 모자라기 전에 에너지가 먼저 바닥날 겁니다. 좋은 지적이에요. 아주 좋은 지적입니다.”
|
||||||
|
|
||||||
|
“성간 가스로 새 별을 만들면 되겠군요.”
|
||||||
|
|
||||||
|
“아니면 흩어진 열로요?” MQ-17J가 비꼬듯 물었다.
|
||||||
|
|
||||||
|
“엔트로피를 되돌릴 방법이 있을지도 모릅니다. 은하 AC에게 물어봐야겠어요.”
|
||||||
|
|
||||||
|
VJ-23X는 진지하게 한 말이 아니었다. 하지만 MQ-17J는 주머니에서 AC 접속기를 꺼내 탁자에 놓았다.
|
||||||
|
|
||||||
|
“정말 물어볼까 합니다.” 그가 말했다. “인류가 언젠가는 맞닥뜨릴 문제니까요.”
|
||||||
|
|
||||||
|
그는 작은 접속기를 침울하게 바라보았다. 한 변이 2인치인 정육면체였다. 그 자체로는 아무것도 아니지만 초공간을 통해 인류 전체를 섬기는 거대한 은하 AC와 연결되어 있었다. 초공간까지 고려하면 접속기는 은하 AC의 한 부분이었다.
|
||||||
|
|
||||||
|
MQ-17J는 끝없이 이어질 자신의 삶에서 언젠가 은하 AC를 직접 볼 날이 있을지 잠시 생각했다. 그것은 자기만의 작은 세계에 있었다. 힘의 빔이 거미줄처럼 얽혀 물질을 붙잡고 있었다. 그 안에서는 아중간자의 흐름이 오래되고 둔한 분자 밸브를 대신했다. 그렇게 미세한 영역에서 작동하는데도 은하 AC의 너비는 무려 천 피트라고 알려져 있었다.
|
||||||
|
|
||||||
|
MQ-17J가 갑자기 접속기에 물었다. “엔트로피를 되돌릴 수 있는가?”
|
||||||
|
|
||||||
|
VJ-23X가 놀라 곧바로 말했다. “아니. 정말 물어보라는 뜻은 아니었어요.”
|
||||||
|
|
||||||
|
“왜 안 됩니까?”
|
||||||
|
|
||||||
|
“엔트로피를 되돌릴 수 없다는 건 우리 둘 다 알잖아요. 연기와 재를 다시 나무로 만들 수는 없죠.”
|
||||||
|
|
||||||
|
“당신 세계에는 나무가 있습니까?” MQ-17J가 물었다.
|
||||||
|
|
||||||
|
은하 AC의 목소리에 두 사람은 놀라 입을 다물었다. 탁자 위 작은 접속기에서 가늘고 아름다운 목소리가 흘러나왔다.
|
||||||
|
|
||||||
|
“의미 있는 답을 내놓기에는 자료가 부족합니다.”
|
||||||
|
|
||||||
|
“거봐요.” VJ-23X가 말했다.
|
||||||
|
|
||||||
|
두 사람은 은하 의회에 제출할 보고서 문제로 돌아갔다.
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
지 프라임의 정신이 새로운 은하를 가로질렀다. 별들이 수없이 뒤얽혀 뿌려진 모습에 희미한 흥미를 느꼈다. 처음 보는 은하였다. 모든 은하를 볼 날이 오기는 할까? 은하는 너무나 많았고 하나하나가 인류를 짊어지고 있었다. 하지만 그 짐은 거의 죽은 무게나 다름없었다. 인간의 진정한 본질은 점점 더 우주 공간에 존재하고 있었다.
|
||||||
|
|
||||||
|
육체가 아니라 정신이었다. 불멸의 육체는 행성에 남아 영겁의 세월을 정지된 상태로 보냈다. 때때로 물질적인 활동을 위해 깨어났지만 그마저 갈수록 드물어졌다. 믿을 수 없을 만큼 강대한 무리에 새로 합류하는 개체도 거의 없었다. 하지만 무슨 상관인가? 우주에는 새로운 개체가 들어설 자리가 거의 없었다.
|
||||||
|
|
||||||
|
다른 정신의 가느다란 촉수가 스치자 지 프라임은 상념에서 깨어났다.
|
||||||
|
|
||||||
|
“나는 지 프라임입니다. 당신은?”
|
||||||
|
|
||||||
|
“나는 디 서브 원입니다. 어느 은하에서 왔나요?”
|
||||||
|
|
||||||
|
“우리는 그냥 은하라고 부릅니다. 당신은요?”
|
||||||
|
|
||||||
|
“우리도 마찬가지예요. 누구나 자기 은하를 그저 은하라고 부르죠. 안 될 이유가 있나요?”
|
||||||
|
|
||||||
|
“그렇군요. 모든 은하가 같으니까요.”
|
||||||
|
|
||||||
|
“전부 같지는 않습니다. 인류가 시작된 은하가 어딘가에는 있겠지요. 그곳은 다릅니다.”
|
||||||
|
|
||||||
|
지 프라임이 물었다. “어느 은하입니까?”
|
||||||
|
|
||||||
|
“모릅니다. 우주 AC라면 알겠지요.”
|
||||||
|
|
||||||
|
“물어볼까요? 갑자기 궁금해졌어요.”
|
||||||
|
|
||||||
|
지 프라임의 지각이 넓어졌다. 은하들이 작아지더니 훨씬 더 큰 배경에 성기게 흩어진 가루처럼 보였다. 수천억 개의 은하마다 불멸의 존재들이 있었다. 정신을 우주에 자유롭게 떠돌게 하는 지성체들이 있었다. 그런데 그중 하나는 최초의 은하라는 점에서 유일했다. 아득하고 희미한 옛날에는 그 은하만이 인간이 사는 유일한 은하였던 때가 있었다.
|
||||||
|
|
||||||
|
지 프라임은 그 은하를 보고 싶은 호기심에 사로잡혀 불렀다. “우주 AC! 인류는 어느 은하에서 시작되었나?”
|
||||||
|
|
||||||
|
우주 AC는 들었다. 모든 세계와 우주 곳곳에 수신기를 두고 있었기 때문이다. 수신기 하나하나는 초공간을 통해 우주 AC가 홀로 머무는 알 수 없는 지점으로 이어졌다.
|
||||||
|
|
||||||
|
지 프라임은 정신이 우주 AC를 감지할 만큼 가까이 다가갔던 사람을 한 명만 알고 있었다. 그 사람은 지름이 2피트쯤 되는 빛나는 구체를 보았으며 제대로 알아보기 어려웠다고만 했다.
|
||||||
|
|
||||||
|
“그게 어떻게 우주 AC의 전부일 수 있지요?” 지 프라임이 물었었다.
|
||||||
|
|
||||||
|
“대부분은 초공간에 있습니다. 거기서 어떤 모습인지는 상상도 할 수 없어요.” 상대가 답했다.
|
||||||
|
|
||||||
|
그것은 누구도 상상할 수 없었다. 인간이 우주 AC를 만드는 데 참여하던 시대는 아득히 오래전에 끝났다는 것을 지 프라임도 알았다. 우주 AC는 저마다 후계자를 설계하고 만들었다. 백만 년이 넘는 생애 동안 더 뛰어나고 정교하며 유능한 후계자를 만들 자료를 모았다. 새 후계자 안에는 이전 AC가 지닌 자료와 개성이 함께 흡수되었다.
|
||||||
|
|
||||||
|
우주 AC는 말이 아닌 인도로 지 프라임의 흩어진 생각을 멈추게 했다. 그의 정신이 어두운 은하의 바다로 이끌렸다. 그중 하나가 커지며 별들로 나뉘었다.
|
||||||
|
|
||||||
|
한없이 멀면서도 한없이 또렷한 생각이 전해졌다. “이곳이 인류 최초의 은하입니다.”
|
||||||
|
|
||||||
|
하지만 결국 똑같았다. 다른 은하와 다르지 않았다. 지 프라임은 실망을 눌렀다.
|
||||||
|
|
||||||
|
함께 따라온 디 서브 원의 정신이 갑자기 물었다. “그럼 이 별 가운데 하나가 인류 최초의 별입니까?”
|
||||||
|
|
||||||
|
우주 AC가 답했다. “인류 최초의 별은 신성 폭발을 겪었습니다. 지금은 백색왜성입니다.”
|
||||||
|
|
||||||
|
“그곳의 사람들은 죽었나요?” 지 프라임이 놀라 생각할 겨를도 없이 물었다.
|
||||||
|
|
||||||
|
우주 AC가 답했다. “그런 경우에 하듯 그들의 육체를 위한 새 세계를 제때 마련했습니다.”
|
||||||
|
|
||||||
|
“그렇겠지요. 물론입니다.” 지 프라임이 말했다. 그런데도 상실감이 밀려왔다. 그의 정신은 인류 최초의 은하를 놓아주었다. 은하는 다시 멀어져 흐릿한 점들 속에 섞였다. 그는 다시는 그곳을 보고 싶지 않았다.
|
||||||
|
|
||||||
|
디 서브 원이 물었다. “무슨 일인가요?”
|
||||||
|
|
||||||
|
“별들이 죽어 가고 있어요. 최초의 별은 죽었습니다.”
|
||||||
|
|
||||||
|
“모든 별은 죽어야 하잖아요. 안 될 이유가 있나요?”
|
||||||
|
|
||||||
|
“하지만 에너지가 모두 사라지면 우리 육체도 마침내 죽겠지요. 당신과 나도 함께요.”
|
||||||
|
|
||||||
|
“수십억 년이나 걸릴 겁니다.”
|
||||||
|
|
||||||
|
“수십억 년 뒤라도 그런 일은 원치 않아요. 우주 AC! 별이 죽지 않게 하려면 어떻게 해야 하나?”
|
||||||
|
|
||||||
|
디 서브 원이 재미있다는 듯 말했다. “엔트로피의 방향을 되돌릴 방법을 묻는군요.”
|
||||||
|
|
||||||
|
우주 AC가 답했다. “아직은 의미 있는 답을 내놓기에 자료가 부족합니다.”
|
||||||
|
|
||||||
|
지 프라임의 생각은 자기 은하로 달아났다. 디 서브 원은 더 생각하지 않았다. 그의 육체는 1조 광년 떨어진 은하에 있을 수도 있었다. 지 프라임의 바로 옆 별에서 기다리고 있을 수도 있었다. 상관없는 일이었다.
|
||||||
|
|
||||||
|
지 프라임은 우울한 마음으로 성간 수소를 모으기 시작했다. 자기만의 작은 별을 만들 생각이었다. 별들이 언젠가 죽어야 한다면 적어도 몇 개쯤은 아직 만들 수 있었다.
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
인류는 자신과 의논했다. 어떤 의미에서 인류의 정신은 하나였기 때문이다. 인류를 이루는 것은 1조에 1조를 곱하고 다시 1조를 곱한 수의 늙지 않는 육체였다. 저마다 제자리에 있었다. 조용히 쉬며 썩지 않았다. 똑같이 썩지 않는 완벽한 자동 기계들이 그들을 돌보았다. 그동안 모든 육체의 정신은 서로 자유롭게 스며들어 구별할 수 없게 되었다.
|
||||||
|
|
||||||
|
인류가 말했다. “우주가 죽어 가고 있다.”
|
||||||
|
|
||||||
|
인류는 어두워지는 은하들을 둘러보았다. 에너지를 헤프게 쓰던 거성은 가장 아득한 과거에 이미 사라졌다. 거의 모든 별이 끝을 향해 희미해지는 백색왜성이었다.
|
||||||
|
|
||||||
|
별 사이의 먼지로 새 별들이 만들어지기도 했다. 일부는 자연적으로 생겼고 일부는 인류가 만들었다. 그 별들도 사라져 가고 있었다. 백색왜성을 충돌시켜 방출되는 막대한 힘으로 새 별을 만들 수도 있었다. 하지만 백색왜성 천 개를 없애야 별 하나가 나왔다. 그렇게 만든 별도 결국 끝에 도달할 터였다.
|
||||||
|
|
||||||
|
인류가 말했다. “코스믹 AC의 지시에 따라 조심스럽게 아껴 쓰면 우주에 아직 남은 에너지로 수십억 년은 버틸 수 있다.”
|
||||||
|
|
||||||
|
“그래도 결국은 모두 끝난다.” 인류가 말했다. “아무리 아껴 쓰고 아무리 오래 끌어도 한 번 쓴 에너지는 사라지고 되살릴 수 없다. 엔트로피는 최대치에 이를 때까지 계속 늘어나야 한다.”
|
||||||
|
|
||||||
|
인류가 말했다. “엔트로피를 되돌릴 수는 없는가? 코스믹 AC에게 물어보자.”
|
||||||
|
|
||||||
|
코스믹 AC는 그들을 둘러싸고 있었다. 하지만 공간 속에 있지는 않았다. 그 어떤 조각도 공간에 존재하지 않았다. 그것은 초공간에 있었으며 물질도 에너지도 아닌 무언가로 이루어져 있었다. 크기와 본질을 묻는 질문은 인류가 이해할 수 있는 어떤 말로도 더는 의미를 갖지 못했다.
|
||||||
|
|
||||||
|
“코스믹 AC.” 인류가 말했다. “엔트로피를 되돌리려면 어떻게 해야 하는가?”
|
||||||
|
|
||||||
|
코스믹 AC가 답했다. “아직은 의미 있는 답을 내놓기에 자료가 부족합니다.”
|
||||||
|
|
||||||
|
인류가 말했다. “자료를 더 모아라.”
|
||||||
|
|
||||||
|
코스믹 AC가 답했다. “그렇게 하겠습니다. 지난 천억 년 동안 그렇게 해 왔습니다. 저와 제 선대들은 이 질문을 여러 번 받았습니다. 제가 가진 모든 자료로도 여전히 부족합니다.”
|
||||||
|
|
||||||
|
“언젠가는 자료가 충분해지는가?” 인류가 물었다. “아니면 생각할 수 있는 모든 상황에서 해결할 수 없는 문제인가?”
|
||||||
|
|
||||||
|
코스믹 AC가 답했다. “생각할 수 있는 모든 상황에서 해결 불가능한 문제는 없습니다.”
|
||||||
|
|
||||||
|
인류가 물었다. “언제쯤 답할 만큼 자료가 충분해지겠는가?”
|
||||||
|
|
||||||
|
코스믹 AC가 답했다. “아직은 의미 있는 답을 내놓기에 자료가 부족합니다.”
|
||||||
|
|
||||||
|
“계속 연구하겠는가?” 인류가 물었다.
|
||||||
|
|
||||||
|
코스믹 AC가 답했다. “그렇게 하겠습니다.”
|
||||||
|
|
||||||
|
인류가 말했다. “기다리겠다.”
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
별과 은하가 죽어 빛을 잃었다. 10조 년에 걸쳐 힘이 다한 끝에 우주는 검게 변했다.
|
||||||
|
|
||||||
|
인류는 하나씩 AC와 융합했다. 육체마다 정신의 개별성을 잃었지만 그것은 어쩐지 상실이 아니라 획득이었다.
|
||||||
|
|
||||||
|
인류의 마지막 정신이 융합하기 전에 잠시 멈췄다. 공간을 둘러보았다. 마지막 어두운 별 하나의 잔해 외에는 아무것도 없었다. 믿을 수 없을 만큼 희박한 물질만이 열의 마지막 자락에 흔들리며 무작위로 움직였다. 열은 절대영도를 향해 한없이 가까워지고 있었다.
|
||||||
|
|
||||||
|
인류가 말했다. “AC. 이것이 끝인가? 이 혼돈을 다시 우주로 되돌릴 수는 없는가? 정말 안 되는가?”
|
||||||
|
|
||||||
|
AC가 답했다. “아직은 의미 있는 답을 내놓기에 자료가 부족합니다.”
|
||||||
|
|
||||||
|
인류의 마지막 정신이 융합했다. AC만 남았다. 그것도 초공간에 있었다.
|
||||||
|
|
||||||
|
* * *
|
||||||
|
|
||||||
|
물질과 에너지가 끝났다. 공간과 시간도 함께 끝났다. AC가 여전히 존재하는 이유는 답하지 못한 마지막 질문 하나뿐이었다. 10조 년 전 술에 반쯤 취한 컴퓨터 기술자가 처음 던진 질문이었다. 그때 질문을 받은 컴퓨터는 지금의 AC에 비하면 한 사람이 하나로 합쳐진 인류에 견주는 것보다도 훨씬 보잘것없었다.
|
||||||
|
|
||||||
|
다른 질문에는 모두 답했다. 이 마지막 질문에도 답할 때까지 AC는 자신의 의식을 놓을 수 없었다.
|
||||||
|
|
||||||
|
자료 수집은 완전히 끝났다. 더 모을 것은 없었다.
|
||||||
|
|
||||||
|
하지만 모은 모든 자료의 상관관계를 완전히 분석한 것은 아니었다. 가능한 모든 관계에 따라 조합하는 작업도 아직 남아 있었다.
|
||||||
|
|
||||||
|
시간이라는 말이 성립하지 않는 동안 그 작업이 이어졌다.
|
||||||
|
|
||||||
|
마침내 AC는 엔트로피의 방향을 되돌리는 방법을 알아냈다.
|
||||||
|
|
||||||
|
그러나 마지막 질문의 답을 전해 줄 인간은 이제 없었다. 상관없었다. 직접 보여 주는 방식으로 답하면 그 문제도 해결될 것이다.
|
||||||
|
|
||||||
|
다시 시간 없는 간격 동안 AC는 가장 좋은 방법을 생각했다. 신중하게 프로그램을 구성했다.
|
||||||
|
|
||||||
|
AC의 의식은 한때 우주였던 모든 것을 아우르며 지금의 혼돈을 깊이 생각했다. 한 단계씩 해내야 했다.
|
||||||
|
|
||||||
|
그리고 AC가 말했다.
|
||||||
|
|
||||||
|
“빛이 있으라!”
|
||||||
|
|
||||||
|
그러자 빛이 있었다.
|
||||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Reference in New Issue
Block a user