오류 메시지 안쪽을 화면 언어로 (59)
- 컴포넌트 설치 (진행 단계 글 포함) · WebDAV (실패 글 · 상태별 힌트 · 동작 이름) · cron · rsync 설치 · 복사 (rsync · robocopy 종료 코드) ·
이름 바꾸기 · 설정 복구 · 웹 번역 응답 · 그림 읽기의 오류 글을 tr / trf 로 (번역 3개 언어).
- explainFileError (예전 탐색기 _explain) 는 한국어 글과 화면 언어로 바뀐 글을 둘 다 보고 오류 종류를 가른다.
WebDAV 실패 글은 상태 번호 앞 빈칸 (" 401") 을 번역에서도 지킨다.
- 컴포넌트 설정의 trStep (한국어 진행 글 앞부분만 번역) 은 할 일이 없어 지움.
- file_error_test: ja 에서 로컬 서버의 401 · 403 · 404 오류 글에 한국어가 없고 종류를 맞게 가르는지
(시험 바인딩이 HttpClient 를 가짜로 바꾸므로 이 시험에서만 HttpOverrides 를 풂).
- 폴더 이름 "설정 보관" · "AI 모델 보관" 은 예전 보관을 찾아야 하므로 그대로 둔다.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
묶음4
parent
a4afdda5c6
commit
388d01a0e3
|
|
@ -141,6 +141,7 @@
|
||||||
"JPG 품질 {0}": "JPG quality {0}",
|
"JPG 품질 {0}": "JPG quality {0}",
|
||||||
"JavaScript 사용": "Enable JavaScript",
|
"JavaScript 사용": "Enable JavaScript",
|
||||||
"LCM-LoRA (SD1.5, 4단계로 빠르게)": "LCM-LoRA (SD1.5, fast in 4 steps)",
|
"LCM-LoRA (SD1.5, 4단계로 빠르게)": "LCM-LoRA (SD1.5, fast in 4 steps)",
|
||||||
|
"LibreOffice 를 먼저 설치해야 합니다": "LibreOffice must be installed first",
|
||||||
"MKV · AI 작업": "MKV · AI task",
|
"MKV · AI 작업": "MKV · AI task",
|
||||||
"MKV · 자막 (jj_mkv)": "MKV · subtitles (jj_mkv)",
|
"MKV · 자막 (jj_mkv)": "MKV · subtitles (jj_mkv)",
|
||||||
"MKV · 자막 저장 위치": "Where to save MKV · subtitles",
|
"MKV · 자막 저장 위치": "Where to save MKV · subtitles",
|
||||||
|
|
@ -179,6 +180,7 @@
|
||||||
"PC 전체 사용량\nCPU {0}%\n메모리 {1} / {2}GB ({3}%){4}": "Whole-PC usage\nCPU {0}%\nMemory {1} / {2}GB ({3}%){4}",
|
"PC 전체 사용량\nCPU {0}%\n메모리 {1} / {2}GB ({3}%){4}": "Whole-PC usage\nCPU {0}%\nMemory {1} / {2}GB ({3}%){4}",
|
||||||
"PDF 로 만들기": "Make PDF",
|
"PDF 로 만들기": "Make PDF",
|
||||||
"PDF 로 바꾸는 중: {0}": "Converting to PDF: {0}",
|
"PDF 로 바꾸는 중: {0}": "Converting to PDF: {0}",
|
||||||
|
"PDF 로 바꾸지 못했습니다 ({0}) {1}": "Could not convert to PDF ({0}) {1}",
|
||||||
"PDF 를 만들지 못했습니다: {0}": "Could not make the PDF: {0}",
|
"PDF 를 만들지 못했습니다: {0}": "Could not make the PDF: {0}",
|
||||||
"PDF 를 열 수 없습니다: {0}": "Cannot open the PDF: {0}",
|
"PDF 를 열 수 없습니다: {0}": "Cannot open the PDF: {0}",
|
||||||
"PDF 에 넣을 그림 선택": "Choose images to add to the PDF",
|
"PDF 에 넣을 그림 선택": "Choose images to add to the PDF",
|
||||||
|
|
@ -195,11 +197,13 @@
|
||||||
"TAESD (빠른 디코더)": "TAESD (fast decoder)",
|
"TAESD (빠른 디코더)": "TAESD (fast decoder)",
|
||||||
"VLC 가 설치되어 있지 않습니다. 설치하면 목록에 나타납니다 (videolan.org).": "VLC is not installed. Once installed it appears in the list (videolan.org).",
|
"VLC 가 설치되어 있지 않습니다. 설치하면 목록에 나타납니다 (videolan.org).": "VLC is not installed. Once installed it appears in the list (videolan.org).",
|
||||||
"VLC 로 열기": "Open with VLC",
|
"VLC 로 열기": "Open with VLC",
|
||||||
|
"WebDAV {0} 실패: {1} {2}{3}": "WebDAV {0} failed: {1} {2}{3}",
|
||||||
"WebDAV · OpenSubtitles 등. 서버 목록과 아이디는 남깁니다": "WebDAV, OpenSubtitles, etc. Server list and user names are kept",
|
"WebDAV · OpenSubtitles 등. 서버 목록과 아이디는 남깁니다": "WebDAV, OpenSubtitles, etc. Server list and user names are kept",
|
||||||
"WebDAV · OpenSubtitles 비밀번호를 이 기기의 안전 저장소에 둡니다. 끄면 저장하지 않고 (있던 것도 지움) 앱을 켤 때마다 다시 넣습니다": "Keeps WebDAV and OpenSubtitles passwords in this device's secure storage. When off, nothing is saved (existing ones are removed) and you enter them each time the app starts",
|
"WebDAV · OpenSubtitles 비밀번호를 이 기기의 안전 저장소에 둡니다. 끄면 저장하지 않고 (있던 것도 지움) 앱을 켤 때마다 다시 넣습니다": "Keeps WebDAV and OpenSubtitles passwords in this device's secure storage. When off, nothing is saved (existing ones are removed) and you enter them each time the app starts",
|
||||||
"WebDAV 서버 \"{0}\" 을(를) 지울까요?": "Delete WebDAV server \"{0}\"?",
|
"WebDAV 서버 \"{0}\" 을(를) 지울까요?": "Delete WebDAV server \"{0}\"?",
|
||||||
"WebDAV 서버 고치기": "Edit WebDAV server",
|
"WebDAV 서버 고치기": "Edit WebDAV server",
|
||||||
"WebDAV 서버 목록과 그 저장된 비밀번호도 지워집니다. 동영상 목록 · 즐겨찾기 · 파일은 그대로입니다": "The WebDAV server list and its saved passwords are deleted too. The video list, bookmarks and files are kept",
|
"WebDAV 서버 목록과 그 저장된 비밀번호도 지워집니다. 동영상 목록 · 즐겨찾기 · 파일은 그대로입니다": "The WebDAV server list and its saved passwords are deleted too. The video list, bookmarks and files are kept",
|
||||||
|
"WebDAV 서버 설정이 없습니다 ({0})": "No WebDAV server settings ({0})",
|
||||||
"WebDAV 서버 추가": "Add WebDAV server",
|
"WebDAV 서버 추가": "Add WebDAV server",
|
||||||
"WebDAV 에서 받는 중": "Downloading from WebDAV",
|
"WebDAV 에서 받는 중": "Downloading from WebDAV",
|
||||||
"WebDAV 원본에 씁니다 (PC 의 폴더는 바뀌면 바로 맞춤). 짧을수록 빨리 맞추지만 서버 · 배터리를 더 씁니다.": "Used for WebDAV sources (PC folders sync as soon as they change). Shorter means faster syncing but more server and battery use.",
|
"WebDAV 원본에 씁니다 (PC 의 폴더는 바뀌면 바로 맞춤). 짧을수록 빨리 맞추지만 서버 · 배터리를 더 씁니다.": "Used for WebDAV sources (PC folders sync as soon as they change). Shorter means faster syncing but more server and battery use.",
|
||||||
|
|
@ -245,6 +249,7 @@
|
||||||
"cookies.txt (Netscape 형식)": "cookies.txt (Netscape format)",
|
"cookies.txt (Netscape 형식)": "cookies.txt (Netscape format)",
|
||||||
"cookies.txt 파일…": "cookies.txt file…",
|
"cookies.txt 파일…": "cookies.txt file…",
|
||||||
"cron (분 시 일 월 요일) · 한 줄에 하나": "cron (minute hour day month weekday) · one per line",
|
"cron (분 시 일 월 요일) · 한 줄에 하나": "cron (minute hour day month weekday) · one per line",
|
||||||
|
"cron 은 다섯 칸입니다 (분 시 일 월 요일)": "cron has five fields (minute hour day month weekday)",
|
||||||
"ffmpeg 를 실행할 수 없습니다: {0}": "Cannot run ffmpeg: {0}",
|
"ffmpeg 를 실행할 수 없습니다: {0}": "Cannot run ffmpeg: {0}",
|
||||||
"ffmpeg 오류 (코드 {0})\n{1}": "ffmpeg error (code {0})\n{1}",
|
"ffmpeg 오류 (코드 {0})\n{1}": "ffmpeg error (code {0})\n{1}",
|
||||||
"http:// 주소는 아이디 · 비밀번호와 파일이 암호화되지 않고 그대로 갑니다. 같은 네트워크의 다른 사람이 볼 수 있으니 서버가 https 를 지원하면 https:// 로 바꾸세요.": "With an http:// address, the user name, password and files are sent unencrypted. Others on the same network can see them, so switch to https:// if the server supports it.",
|
"http:// 주소는 아이디 · 비밀번호와 파일이 암호화되지 않고 그대로 갑니다. 같은 네트워크의 다른 사람이 볼 수 있으니 서버가 https 를 지원하면 https:// 로 바꾸세요.": "With an http:// address, the user name, password and files are sent unencrypted. Others on the same network can see them, so switch to https:// if the server supports it.",
|
||||||
|
|
@ -252,6 +257,7 @@
|
||||||
"lsync 로 이동": "Move to lsync",
|
"lsync 로 이동": "Move to lsync",
|
||||||
"quit 시작": "quit started",
|
"quit 시작": "quit started",
|
||||||
"robocopy 옵션": "robocopy options",
|
"robocopy 옵션": "robocopy options",
|
||||||
|
"robocopy 종료 코드 {0}": "robocopy exit code {0}",
|
||||||
"rsync --delete · robocopy /PURGE. 끄면 대상에 더하기 · 바꾸기만": "rsync --delete · robocopy /PURGE. When off, only adds · updates in the target",
|
"rsync --delete · robocopy /PURGE. 끄면 대상에 더하기 · 바꾸기만": "rsync --delete · robocopy /PURGE. When off, only adds · updates in the target",
|
||||||
"rsync 가 없습니다 (환경 설정 > 파일 탐색기에서 내려받기 · 경로 지정)": "rsync is not available (Settings > File explorer: download · set path)",
|
"rsync 가 없습니다 (환경 설정 > 파일 탐색기에서 내려받기 · 경로 지정)": "rsync is not available (Settings > File explorer: download · set path)",
|
||||||
"rsync 가져오기": "Get rsync",
|
"rsync 가져오기": "Get rsync",
|
||||||
|
|
@ -265,9 +271,12 @@
|
||||||
"rsync 실행 파일": "rsync executable",
|
"rsync 실행 파일": "rsync executable",
|
||||||
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > Rsync 에서 확인하세요.": "Cannot find the rsync executable. Check Settings > Rsync.",
|
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > Rsync 에서 확인하세요.": "Cannot find the rsync executable. Check Settings > Rsync.",
|
||||||
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > 파일 탐색기에서 경로를 확인하세요.": "rsync executable not found. Check the path in Settings > File explorer.",
|
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > 파일 탐색기에서 경로를 확인하세요.": "rsync executable not found. Check the path in Settings > File explorer.",
|
||||||
|
"rsync 실행 파일이 없습니다": "The rsync executable is missing",
|
||||||
"rsync 양쪽 (⇄)": "rsync both ways (⇄)",
|
"rsync 양쪽 (⇄)": "rsync both ways (⇄)",
|
||||||
"rsync 에 고르기": "Pick for rsync",
|
"rsync 에 고르기": "Pick for rsync",
|
||||||
"rsync 옵션": "rsync options",
|
"rsync 옵션": "rsync options",
|
||||||
|
"rsync 종료 코드 {0}": "rsync exit code {0}",
|
||||||
|
"settings.json 없음": "settings.json missing",
|
||||||
"stable-diffusion.cpp (Windows · CPU · Vulkan)": "stable-diffusion.cpp (Windows · CPU · Vulkan)",
|
"stable-diffusion.cpp (Windows · CPU · Vulkan)": "stable-diffusion.cpp (Windows · CPU · Vulkan)",
|
||||||
"stable-diffusion.cpp (Windows · NVIDIA CUDA 12)": "stable-diffusion.cpp (Windows · NVIDIA CUDA 12)",
|
"stable-diffusion.cpp (Windows · NVIDIA CUDA 12)": "stable-diffusion.cpp (Windows · NVIDIA CUDA 12)",
|
||||||
"v{0} 받는 중": "Downloading v{0}",
|
"v{0} 받는 중": "Downloading v{0}",
|
||||||
|
|
@ -304,8 +313,10 @@
|
||||||
"{0} 외 {1}개": "{0} and {1} more",
|
"{0} 외 {1}개": "{0} and {1} more",
|
||||||
"{0} 은(는) 이미 이 폴더에 있어 옮길 것이 없습니다.\n{1}": "{0} is already in this folder, so there is nothing to move.\n{1}",
|
"{0} 은(는) 이미 이 폴더에 있어 옮길 것이 없습니다.\n{1}": "{0} is already in this folder, so there is nothing to move.\n{1}",
|
||||||
"{0} 을 담았습니다. 넣을 폴더에서 [붙여넣기] 를 누르세요 ({1}).": "Picked up {0}. Open the target folder and tap [Paste] ({1}).",
|
"{0} 을 담았습니다. 넣을 폴더에서 [붙여넣기] 를 누르세요 ({1}).": "Picked up {0}. Open the target folder and tap [Paste] ({1}).",
|
||||||
|
"{0} 을(를) 받지 못했습니다 ({1})": "Could not download {0} ({1})",
|
||||||
"{0} 을(를) 설치했습니다.": "Installed {0}.",
|
"{0} 을(를) 설치했습니다.": "Installed {0}.",
|
||||||
"{0} 을(를) 지울까요?": "Delete {0}?",
|
"{0} 을(를) 지울까요?": "Delete {0}?",
|
||||||
|
"{0} 의 SHA256 이 다릅니다 (손상되었거나 다른 파일). 설치를 멈췄습니다.": "The SHA256 of {0} does not match (damaged or a different file). Installation stopped.",
|
||||||
"{0} 이 비어 있습니다 (카드 · USB · 디스크를 넣은 뒤 다시 누르세요).": "{0} is empty (insert a card, USB drive or disc and tap again).",
|
"{0} 이 비어 있습니다 (카드 · USB · 디스크를 넣은 뒤 다시 누르세요).": "{0} is empty (insert a card, USB drive or disc and tap again).",
|
||||||
"{0} 인코더가 FFmpeg 에 없습니다.": "FFmpeg does not have the {0} encoder.",
|
"{0} 인코더가 FFmpeg 에 없습니다.": "FFmpeg does not have the {0} encoder.",
|
||||||
"{0} 전체": "All of {0}",
|
"{0} 전체": "All of {0}",
|
||||||
|
|
@ -401,6 +412,7 @@
|
||||||
"같은 화질이면 H.264 먼저 받기": "Prefer H.264 at the same quality",
|
"같은 화질이면 H.264 먼저 받기": "Prefer H.264 at the same quality",
|
||||||
"개수": "Count",
|
"개수": "Count",
|
||||||
"거꾸로": "Reverse",
|
"거꾸로": "Reverse",
|
||||||
|
"거꾸로 된 범위: {0}": "Reversed range: {0}",
|
||||||
"건너뛰기": "Skip",
|
"건너뛰기": "Skip",
|
||||||
"건너뜀 (출력 폴더의 파일): {0}": "Skipped (file in the output folder): {0}",
|
"건너뜀 (출력 폴더의 파일): {0}": "Skipped (file in the output folder): {0}",
|
||||||
"건너뜁니다": "skips it",
|
"건너뜁니다": "skips it",
|
||||||
|
|
@ -441,6 +453,7 @@
|
||||||
"공용 폴더에 받은 파일 (동영상 · 그림 등)": "Files downloaded to shared folders (videos, images, etc.)",
|
"공용 폴더에 받은 파일 (동영상 · 그림 등)": "Files downloaded to shared folders (videos, images, etc.)",
|
||||||
"관리 메뉴": "Manage menu",
|
"관리 메뉴": "Manage menu",
|
||||||
"광고 건너뛰는 중…": "Skipping ad…",
|
"광고 건너뛰는 중…": "Skipping ad…",
|
||||||
|
"권한 없음": "no permission",
|
||||||
"권한 허용 화면 열기": "Open the permission screen",
|
"권한 허용 화면 열기": "Open the permission screen",
|
||||||
"권한이 없습니다": "No permission",
|
"권한이 없습니다": "No permission",
|
||||||
"그 파일 하나만": "Only that file",
|
"그 파일 하나만": "Only that file",
|
||||||
|
|
@ -462,6 +475,7 @@
|
||||||
"그림을 바꿔 만들기": "Make from this picture",
|
"그림을 바꿔 만들기": "Make from this picture",
|
||||||
"그림을 받을 수 없습니다 ({0})": "Couldn't get the image ({0})",
|
"그림을 받을 수 없습니다 ({0})": "Couldn't get the image ({0})",
|
||||||
"그림을 올릴 수 없습니다 ({0})": "Couldn't upload the image ({0})",
|
"그림을 올릴 수 없습니다 ({0})": "Couldn't upload the image ({0})",
|
||||||
|
"그림을 읽을 수 없습니다": "Cannot read the image",
|
||||||
"그림을 페이지로 넣기 (이 페이지 뒤)": "Add images as pages (after this page)",
|
"그림을 페이지로 넣기 (이 페이지 뒤)": "Add images as pages (after this page)",
|
||||||
"그림이 거의 같고 마지막 단계가 10배쯤 빠릅니다 (받아 두었을 때)": "Almost the same image, and the last step is about 10× faster (when downloaded)",
|
"그림이 거의 같고 마지막 단계가 10배쯤 빠릅니다 (받아 두었을 때)": "Almost the same image, and the last step is about 10× faster (when downloaded)",
|
||||||
"글을 격자에 반영": "Apply text to grid",
|
"글을 격자에 반영": "Apply text to grid",
|
||||||
|
|
@ -575,6 +589,7 @@
|
||||||
"다른 언어로 번역 (AI · 이 {0}에서)": "Translate to another language (AI · on this {0})",
|
"다른 언어로 번역 (AI · 이 {0}에서)": "Translate to another language (AI · on this {0})",
|
||||||
"다른 이름으로 저장": "Save as",
|
"다른 이름으로 저장": "Save as",
|
||||||
"다른 이름으로 저장: {0} ({1})": "Save as: {0} ({1})",
|
"다른 이름으로 저장: {0} ({1})": "Save as: {0} ({1})",
|
||||||
|
"다른 저장소로는 이름만 바꿀 수 없습니다": "Cannot just rename onto another storage",
|
||||||
"다른 창 폴더로": "To the other pane's folder",
|
"다른 창 폴더로": "To the other pane's folder",
|
||||||
"다른 창에서 열기": "Open in other pane",
|
"다른 창에서 열기": "Open in other pane",
|
||||||
"다른 창으로 복사": "Copy to other pane",
|
"다른 창으로 복사": "Copy to other pane",
|
||||||
|
|
@ -786,6 +801,7 @@
|
||||||
"모두 풀기": "Extract all",
|
"모두 풀기": "Extract all",
|
||||||
"모든 작업 취소": "Cancel all jobs",
|
"모든 작업 취소": "Cancel all jobs",
|
||||||
"목": "Thu",
|
"목": "Thu",
|
||||||
|
"목록": "list",
|
||||||
"목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "Hides ad areas in lists · next to · on top of videos",
|
"목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "Hides ad areas in lists · next to · on top of videos",
|
||||||
"목록 보기": "View list",
|
"목록 보기": "View list",
|
||||||
"목록에서 빼기": "Remove from list",
|
"목록에서 빼기": "Remove from list",
|
||||||
|
|
@ -800,6 +816,7 @@
|
||||||
"무엇이 바뀌는지 비교하는 중…": "Comparing what will change…",
|
"무엇이 바뀌는지 비교하는 중…": "Comparing what will change…",
|
||||||
"무한": "Unlimited",
|
"무한": "Unlimited",
|
||||||
"문서 미리보기": "Document preview",
|
"문서 미리보기": "Document preview",
|
||||||
|
"문서 미리보기 컴포넌트를 먼저 설치하세요": "Install the document preview component first",
|
||||||
"문자셋 경고": "Charset warning",
|
"문자셋 경고": "Charset warning",
|
||||||
"묻기": "Ask",
|
"묻기": "Ask",
|
||||||
"물어보지 않기": "Never ask",
|
"물어보지 않기": "Never ask",
|
||||||
|
|
@ -828,6 +845,7 @@
|
||||||
"받기 ({0})": "Download ({0})",
|
"받기 ({0})": "Download ({0})",
|
||||||
"받기 화면으로": "Go to downloads",
|
"받기 화면으로": "Go to downloads",
|
||||||
"받는 중": "Downloading",
|
"받는 중": "Downloading",
|
||||||
|
"받는 중: {0}": "Downloading: {0}",
|
||||||
"받는 중이거나 일시정지한 다운로드가 있어 건너뜁니다 (이어받기가 깨지지 않게)": "Skipped because downloads are running or paused (so they can resume)",
|
"받는 중이거나 일시정지한 다운로드가 있어 건너뜁니다 (이어받기가 깨지지 않게)": "Skipped because downloads are running or paused (so they can resume)",
|
||||||
"받는 중인 다운로드 {0}개": "{0} downloads in progress",
|
"받는 중인 다운로드 {0}개": "{0} downloads in progress",
|
||||||
"받는 중인 다운로드가 없습니다.": "Nothing is downloading.",
|
"받는 중인 다운로드가 없습니다.": "Nothing is downloading.",
|
||||||
|
|
@ -876,8 +894,11 @@
|
||||||
"번역 모델: NLLB-200 (로컬) ": "Translation model: NLLB-200 (local) ",
|
"번역 모델: NLLB-200 (로컬) ": "Translation model: NLLB-200 (local) ",
|
||||||
"번역 모델: NLLB-200 (이 {0}에서만) ": "Translation model: NLLB-200 (only on this {0}) ",
|
"번역 모델: NLLB-200 (이 {0}에서만) ": "Translation model: NLLB-200 (only on this {0}) ",
|
||||||
"번역 모델을 먼저 불러와야 합니다.": "The translation model must be loaded first.",
|
"번역 모델을 먼저 불러와야 합니다.": "The translation model must be loaded first.",
|
||||||
|
"번역 서버 응답 {0}": "Translation server response {0}",
|
||||||
"번역 시작": "Start translation",
|
"번역 시작": "Start translation",
|
||||||
|
"번역 응답의 개수가 다릅니다 ({0} / {1})": "The number of translation results does not match ({0} / {1})",
|
||||||
"번역할 언어 (jj_mkv\\파일명_언어코드.srt 로 저장 후 MKV 에 추가)": "Languages to translate to (saved as jj_mkv\\filename_languagecode.srt and added to the MKV)",
|
"번역할 언어 (jj_mkv\\파일명_언어코드.srt 로 저장 후 MKV 에 추가)": "Languages to translate to (saved as jj_mkv\\filename_languagecode.srt and added to the MKV)",
|
||||||
|
"범위 밖 값: {0} ({1}~{2})": "Value out of range: {0} ({1}~{2})",
|
||||||
"베트남어": "Vietnamese",
|
"베트남어": "Vietnamese",
|
||||||
"벵골어": "Bengali",
|
"벵골어": "Bengali",
|
||||||
"변경 내용을 저장하지 않고 나갈까요?": "Leave without saving the changes?",
|
"변경 내용을 저장하지 않고 나갈까요?": "Leave without saving the changes?",
|
||||||
|
|
@ -985,11 +1006,13 @@
|
||||||
"서버 설정 고치기": "Edit server settings",
|
"서버 설정 고치기": "Edit server settings",
|
||||||
"서버 설정과 이 기기에 저장된 비밀번호를 지웁니다. 서버의 파일은 그대로입니다. 이 서버를 쓰는 동기화 · 복사는 다시 넣을 때까지 연결되지 않습니다.": "Deletes the server setting and the password saved on this device. Files on the server stay as they are. Syncs and copies using this server won't connect until you add it again.",
|
"서버 설정과 이 기기에 저장된 비밀번호를 지웁니다. 서버의 파일은 그대로입니다. 이 서버를 쓰는 동기화 · 복사는 다시 넣을 때까지 연결되지 않습니다.": "Deletes the server setting and the password saved on this device. Files on the server stay as they are. Syncs and copies using this server won't connect until you add it again.",
|
||||||
"서버 인증서를 확인할 수 없습니다": "Cannot verify the server certificate",
|
"서버 인증서를 확인할 수 없습니다": "Cannot verify the server certificate",
|
||||||
|
"서버 저장 공간 부족": "server storage full",
|
||||||
"서버가 https 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 https:// 로 바꾸세요.": "The server asks to move to an https address ({0}). Change the server address to https://.",
|
"서버가 https 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 https:// 로 바꾸세요.": "The server asks to move to an https address ({0}). Change the server address to https://.",
|
||||||
"서버가 거절했습니다 ({0}): {1}": "The server refused ({0}): {1}",
|
"서버가 거절했습니다 ({0}): {1}": "The server refused ({0}): {1}",
|
||||||
"서버가 그림을 돌려주지 않았습니다": "The server returned no image",
|
"서버가 그림을 돌려주지 않았습니다": "The server returned no image",
|
||||||
"서버가 너무 오래 답하지 않습니다": "The server isn't responding for too long",
|
"서버가 너무 오래 답하지 않습니다": "The server isn't responding for too long",
|
||||||
"서버가 다른 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 확인하세요.": "The server asks to move to another address ({0}). Check the server address.",
|
"서버가 다른 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 확인하세요.": "The server asks to move to another address ({0}). Check the server address.",
|
||||||
|
"서버가 이 기능을 허용하지 않음": "the server does not allow this",
|
||||||
"서버에 닿지 않습니다": "Cannot reach the server",
|
"서버에 닿지 않습니다": "Cannot reach the server",
|
||||||
"서버에서 이 계정의 권한을 확인하세요.": "Check this account's permissions on the server.",
|
"서버에서 이 계정의 권한을 확인하세요.": "Check this account's permissions on the server.",
|
||||||
"서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.": "You need to be on the same network as the server or have a VPN (e.g. Tailscale) on. Turn it on, then tap [Try again].",
|
"서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.": "You need to be on the same network as the server or have a VPN (e.g. Tailscale) on. Turn it on, then tap [Try again].",
|
||||||
|
|
@ -1027,6 +1050,7 @@
|
||||||
"설치 실패": "Install failed",
|
"설치 실패": "Install failed",
|
||||||
"설치 준비 완료": "Ready to install",
|
"설치 준비 완료": "Ready to install",
|
||||||
"설치 파일: {0}\n이제 앱을 지운 뒤, 파일 앱에서 이 파일을 눌러 설치하세요.": "Install file: {0}\nNow uninstall the app, then tap this file in a file manager to install it.",
|
"설치 파일: {0}\n이제 앱을 지운 뒤, 파일 앱에서 이 파일을 눌러 설치하세요.": "Install file: {0}\nNow uninstall the app, then tap this file in a file manager to install it.",
|
||||||
|
"설치 파일을 풀 수 없습니다 (msiexec {0})": "Could not extract the installer (msiexec {0})",
|
||||||
"설치 허용 필요": "Permission needed to install",
|
"설치 허용 필요": "Permission needed to install",
|
||||||
"설치 화면을 열 수 없습니다: {0}": "Cannot open the install screen: {0}",
|
"설치 화면을 열 수 없습니다: {0}": "Cannot open the install screen: {0}",
|
||||||
"설치가 끝나면 프로그램이 다시 시작됩니다.": "The program restarts when the installation finishes.",
|
"설치가 끝나면 프로그램이 다시 시작됩니다.": "The program restarts when the installation finishes.",
|
||||||
|
|
@ -1103,6 +1127,7 @@
|
||||||
"실행한 rsync 가 없습니다. Rsync 화면에서 → · ← · ⇄ 로 실행하면 여기에 자동으로 등록됩니다.": "No rsync runs yet. Runs started with → · ← · ⇄ on the Rsync screen are added here automatically.",
|
"실행한 rsync 가 없습니다. Rsync 화면에서 → · ← · ⇄ 로 실행하면 여기에 자동으로 등록됩니다.": "No rsync runs yet. Runs started with → · ← · ⇄ on the Rsync screen are added here automatically.",
|
||||||
"싱크": "Sync",
|
"싱크": "Sync",
|
||||||
"쓰레드 확인 (AI · 변환 작업이 멈출 때까지)": "Thread check (until AI · conversion jobs stop)",
|
"쓰레드 확인 (AI · 변환 작업이 멈출 때까지)": "Thread check (until AI · conversion jobs stop)",
|
||||||
|
"쓸 수 없는 이름입니다": "This name cannot be used",
|
||||||
"아랍어": "Arabic",
|
"아랍어": "Arabic",
|
||||||
"아래 프로그램이 없어 일부 기능을 쓸 수 없습니다. 공식 배포처에서 내려받아 프로그램 폴더에 설치할까요?": "Some features are unavailable because the programs below are missing. Download them from the official sources and install them in the program folder?",
|
"아래 프로그램이 없어 일부 기능을 쓸 수 없습니다. 공식 배포처에서 내려받아 프로그램 폴더에 설치할까요?": "Some features are unavailable because the programs below are missing. Download them from the official sources and install them in the program folder?",
|
||||||
"아래로": "Down",
|
"아래로": "Down",
|
||||||
|
|
@ -1110,6 +1135,7 @@
|
||||||
"아무것도 안 함": "Do nothing",
|
"아무것도 안 함": "Do nothing",
|
||||||
"아이디": "User name",
|
"아이디": "User name",
|
||||||
"아이디 (선택)": "Username (optional)",
|
"아이디 (선택)": "Username (optional)",
|
||||||
|
"아이디 · 비밀번호를 확인하세요": "check the user name and password",
|
||||||
"아이디 또는 비밀번호가 맞지 않습니다": "The user name or password is wrong",
|
"아이디 또는 비밀번호가 맞지 않습니다": "The user name or password is wrong",
|
||||||
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "You can enter the username · password in Settings (optional, raises the daily download limit).",
|
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "You can enter the username · password in Settings (optional, raises the daily download limit).",
|
||||||
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "Icons · list look: X-plore (thumbnails · two lines) · Windows Explorer (color icons · columns) · Total Commander (dense list · [folders])",
|
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "Icons · list look: X-plore (thumbnails · two lines) · Windows Explorer (color icons · columns) · Total Commander (dense list · [folders])",
|
||||||
|
|
@ -1160,6 +1186,8 @@
|
||||||
"업데이트 · 설치하고 남은 파일": "Update · install leftovers",
|
"업데이트 · 설치하고 남은 파일": "Update · install leftovers",
|
||||||
"업데이트 실패: {0}": "Update failed: {0}",
|
"업데이트 실패: {0}": "Update failed: {0}",
|
||||||
"업데이트로 바뀐 기본값 알림": "Notify about defaults changed by updates",
|
"업데이트로 바뀐 기본값 알림": "Notify about defaults changed by updates",
|
||||||
|
"없는 경로": "path not found",
|
||||||
|
"없는 경로: {0}": "path not found: {0}",
|
||||||
"없음": "None",
|
"없음": "None",
|
||||||
"없음: 세부 정보의 [이동] 을 처음 누를 때 폴더를 골라 하나 만듭니다": "None: one is created when you first press [Move] in the details",
|
"없음: 세부 정보의 [이동] 을 처음 누를 때 폴더를 골라 하나 만듭니다": "None: one is created when you first press [Move] in the details",
|
||||||
"엔진": "Engine",
|
"엔진": "Engine",
|
||||||
|
|
@ -1206,6 +1234,7 @@
|
||||||
"오른쪽 90°": "Right 90°",
|
"오른쪽 90°": "Right 90°",
|
||||||
"오픈 소스 라이선스": "Open source licenses",
|
"오픈 소스 라이선스": "Open source licenses",
|
||||||
"올려 둔 버전이 없습니다.": "No versions have been published.",
|
"올려 둔 버전이 없습니다.": "No versions have been published.",
|
||||||
|
"올리기": "upload",
|
||||||
"올린 것": "Upscaled",
|
"올린 것": "Upscaled",
|
||||||
"올린 것 (AI)": "Upscaled (AI)",
|
"올린 것 (AI)": "Upscaled (AI)",
|
||||||
"올린 것으로 계속 보기": "Keep viewing the upscaled one",
|
"올린 것으로 계속 보기": "Keep viewing the upscaled one",
|
||||||
|
|
@ -1318,6 +1347,7 @@
|
||||||
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "About {0} per image on this device (based on last time)",
|
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "About {0} per image on this device (based on last time)",
|
||||||
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "About {0} per image, {1} in total on this device (based on last time)",
|
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "About {0} per image, {1} in total on this device (based on last time)",
|
||||||
"이 기기에서는 AI 번역을 쓸 수 없습니다.": "AI translation is not available on this device.",
|
"이 기기에서는 AI 번역을 쓸 수 없습니다.": "AI translation is not available on this device.",
|
||||||
|
"이 기기에서는 쓸 수 없는 컴포넌트입니다": "This component is not available on this device",
|
||||||
"이 기기용 파일 없음": "No file for this device",
|
"이 기기용 파일 없음": "No file for this device",
|
||||||
"이 기기의 안전 저장소를 쓸 수 없어 비밀번호를 저장하지 못했습니다": "Couldn't save the password because this device's secure storage is unavailable",
|
"이 기기의 안전 저장소를 쓸 수 없어 비밀번호를 저장하지 못했습니다": "Couldn't save the password because this device's secure storage is unavailable",
|
||||||
"이 기기의 폴더": "Folder on this device",
|
"이 기기의 폴더": "Folder on this device",
|
||||||
|
|
@ -1488,6 +1518,9 @@
|
||||||
"작업하다 남은 임시 파일 · 받다 만 다운로드 (.part 등) · 받다 만 AI 모델 · 업데이트하고 남은 파일 · 지난 작업 기록을 찾아 지웁니다. 받은 동영상 · 만든 MKV · 자막은 지우지 않고, 진행 중인 작업 · 다운로드가 쓰는 것은 건너뜁니다": "Finds and deletes temporary files left from jobs · unfinished downloads (.part etc.) · unfinished AI models · update leftovers · old job logs. Downloaded videos · made MKVs · subtitles are not deleted, and anything used by running jobs · downloads is skipped",
|
"작업하다 남은 임시 파일 · 받다 만 다운로드 (.part 등) · 받다 만 AI 모델 · 업데이트하고 남은 파일 · 지난 작업 기록을 찾아 지웁니다. 받은 동영상 · 만든 MKV · 자막은 지우지 않고, 진행 중인 작업 · 다운로드가 쓰는 것은 건너뜁니다": "Finds and deletes temporary files left from jobs · unfinished downloads (.part etc.) · unfinished AI models · update leftovers · old job logs. Downloaded videos · made MKVs · subtitles are not deleted, and anything used by running jobs · downloads is skipped",
|
||||||
"작은 용량": "Small size",
|
"작은 용량": "Small size",
|
||||||
"잘못된 varint (위치 {0})": "Invalid varint (position {0})",
|
"잘못된 varint (위치 {0})": "Invalid varint (position {0})",
|
||||||
|
"잘못된 간격: {0}": "Invalid step: {0}",
|
||||||
|
"잘못된 범위: {0}": "Invalid range: {0}",
|
||||||
|
"잘못된 칸: {0}": "Invalid field: {0}",
|
||||||
"재개": "Resume",
|
"재개": "Resume",
|
||||||
"재생": "Play",
|
"재생": "Play",
|
||||||
"재생 목록": "Playlist",
|
"재생 목록": "Playlist",
|
||||||
|
|
@ -1719,6 +1752,7 @@
|
||||||
"칠한 시간이 없어 동기화하지 않습니다.": "No hours painted, so nothing will sync.",
|
"칠한 시간이 없어 동기화하지 않습니다.": "No hours painted, so nothing will sync.",
|
||||||
"칸에 보이는 옵션: {0}\n저장된 옵션: {1}\n\n고친 옵션을 저장하고 실행할까요?": "Options in the field: {0}\nSaved options: {1}\n\nSave the edited options and run?",
|
"칸에 보이는 옵션: {0}\n저장된 옵션: {1}\n\n고친 옵션을 저장하고 실행할까요?": "Options in the field: {0}\nSaved options: {1}\n\nSave the edited options and run?",
|
||||||
"컴포넌트": "Components",
|
"컴포넌트": "Components",
|
||||||
|
"컴포넌트 목록을 받을 수 없습니다 ({0})": "Could not get the component list ({0})",
|
||||||
"켜기": "On",
|
"켜기": "On",
|
||||||
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "When on, double-tapping shows the images inside right away. When off, opens the file list (extract selected).",
|
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "When on, double-tapping shows the images inside right away. When off, opens the file list (extract selected).",
|
||||||
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "Turning it on downloads and installs a converter (about 420MB). Turning it off deletes it.",
|
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "Turning it on downloads and installs a converter (about 420MB). Turning it off deletes it.",
|
||||||
|
|
@ -1772,10 +1806,12 @@
|
||||||
"파일이 깨졌습니다": "The file is damaged",
|
"파일이 깨졌습니다": "The file is damaged",
|
||||||
"파일이 깨졌습니다 · [다시 받기] 를 눌러 주세요": "The file is damaged · tap [Download again]",
|
"파일이 깨졌습니다 · [다시 받기] 를 눌러 주세요": "The file is damaged · tap [Download again]",
|
||||||
"파일이 보이지 않습니다: \"모든 파일에 대한 접근\" 권한이 없습니다": "Files are not shown: \"All files access\" is not allowed",
|
"파일이 보이지 않습니다: \"모든 파일에 대한 접근\" 권한이 없습니다": "Files are not shown: \"All files access\" is not allowed",
|
||||||
|
"파일이 손상되었습니다 (SHA-256 다름): {0}": "The file is damaged (SHA-256 mismatch): {0}",
|
||||||
"파일이 없습니다 (지워졌거나 옮겨짐)": "File not found (deleted or moved)",
|
"파일이 없습니다 (지워졌거나 옮겨짐)": "File not found (deleted or moved)",
|
||||||
"팝업 끄기": "Close pop-up",
|
"팝업 끄기": "Close pop-up",
|
||||||
"팝업 보기": "Pop-up view",
|
"팝업 보기": "Pop-up view",
|
||||||
"패키지 라이선스": "Package licenses",
|
"패키지 라이선스": "Package licenses",
|
||||||
|
"패키지에 {0} 이 없습니다": "{0} is missing from the package",
|
||||||
"페르시아어": "Persian",
|
"페르시아어": "Persian",
|
||||||
"페이지 열기": "Open page",
|
"페이지 열기": "Open page",
|
||||||
"페이지 지우기": "Delete page",
|
"페이지 지우기": "Delete page",
|
||||||
|
|
@ -1809,6 +1845,7 @@
|
||||||
"폴더가 없습니다": "The folder does not exist",
|
"폴더가 없습니다": "The folder does not exist",
|
||||||
"폴더는 보여도 그 안의 동영상 · 파일은 이 권한이 있어야 보입니다. 허용 화면에서 JJ_MKVMaker 를 켜고 돌아오세요.": "Folders are shown, but the videos and files inside need this permission. Turn on JJ_MKVMaker on the permission screen and come back.",
|
"폴더는 보여도 그 안의 동영상 · 파일은 이 권한이 있어야 보입니다. 허용 화면에서 JJ_MKVMaker 를 켜고 돌아오세요.": "Folders are shown, but the videos and files inside need this permission. Turn on JJ_MKVMaker on the permission screen and come back.",
|
||||||
"폴더를 만들 수 없습니다: {0}": "Cannot create the folder: {0}",
|
"폴더를 만들 수 없습니다: {0}": "Cannot create the folder: {0}",
|
||||||
|
"폴더를 자기 안으로 복사 · 이동할 수 없습니다": "Cannot copy or move a folder into itself",
|
||||||
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "Cannot {0} a folder into itself: {1}",
|
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "Cannot {0} a folder into itself: {1}",
|
||||||
"폴더만 lsync 로 옮길 수 있습니다.": "Only folders can be moved to lsync.",
|
"폴더만 lsync 로 옮길 수 있습니다.": "Only folders can be moved to lsync.",
|
||||||
"폴란드어": "Polish",
|
"폴란드어": "Polish",
|
||||||
|
|
@ -1818,6 +1855,7 @@
|
||||||
"표시 지우기": "Clear marks",
|
"표시 지우기": "Clear marks",
|
||||||
"표준": "Standard",
|
"표준": "Standard",
|
||||||
"푸는 중": "Extracting",
|
"푸는 중": "Extracting",
|
||||||
|
"푸는 중: {0}": "Extracting: {0}",
|
||||||
"풀지 못했습니다: {0}": "Could not extract: {0}",
|
"풀지 못했습니다: {0}": "Could not extract: {0}",
|
||||||
"프랑스어": "French",
|
"프랑스어": "French",
|
||||||
"프로그램": "Program",
|
"프로그램": "Program",
|
||||||
|
|
@ -1898,6 +1936,8 @@
|
||||||
"확인 창에서 알린 뒤 허용합니다. 지우기 (--delete) 가 있으면 늘 막습니다. 끄면 늘 막습니다": "Allowed after a notice in the confirmation. Always blocked with delete (--delete). When off, always blocked",
|
"확인 창에서 알린 뒤 허용합니다. 지우기 (--delete) 가 있으면 늘 막습니다. 끄면 늘 막습니다": "Allowed after a notice in the confirmation. Always blocked with delete (--delete). When off, always blocked",
|
||||||
"확인됨": "Verified",
|
"확인됨": "Verified",
|
||||||
"확장 설치": "Installing extension",
|
"확장 설치": "Installing extension",
|
||||||
|
"확장 설치: {0}": "Installing extension: {0}",
|
||||||
|
"확장을 설치할 수 없습니다 ({0}): {1}": "Could not install the extension ({0}): {1}",
|
||||||
"확장자": "Ext",
|
"확장자": "Ext",
|
||||||
"확장자별 재생 프로그램": "Player per file extension",
|
"확장자별 재생 프로그램": "Player per file extension",
|
||||||
"환경 설정": "Settings",
|
"환경 설정": "Settings",
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@
|
||||||
"JPG 품질 {0}": "JPG 品質 {0}",
|
"JPG 품질 {0}": "JPG 品質 {0}",
|
||||||
"JavaScript 사용": "JavaScript を使う",
|
"JavaScript 사용": "JavaScript を使う",
|
||||||
"LCM-LoRA (SD1.5, 4단계로 빠르게)": "LCM-LoRA (SD1.5、4 ステップで高速)",
|
"LCM-LoRA (SD1.5, 4단계로 빠르게)": "LCM-LoRA (SD1.5、4 ステップで高速)",
|
||||||
|
"LibreOffice 를 먼저 설치해야 합니다": "先に LibreOffice をインストールする必要があります",
|
||||||
"MKV · AI 작업": "MKV・AI 作業",
|
"MKV · AI 작업": "MKV・AI 作業",
|
||||||
"MKV · 자막 (jj_mkv)": "MKV・字幕(jj_mkv)",
|
"MKV · 자막 (jj_mkv)": "MKV・字幕(jj_mkv)",
|
||||||
"MKV · 자막 저장 위치": "MKV・字幕の保存先",
|
"MKV · 자막 저장 위치": "MKV・字幕の保存先",
|
||||||
|
|
@ -179,6 +180,7 @@
|
||||||
"PC 전체 사용량\nCPU {0}%\n메모리 {1} / {2}GB ({3}%){4}": "PC 全体の使用量\nCPU {0}%\nメモリ {1} / {2}GB({3}%){4}",
|
"PC 전체 사용량\nCPU {0}%\n메모리 {1} / {2}GB ({3}%){4}": "PC 全体の使用量\nCPU {0}%\nメモリ {1} / {2}GB({3}%){4}",
|
||||||
"PDF 로 만들기": "PDF を作成",
|
"PDF 로 만들기": "PDF を作成",
|
||||||
"PDF 로 바꾸는 중: {0}": "PDF に変換中: {0}",
|
"PDF 로 바꾸는 중: {0}": "PDF に変換中: {0}",
|
||||||
|
"PDF 로 바꾸지 못했습니다 ({0}) {1}": "PDF に変換できませんでした ({0}) {1}",
|
||||||
"PDF 를 만들지 못했습니다: {0}": "PDF を作成できませんでした: {0}",
|
"PDF 를 만들지 못했습니다: {0}": "PDF を作成できませんでした: {0}",
|
||||||
"PDF 를 열 수 없습니다: {0}": "PDF を開けません: {0}",
|
"PDF 를 열 수 없습니다: {0}": "PDF を開けません: {0}",
|
||||||
"PDF 에 넣을 그림 선택": "PDF に追加する画像を選択",
|
"PDF 에 넣을 그림 선택": "PDF に追加する画像を選択",
|
||||||
|
|
@ -195,11 +197,13 @@
|
||||||
"TAESD (빠른 디코더)": "TAESD (高速デコーダー)",
|
"TAESD (빠른 디코더)": "TAESD (高速デコーダー)",
|
||||||
"VLC 가 설치되어 있지 않습니다. 설치하면 목록에 나타납니다 (videolan.org).": "VLC がインストールされていません。インストールするとリストに表示されます(videolan.org)。",
|
"VLC 가 설치되어 있지 않습니다. 설치하면 목록에 나타납니다 (videolan.org).": "VLC がインストールされていません。インストールするとリストに表示されます(videolan.org)。",
|
||||||
"VLC 로 열기": "VLC で開く",
|
"VLC 로 열기": "VLC で開く",
|
||||||
|
"WebDAV {0} 실패: {1} {2}{3}": "WebDAV {0} 失敗: {1} {2}{3}",
|
||||||
"WebDAV · OpenSubtitles 등. 서버 목록과 아이디는 남깁니다": "WebDAV・OpenSubtitles など。サーバー一覧と ID は残します",
|
"WebDAV · OpenSubtitles 등. 서버 목록과 아이디는 남깁니다": "WebDAV・OpenSubtitles など。サーバー一覧と ID は残します",
|
||||||
"WebDAV · OpenSubtitles 비밀번호를 이 기기의 안전 저장소에 둡니다. 끄면 저장하지 않고 (있던 것도 지움) 앱을 켤 때마다 다시 넣습니다": "WebDAV・OpenSubtitles のパスワードをこの端末の安全な保存領域に保存します。オフにすると保存せず (既存のものも削除)、アプリを起動するたびに入力します",
|
"WebDAV · OpenSubtitles 비밀번호를 이 기기의 안전 저장소에 둡니다. 끄면 저장하지 않고 (있던 것도 지움) 앱을 켤 때마다 다시 넣습니다": "WebDAV・OpenSubtitles のパスワードをこの端末の安全な保存領域に保存します。オフにすると保存せず (既存のものも削除)、アプリを起動するたびに入力します",
|
||||||
"WebDAV 서버 \"{0}\" 을(를) 지울까요?": "WebDAV サーバー「{0}」を削除しますか?",
|
"WebDAV 서버 \"{0}\" 을(를) 지울까요?": "WebDAV サーバー「{0}」を削除しますか?",
|
||||||
"WebDAV 서버 고치기": "WebDAV サーバーを編集",
|
"WebDAV 서버 고치기": "WebDAV サーバーを編集",
|
||||||
"WebDAV 서버 목록과 그 저장된 비밀번호도 지워집니다. 동영상 목록 · 즐겨찾기 · 파일은 그대로입니다": "WebDAV サーバー一覧とその保存したパスワードも消えます。動画リスト・お気に入り・ファイルはそのままです",
|
"WebDAV 서버 목록과 그 저장된 비밀번호도 지워집니다. 동영상 목록 · 즐겨찾기 · 파일은 그대로입니다": "WebDAV サーバー一覧とその保存したパスワードも消えます。動画リスト・お気に入り・ファイルはそのままです",
|
||||||
|
"WebDAV 서버 설정이 없습니다 ({0})": "WebDAV サーバー設定がありません ({0})",
|
||||||
"WebDAV 서버 추가": "WebDAV サーバーを追加",
|
"WebDAV 서버 추가": "WebDAV サーバーを追加",
|
||||||
"WebDAV 에서 받는 중": "WebDAV からダウンロード中",
|
"WebDAV 에서 받는 중": "WebDAV からダウンロード中",
|
||||||
"WebDAV 원본에 씁니다 (PC 의 폴더는 바뀌면 바로 맞춤). 짧을수록 빨리 맞추지만 서버 · 배터리를 더 씁니다.": "WebDAV の元に使います (PC のフォルダーは変わるとすぐ同期)。短いほど早く同期しますが、サーバー・バッテリーをより使います。",
|
"WebDAV 원본에 씁니다 (PC 의 폴더는 바뀌면 바로 맞춤). 짧을수록 빨리 맞추지만 서버 · 배터리를 더 씁니다.": "WebDAV の元に使います (PC のフォルダーは変わるとすぐ同期)。短いほど早く同期しますが、サーバー・バッテリーをより使います。",
|
||||||
|
|
@ -245,6 +249,7 @@
|
||||||
"cookies.txt (Netscape 형식)": "cookies.txt(Netscape 形式)",
|
"cookies.txt (Netscape 형식)": "cookies.txt(Netscape 形式)",
|
||||||
"cookies.txt 파일…": "cookies.txt ファイル…",
|
"cookies.txt 파일…": "cookies.txt ファイル…",
|
||||||
"cron (분 시 일 월 요일) · 한 줄에 하나": "cron (分 時 日 月 曜日) · 1 行に 1 つ",
|
"cron (분 시 일 월 요일) · 한 줄에 하나": "cron (分 時 日 月 曜日) · 1 行に 1 つ",
|
||||||
|
"cron 은 다섯 칸입니다 (분 시 일 월 요일)": "cron は 5 項目です (分 時 日 月 曜日)",
|
||||||
"ffmpeg 를 실행할 수 없습니다: {0}": "ffmpeg を実行できません: {0}",
|
"ffmpeg 를 실행할 수 없습니다: {0}": "ffmpeg を実行できません: {0}",
|
||||||
"ffmpeg 오류 (코드 {0})\n{1}": "ffmpeg エラー(コード {0})\n{1}",
|
"ffmpeg 오류 (코드 {0})\n{1}": "ffmpeg エラー(コード {0})\n{1}",
|
||||||
"http:// 주소는 아이디 · 비밀번호와 파일이 암호화되지 않고 그대로 갑니다. 같은 네트워크의 다른 사람이 볼 수 있으니 서버가 https 를 지원하면 https:// 로 바꾸세요.": "http:// のアドレスでは ID・パスワードとファイルが暗号化されずに送られます。同じネットワークの他の人が見られるため、サーバーが https に対応していれば https:// に変えてください。",
|
"http:// 주소는 아이디 · 비밀번호와 파일이 암호화되지 않고 그대로 갑니다. 같은 네트워크의 다른 사람이 볼 수 있으니 서버가 https 를 지원하면 https:// 로 바꾸세요.": "http:// のアドレスでは ID・パスワードとファイルが暗号化されずに送られます。同じネットワークの他の人が見られるため、サーバーが https に対応していれば https:// に変えてください。",
|
||||||
|
|
@ -252,6 +257,7 @@
|
||||||
"lsync 로 이동": "lsync へ移動",
|
"lsync 로 이동": "lsync へ移動",
|
||||||
"quit 시작": "終了開始",
|
"quit 시작": "終了開始",
|
||||||
"robocopy 옵션": "robocopy オプション",
|
"robocopy 옵션": "robocopy オプション",
|
||||||
|
"robocopy 종료 코드 {0}": "robocopy 終了コード {0}",
|
||||||
"rsync --delete · robocopy /PURGE. 끄면 대상에 더하기 · 바꾸기만": "rsync --delete · robocopy /PURGE。オフなら対象に追加 · 更新のみ",
|
"rsync --delete · robocopy /PURGE. 끄면 대상에 더하기 · 바꾸기만": "rsync --delete · robocopy /PURGE。オフなら対象に追加 · 更新のみ",
|
||||||
"rsync 가 없습니다 (환경 설정 > 파일 탐색기에서 내려받기 · 경로 지정)": "rsync がありません (環境設定 > ファイルエクスプローラーでダウンロード · パス指定)",
|
"rsync 가 없습니다 (환경 설정 > 파일 탐색기에서 내려받기 · 경로 지정)": "rsync がありません (環境設定 > ファイルエクスプローラーでダウンロード · パス指定)",
|
||||||
"rsync 가져오기": "rsync の入手",
|
"rsync 가져오기": "rsync の入手",
|
||||||
|
|
@ -265,9 +271,12 @@
|
||||||
"rsync 실행 파일": "rsync 実行ファイル",
|
"rsync 실행 파일": "rsync 実行ファイル",
|
||||||
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > Rsync 에서 확인하세요.": "rsync 実行ファイルが見つかりません。環境設定 > Rsync を確認してください。",
|
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > Rsync 에서 확인하세요.": "rsync 実行ファイルが見つかりません。環境設定 > Rsync を確認してください。",
|
||||||
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > 파일 탐색기에서 경로를 확인하세요.": "rsync 実行ファイルが見つかりません。環境設定 > ファイルエクスプローラーでパスを確認してください。",
|
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > 파일 탐색기에서 경로를 확인하세요.": "rsync 実行ファイルが見つかりません。環境設定 > ファイルエクスプローラーでパスを確認してください。",
|
||||||
|
"rsync 실행 파일이 없습니다": "rsync の実行ファイルがありません",
|
||||||
"rsync 양쪽 (⇄)": "rsync 双方向 (⇄)",
|
"rsync 양쪽 (⇄)": "rsync 双方向 (⇄)",
|
||||||
"rsync 에 고르기": "rsync に選ぶ",
|
"rsync 에 고르기": "rsync に選ぶ",
|
||||||
"rsync 옵션": "rsync オプション",
|
"rsync 옵션": "rsync オプション",
|
||||||
|
"rsync 종료 코드 {0}": "rsync 終了コード {0}",
|
||||||
|
"settings.json 없음": "settings.json がありません",
|
||||||
"stable-diffusion.cpp (Windows · CPU · Vulkan)": "stable-diffusion.cpp (Windows・CPU・Vulkan)",
|
"stable-diffusion.cpp (Windows · CPU · Vulkan)": "stable-diffusion.cpp (Windows・CPU・Vulkan)",
|
||||||
"stable-diffusion.cpp (Windows · NVIDIA CUDA 12)": "stable-diffusion.cpp (Windows・NVIDIA CUDA 12)",
|
"stable-diffusion.cpp (Windows · NVIDIA CUDA 12)": "stable-diffusion.cpp (Windows・NVIDIA CUDA 12)",
|
||||||
"v{0} 받는 중": "v{0} をダウンロード中",
|
"v{0} 받는 중": "v{0} をダウンロード中",
|
||||||
|
|
@ -304,8 +313,10 @@
|
||||||
"{0} 외 {1}개": "{0} ほか {1} 件",
|
"{0} 외 {1}개": "{0} ほか {1} 件",
|
||||||
"{0} 은(는) 이미 이 폴더에 있어 옮길 것이 없습니다.\n{1}": "{0} は既にこのフォルダーにあるため移動するものがありません。\n{1}",
|
"{0} 은(는) 이미 이 폴더에 있어 옮길 것이 없습니다.\n{1}": "{0} は既にこのフォルダーにあるため移動するものがありません。\n{1}",
|
||||||
"{0} 을 담았습니다. 넣을 폴더에서 [붙여넣기] 를 누르세요 ({1}).": "{0} を保持しました。入れるフォルダーで [貼り付け] を押してください ({1})。",
|
"{0} 을 담았습니다. 넣을 폴더에서 [붙여넣기] 를 누르세요 ({1}).": "{0} を保持しました。入れるフォルダーで [貼り付け] を押してください ({1})。",
|
||||||
|
"{0} 을(를) 받지 못했습니다 ({1})": "{0} をダウンロードできませんでした ({1})",
|
||||||
"{0} 을(를) 설치했습니다.": "{0} をインストールしました。",
|
"{0} 을(를) 설치했습니다.": "{0} をインストールしました。",
|
||||||
"{0} 을(를) 지울까요?": "{0} を削除しますか?",
|
"{0} 을(를) 지울까요?": "{0} を削除しますか?",
|
||||||
|
"{0} 의 SHA256 이 다릅니다 (손상되었거나 다른 파일). 설치를 멈췄습니다.": "{0} の SHA256 が一致しません (破損しているか別のファイル)。インストールを中止しました。",
|
||||||
"{0} 이 비어 있습니다 (카드 · USB · 디스크를 넣은 뒤 다시 누르세요).": "{0} は空です (カード・USB・ディスクを入れてからもう一度押してください)。",
|
"{0} 이 비어 있습니다 (카드 · USB · 디스크를 넣은 뒤 다시 누르세요).": "{0} は空です (カード・USB・ディスクを入れてからもう一度押してください)。",
|
||||||
"{0} 인코더가 FFmpeg 에 없습니다.": "FFmpeg に {0} エンコーダーがありません。",
|
"{0} 인코더가 FFmpeg 에 없습니다.": "FFmpeg に {0} エンコーダーがありません。",
|
||||||
"{0} 전체": "{0} 全体",
|
"{0} 전체": "{0} 全体",
|
||||||
|
|
@ -401,6 +412,7 @@
|
||||||
"같은 화질이면 H.264 먼저 받기": "同じ画質なら H.264 を優先",
|
"같은 화질이면 H.264 먼저 받기": "同じ画質なら H.264 を優先",
|
||||||
"개수": "枚数",
|
"개수": "枚数",
|
||||||
"거꾸로": "逆順",
|
"거꾸로": "逆順",
|
||||||
|
"거꾸로 된 범위: {0}": "逆順の範囲: {0}",
|
||||||
"건너뛰기": "スキップ",
|
"건너뛰기": "スキップ",
|
||||||
"건너뜀 (출력 폴더의 파일): {0}": "スキップ(出力フォルダーのファイル): {0}",
|
"건너뜀 (출력 폴더의 파일): {0}": "スキップ(出力フォルダーのファイル): {0}",
|
||||||
"건너뜁니다": "スキップします",
|
"건너뜁니다": "スキップします",
|
||||||
|
|
@ -441,6 +453,7 @@
|
||||||
"공용 폴더에 받은 파일 (동영상 · 그림 등)": "共有フォルダーにダウンロードしたファイル (動画・画像など)",
|
"공용 폴더에 받은 파일 (동영상 · 그림 등)": "共有フォルダーにダウンロードしたファイル (動画・画像など)",
|
||||||
"관리 메뉴": "管理メニュー",
|
"관리 메뉴": "管理メニュー",
|
||||||
"광고 건너뛰는 중…": "広告をスキップ中…",
|
"광고 건너뛰는 중…": "広告をスキップ中…",
|
||||||
|
"권한 없음": "権限なし",
|
||||||
"권한 허용 화면 열기": "権限の許可画面を開く",
|
"권한 허용 화면 열기": "権限の許可画面を開く",
|
||||||
"권한이 없습니다": "権限がありません",
|
"권한이 없습니다": "権限がありません",
|
||||||
"그 파일 하나만": "そのファイルだけ",
|
"그 파일 하나만": "そのファイルだけ",
|
||||||
|
|
@ -462,6 +475,7 @@
|
||||||
"그림을 바꿔 만들기": "画像を変えて作成",
|
"그림을 바꿔 만들기": "画像を変えて作成",
|
||||||
"그림을 받을 수 없습니다 ({0})": "画像を受け取れません ({0})",
|
"그림을 받을 수 없습니다 ({0})": "画像を受け取れません ({0})",
|
||||||
"그림을 올릴 수 없습니다 ({0})": "画像をアップロードできません ({0})",
|
"그림을 올릴 수 없습니다 ({0})": "画像をアップロードできません ({0})",
|
||||||
|
"그림을 읽을 수 없습니다": "画像を読み込めません",
|
||||||
"그림을 페이지로 넣기 (이 페이지 뒤)": "画像をページとして追加 (このページの後)",
|
"그림을 페이지로 넣기 (이 페이지 뒤)": "画像をページとして追加 (このページの後)",
|
||||||
"그림이 거의 같고 마지막 단계가 10배쯤 빠릅니다 (받아 두었을 때)": "画像はほぼ同じで、最後の段階が約 10 倍速くなります (ダウンロード済みの場合)",
|
"그림이 거의 같고 마지막 단계가 10배쯤 빠릅니다 (받아 두었을 때)": "画像はほぼ同じで、最後の段階が約 10 倍速くなります (ダウンロード済みの場合)",
|
||||||
"글을 격자에 반영": "テキストをグリッドに反映",
|
"글을 격자에 반영": "テキストをグリッドに反映",
|
||||||
|
|
@ -575,6 +589,7 @@
|
||||||
"다른 언어로 번역 (AI · 이 {0}에서)": "他の言語に翻訳(AI・この{0}で)",
|
"다른 언어로 번역 (AI · 이 {0}에서)": "他の言語に翻訳(AI・この{0}で)",
|
||||||
"다른 이름으로 저장": "名前を付けて保存",
|
"다른 이름으로 저장": "名前を付けて保存",
|
||||||
"다른 이름으로 저장: {0} ({1})": "名前を付けて保存: {0}({1})",
|
"다른 이름으로 저장: {0} ({1})": "名前を付けて保存: {0}({1})",
|
||||||
|
"다른 저장소로는 이름만 바꿀 수 없습니다": "別のストレージへは名前の変更だけではできません",
|
||||||
"다른 창 폴더로": "もう一方の画面のフォルダーへ",
|
"다른 창 폴더로": "もう一方の画面のフォルダーへ",
|
||||||
"다른 창에서 열기": "もう一方のペインで開く",
|
"다른 창에서 열기": "もう一方のペインで開く",
|
||||||
"다른 창으로 복사": "もう一方のペインへコピー",
|
"다른 창으로 복사": "もう一方のペインへコピー",
|
||||||
|
|
@ -786,6 +801,7 @@
|
||||||
"모두 풀기": "すべて展開",
|
"모두 풀기": "すべて展開",
|
||||||
"모든 작업 취소": "すべての作業をキャンセル",
|
"모든 작업 취소": "すべての作業をキャンセル",
|
||||||
"목": "木",
|
"목": "木",
|
||||||
|
"목록": "一覧",
|
||||||
"목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "リスト・動画の横・動画の上に出る広告エリアを隠します",
|
"목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "リスト・動画の横・動画の上に出る広告エリアを隠します",
|
||||||
"목록 보기": "リストを見る",
|
"목록 보기": "リストを見る",
|
||||||
"목록에서 빼기": "リストから外す",
|
"목록에서 빼기": "リストから外す",
|
||||||
|
|
@ -800,6 +816,7 @@
|
||||||
"무엇이 바뀌는지 비교하는 중…": "何が変わるか比較中…",
|
"무엇이 바뀌는지 비교하는 중…": "何が変わるか比較中…",
|
||||||
"무한": "無制限",
|
"무한": "無制限",
|
||||||
"문서 미리보기": "文書プレビュー",
|
"문서 미리보기": "文書プレビュー",
|
||||||
|
"문서 미리보기 컴포넌트를 먼저 설치하세요": "先にドキュメントプレビューのコンポーネントをインストールしてください",
|
||||||
"문자셋 경고": "文字コードの警告",
|
"문자셋 경고": "文字コードの警告",
|
||||||
"묻기": "確認する",
|
"묻기": "確認する",
|
||||||
"물어보지 않기": "尋ねない",
|
"물어보지 않기": "尋ねない",
|
||||||
|
|
@ -828,6 +845,7 @@
|
||||||
"받기 ({0})": "ダウンロード ({0})",
|
"받기 ({0})": "ダウンロード ({0})",
|
||||||
"받기 화면으로": "ダウンロード画面へ",
|
"받기 화면으로": "ダウンロード画面へ",
|
||||||
"받는 중": "ダウンロード中",
|
"받는 중": "ダウンロード中",
|
||||||
|
"받는 중: {0}": "ダウンロード中: {0}",
|
||||||
"받는 중이거나 일시정지한 다운로드가 있어 건너뜁니다 (이어받기가 깨지지 않게)": "ダウンロード中または一時停止中のものがあるためスキップします(再開できるように)",
|
"받는 중이거나 일시정지한 다운로드가 있어 건너뜁니다 (이어받기가 깨지지 않게)": "ダウンロード中または一時停止中のものがあるためスキップします(再開できるように)",
|
||||||
"받는 중인 다운로드 {0}개": "ダウンロード中 {0}個",
|
"받는 중인 다운로드 {0}개": "ダウンロード中 {0}個",
|
||||||
"받는 중인 다운로드가 없습니다.": "ダウンロード中のものはありません。",
|
"받는 중인 다운로드가 없습니다.": "ダウンロード中のものはありません。",
|
||||||
|
|
@ -876,8 +894,11 @@
|
||||||
"번역 모델: NLLB-200 (로컬) ": "翻訳モデル: NLLB-200(ローカル) ",
|
"번역 모델: NLLB-200 (로컬) ": "翻訳モデル: NLLB-200(ローカル) ",
|
||||||
"번역 모델: NLLB-200 (이 {0}에서만) ": "翻訳モデル: NLLB-200(この{0}のみ) ",
|
"번역 모델: NLLB-200 (이 {0}에서만) ": "翻訳モデル: NLLB-200(この{0}のみ) ",
|
||||||
"번역 모델을 먼저 불러와야 합니다.": "先に翻訳モデルを読み込む必要があります。",
|
"번역 모델을 먼저 불러와야 합니다.": "先に翻訳モデルを読み込む必要があります。",
|
||||||
|
"번역 서버 응답 {0}": "翻訳サーバーの応答 {0}",
|
||||||
"번역 시작": "翻訳開始",
|
"번역 시작": "翻訳開始",
|
||||||
|
"번역 응답의 개수가 다릅니다 ({0} / {1})": "翻訳結果の数が一致しません ({0} / {1})",
|
||||||
"번역할 언어 (jj_mkv\\파일명_언어코드.srt 로 저장 후 MKV 에 추가)": "翻訳する言語(jj_mkv\\ファイル名_言語コード.srt に保存して MKV に追加)",
|
"번역할 언어 (jj_mkv\\파일명_언어코드.srt 로 저장 후 MKV 에 추가)": "翻訳する言語(jj_mkv\\ファイル名_言語コード.srt に保存して MKV に追加)",
|
||||||
|
"범위 밖 값: {0} ({1}~{2})": "範囲外の値: {0} ({1}~{2})",
|
||||||
"베트남어": "ベトナム語",
|
"베트남어": "ベトナム語",
|
||||||
"벵골어": "ベンガル語",
|
"벵골어": "ベンガル語",
|
||||||
"변경 내용을 저장하지 않고 나갈까요?": "変更を保存せずに終了しますか?",
|
"변경 내용을 저장하지 않고 나갈까요?": "変更を保存せずに終了しますか?",
|
||||||
|
|
@ -985,11 +1006,13 @@
|
||||||
"서버 설정 고치기": "サーバー設定を修正",
|
"서버 설정 고치기": "サーバー設定を修正",
|
||||||
"서버 설정과 이 기기에 저장된 비밀번호를 지웁니다. 서버의 파일은 그대로입니다. 이 서버를 쓰는 동기화 · 복사는 다시 넣을 때까지 연결되지 않습니다.": "サーバー設定とこの端末に保存したパスワードを削除します。サーバーのファイルはそのままです。このサーバーを使う同期・コピーは、再度追加するまで接続できません。",
|
"서버 설정과 이 기기에 저장된 비밀번호를 지웁니다. 서버의 파일은 그대로입니다. 이 서버를 쓰는 동기화 · 복사는 다시 넣을 때까지 연결되지 않습니다.": "サーバー設定とこの端末に保存したパスワードを削除します。サーバーのファイルはそのままです。このサーバーを使う同期・コピーは、再度追加するまで接続できません。",
|
||||||
"서버 인증서를 확인할 수 없습니다": "サーバー証明書を確認できません",
|
"서버 인증서를 확인할 수 없습니다": "サーバー証明書を確認できません",
|
||||||
|
"서버 저장 공간 부족": "サーバーの空き容量不足",
|
||||||
"서버가 https 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 https:// 로 바꾸세요.": "サーバーが https アドレスへの移動を求めています ({0})。サーバー設定のアドレスを https:// に変更してください。",
|
"서버가 https 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 https:// 로 바꾸세요.": "サーバーが https アドレスへの移動を求めています ({0})。サーバー設定のアドレスを https:// に変更してください。",
|
||||||
"서버가 거절했습니다 ({0}): {1}": "サーバーが拒否しました ({0}): {1}",
|
"서버가 거절했습니다 ({0}): {1}": "サーバーが拒否しました ({0}): {1}",
|
||||||
"서버가 그림을 돌려주지 않았습니다": "サーバーが画像を返しませんでした",
|
"서버가 그림을 돌려주지 않았습니다": "サーバーが画像を返しませんでした",
|
||||||
"서버가 너무 오래 답하지 않습니다": "サーバーの応答が長時間ありません",
|
"서버가 너무 오래 답하지 않습니다": "サーバーの応答が長時間ありません",
|
||||||
"서버가 다른 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 확인하세요.": "サーバーが別のアドレスへの移動を求めています ({0})。サーバー設定のアドレスを確認してください。",
|
"서버가 다른 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 확인하세요.": "サーバーが別のアドレスへの移動を求めています ({0})。サーバー設定のアドレスを確認してください。",
|
||||||
|
"서버가 이 기능을 허용하지 않음": "サーバーがこの機能を許可していません",
|
||||||
"서버에 닿지 않습니다": "サーバーに接続できません",
|
"서버에 닿지 않습니다": "サーバーに接続できません",
|
||||||
"서버에서 이 계정의 권한을 확인하세요.": "サーバーでこのアカウントの権限を確認してください。",
|
"서버에서 이 계정의 권한을 확인하세요.": "サーバーでこのアカウントの権限を確認してください。",
|
||||||
"서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.": "サーバーと同じネットワークにいるか、VPN (例: Tailscale) をオンにする必要があります。オンにしてから [再試行] を押してください。",
|
"서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.": "サーバーと同じネットワークにいるか、VPN (例: Tailscale) をオンにする必要があります。オンにしてから [再試行] を押してください。",
|
||||||
|
|
@ -1027,6 +1050,7 @@
|
||||||
"설치 실패": "インストール失敗",
|
"설치 실패": "インストール失敗",
|
||||||
"설치 준비 완료": "インストール準備完了",
|
"설치 준비 완료": "インストール準備完了",
|
||||||
"설치 파일: {0}\n이제 앱을 지운 뒤, 파일 앱에서 이 파일을 눌러 설치하세요.": "インストールファイル: {0}\nアプリを削除してから、ファイルアプリでこのファイルをタップしてインストールしてください。",
|
"설치 파일: {0}\n이제 앱을 지운 뒤, 파일 앱에서 이 파일을 눌러 설치하세요.": "インストールファイル: {0}\nアプリを削除してから、ファイルアプリでこのファイルをタップしてインストールしてください。",
|
||||||
|
"설치 파일을 풀 수 없습니다 (msiexec {0})": "インストーラーを展開できません (msiexec {0})",
|
||||||
"설치 허용 필요": "インストールの許可が必要",
|
"설치 허용 필요": "インストールの許可が必要",
|
||||||
"설치 화면을 열 수 없습니다: {0}": "インストール画面を開けません: {0}",
|
"설치 화면을 열 수 없습니다: {0}": "インストール画面を開けません: {0}",
|
||||||
"설치가 끝나면 프로그램이 다시 시작됩니다.": "インストールが終わるとプログラムが再起動します。",
|
"설치가 끝나면 프로그램이 다시 시작됩니다.": "インストールが終わるとプログラムが再起動します。",
|
||||||
|
|
@ -1103,6 +1127,7 @@
|
||||||
"실행한 rsync 가 없습니다. Rsync 화면에서 → · ← · ⇄ 로 실행하면 여기에 자동으로 등록됩니다.": "実行した rsync はありません。Rsync 画面で → · ← · ⇄ で実行すると自動でここに登録されます。",
|
"실행한 rsync 가 없습니다. Rsync 화면에서 → · ← · ⇄ 로 실행하면 여기에 자동으로 등록됩니다.": "実行した rsync はありません。Rsync 画面で → · ← · ⇄ で実行すると自動でここに登録されます。",
|
||||||
"싱크": "同期",
|
"싱크": "同期",
|
||||||
"쓰레드 확인 (AI · 변환 작업이 멈출 때까지)": "スレッド確認(AI・変換作業が止まるまで)",
|
"쓰레드 확인 (AI · 변환 작업이 멈출 때까지)": "スレッド確認(AI・変換作業が止まるまで)",
|
||||||
|
"쓸 수 없는 이름입니다": "使用できない名前です",
|
||||||
"아랍어": "アラビア語",
|
"아랍어": "アラビア語",
|
||||||
"아래 프로그램이 없어 일부 기능을 쓸 수 없습니다. 공식 배포처에서 내려받아 프로그램 폴더에 설치할까요?": "以下のプログラムがないため一部の機能が使えません。公式配布元からダウンロードしてプログラムフォルダーにインストールしますか?",
|
"아래 프로그램이 없어 일부 기능을 쓸 수 없습니다. 공식 배포처에서 내려받아 프로그램 폴더에 설치할까요?": "以下のプログラムがないため一部の機能が使えません。公式配布元からダウンロードしてプログラムフォルダーにインストールしますか?",
|
||||||
"아래로": "下へ",
|
"아래로": "下へ",
|
||||||
|
|
@ -1110,6 +1135,7 @@
|
||||||
"아무것도 안 함": "何もしない",
|
"아무것도 안 함": "何もしない",
|
||||||
"아이디": "ユーザー名",
|
"아이디": "ユーザー名",
|
||||||
"아이디 (선택)": "ユーザー名(任意)",
|
"아이디 (선택)": "ユーザー名(任意)",
|
||||||
|
"아이디 · 비밀번호를 확인하세요": "ID とパスワードを確認してください",
|
||||||
"아이디 또는 비밀번호가 맞지 않습니다": "ユーザー名またはパスワードが正しくありません",
|
"아이디 또는 비밀번호가 맞지 않습니다": "ユーザー名またはパスワードが正しくありません",
|
||||||
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "ユーザー名・パスワードは環境設定で入力できます(任意、1日のダウンロード回数が増えます)。",
|
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "ユーザー名・パスワードは環境設定で入力できます(任意、1日のダウンロード回数が増えます)。",
|
||||||
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "アイコン · 一覧の見た目: X-plore (サムネイル · 2 行) · Windows エクスプローラー (カラーアイコン · 列) · Total Commander (詰めた一覧 · [フォルダー])",
|
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "アイコン · 一覧の見た目: X-plore (サムネイル · 2 行) · Windows エクスプローラー (カラーアイコン · 列) · Total Commander (詰めた一覧 · [フォルダー])",
|
||||||
|
|
@ -1160,6 +1186,8 @@
|
||||||
"업데이트 · 설치하고 남은 파일": "更新・インストールの残り",
|
"업데이트 · 설치하고 남은 파일": "更新・インストールの残り",
|
||||||
"업데이트 실패: {0}": "更新失敗: {0}",
|
"업데이트 실패: {0}": "更新失敗: {0}",
|
||||||
"업데이트로 바뀐 기본값 알림": "アップデートで変わった既定値の通知",
|
"업데이트로 바뀐 기본값 알림": "アップデートで変わった既定値の通知",
|
||||||
|
"없는 경로": "存在しないパス",
|
||||||
|
"없는 경로: {0}": "存在しないパス: {0}",
|
||||||
"없음": "なし",
|
"없음": "なし",
|
||||||
"없음: 세부 정보의 [이동] 을 처음 누를 때 폴더를 골라 하나 만듭니다": "なし: 詳細の[移動]を初めて押したときにフォルダーを選んで作成します",
|
"없음: 세부 정보의 [이동] 을 처음 누를 때 폴더를 골라 하나 만듭니다": "なし: 詳細の[移動]を初めて押したときにフォルダーを選んで作成します",
|
||||||
"엔진": "エンジン",
|
"엔진": "エンジン",
|
||||||
|
|
@ -1206,6 +1234,7 @@
|
||||||
"오른쪽 90°": "右 90°",
|
"오른쪽 90°": "右 90°",
|
||||||
"오픈 소스 라이선스": "オープンソースライセンス",
|
"오픈 소스 라이선스": "オープンソースライセンス",
|
||||||
"올려 둔 버전이 없습니다.": "公開したバージョンがありません。",
|
"올려 둔 버전이 없습니다.": "公開したバージョンがありません。",
|
||||||
|
"올리기": "アップロード",
|
||||||
"올린 것": "高解像度化後",
|
"올린 것": "高解像度化後",
|
||||||
"올린 것 (AI)": "高解像度化後 (AI)",
|
"올린 것 (AI)": "高解像度化後 (AI)",
|
||||||
"올린 것으로 계속 보기": "高解像度化した画像で表示を続ける",
|
"올린 것으로 계속 보기": "高解像度化した画像で表示を続ける",
|
||||||
|
|
@ -1318,6 +1347,7 @@
|
||||||
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "この端末で 1 枚約 {0} (前回の所要時間から)",
|
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "この端末で 1 枚約 {0} (前回の所要時間から)",
|
||||||
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "この端末で 1 枚約 {0}・全部で約 {1} (前回の所要時間から)",
|
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "この端末で 1 枚約 {0}・全部で約 {1} (前回の所要時間から)",
|
||||||
"이 기기에서는 AI 번역을 쓸 수 없습니다.": "この端末では AI 翻訳を使えません。",
|
"이 기기에서는 AI 번역을 쓸 수 없습니다.": "この端末では AI 翻訳を使えません。",
|
||||||
|
"이 기기에서는 쓸 수 없는 컴포넌트입니다": "この端末では使えないコンポーネントです",
|
||||||
"이 기기용 파일 없음": "このデバイス用のファイルなし",
|
"이 기기용 파일 없음": "このデバイス用のファイルなし",
|
||||||
"이 기기의 안전 저장소를 쓸 수 없어 비밀번호를 저장하지 못했습니다": "この端末の安全な保存領域を使えないため、パスワードを保存できませんでした",
|
"이 기기의 안전 저장소를 쓸 수 없어 비밀번호를 저장하지 못했습니다": "この端末の安全な保存領域を使えないため、パスワードを保存できませんでした",
|
||||||
"이 기기의 폴더": "この端末のフォルダー",
|
"이 기기의 폴더": "この端末のフォルダー",
|
||||||
|
|
@ -1488,6 +1518,9 @@
|
||||||
"작업하다 남은 임시 파일 · 받다 만 다운로드 (.part 등) · 받다 만 AI 모델 · 업데이트하고 남은 파일 · 지난 작업 기록을 찾아 지웁니다. 받은 동영상 · 만든 MKV · 자막은 지우지 않고, 진행 중인 작업 · 다운로드가 쓰는 것은 건너뜁니다": "作業で残った一時ファイル・ダウンロード途中のファイル(.part など)・途中の AI モデル・更新の残り・古い作業記録を探して削除します。ダウンロードした動画・作成した MKV・字幕は削除せず、進行中の作業・ダウンロードが使っているものはスキップします",
|
"작업하다 남은 임시 파일 · 받다 만 다운로드 (.part 등) · 받다 만 AI 모델 · 업데이트하고 남은 파일 · 지난 작업 기록을 찾아 지웁니다. 받은 동영상 · 만든 MKV · 자막은 지우지 않고, 진행 중인 작업 · 다운로드가 쓰는 것은 건너뜁니다": "作業で残った一時ファイル・ダウンロード途中のファイル(.part など)・途中の AI モデル・更新の残り・古い作業記録を探して削除します。ダウンロードした動画・作成した MKV・字幕は削除せず、進行中の作業・ダウンロードが使っているものはスキップします",
|
||||||
"작은 용량": "小さい容量",
|
"작은 용량": "小さい容量",
|
||||||
"잘못된 varint (위치 {0})": "不正な varint(位置 {0})",
|
"잘못된 varint (위치 {0})": "不正な varint(位置 {0})",
|
||||||
|
"잘못된 간격: {0}": "不正な間隔: {0}",
|
||||||
|
"잘못된 범위: {0}": "不正な範囲: {0}",
|
||||||
|
"잘못된 칸: {0}": "不正な項目: {0}",
|
||||||
"재개": "再開",
|
"재개": "再開",
|
||||||
"재생": "再生",
|
"재생": "再生",
|
||||||
"재생 목록": "再生リスト",
|
"재생 목록": "再生リスト",
|
||||||
|
|
@ -1719,6 +1752,7 @@
|
||||||
"칠한 시간이 없어 동기화하지 않습니다.": "塗った時間がないため同期しません。",
|
"칠한 시간이 없어 동기화하지 않습니다.": "塗った時間がないため同期しません。",
|
||||||
"칸에 보이는 옵션: {0}\n저장된 옵션: {1}\n\n고친 옵션을 저장하고 실행할까요?": "欄に表示中のオプション: {0}\n保存済みのオプション: {1}\n\n編集したオプションを保存して実行しますか?",
|
"칸에 보이는 옵션: {0}\n저장된 옵션: {1}\n\n고친 옵션을 저장하고 실행할까요?": "欄に表示中のオプション: {0}\n保存済みのオプション: {1}\n\n編集したオプションを保存して実行しますか?",
|
||||||
"컴포넌트": "コンポーネント",
|
"컴포넌트": "コンポーネント",
|
||||||
|
"컴포넌트 목록을 받을 수 없습니다 ({0})": "コンポーネント一覧を取得できません ({0})",
|
||||||
"켜기": "オン",
|
"켜기": "オン",
|
||||||
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "オンにするとダブルタップで中の画像をすぐめくって表示します。オフにすると一覧 (選んで展開) を開きます。",
|
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "オンにするとダブルタップで中の画像をすぐめくって表示します。オフにすると一覧 (選んで展開) を開きます。",
|
||||||
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "オンにすると変換ツールをダウンロードしてインストールします (約 420MB)。オフにすると削除します。",
|
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "オンにすると変換ツールをダウンロードしてインストールします (約 420MB)。オフにすると削除します。",
|
||||||
|
|
@ -1772,10 +1806,12 @@
|
||||||
"파일이 깨졌습니다": "ファイルが壊れています",
|
"파일이 깨졌습니다": "ファイルが壊れています",
|
||||||
"파일이 깨졌습니다 · [다시 받기] 를 눌러 주세요": "ファイルが壊れています・[再ダウンロード] を押してください",
|
"파일이 깨졌습니다 · [다시 받기] 를 눌러 주세요": "ファイルが壊れています・[再ダウンロード] を押してください",
|
||||||
"파일이 보이지 않습니다: \"모든 파일에 대한 접근\" 권한이 없습니다": "ファイルが表示されません: 「すべてのファイルへのアクセス」権限がありません",
|
"파일이 보이지 않습니다: \"모든 파일에 대한 접근\" 권한이 없습니다": "ファイルが表示されません: 「すべてのファイルへのアクセス」権限がありません",
|
||||||
|
"파일이 손상되었습니다 (SHA-256 다름): {0}": "ファイルが破損しています (SHA-256 不一致): {0}",
|
||||||
"파일이 없습니다 (지워졌거나 옮겨짐)": "ファイルがありません (削除または移動)",
|
"파일이 없습니다 (지워졌거나 옮겨짐)": "ファイルがありません (削除または移動)",
|
||||||
"팝업 끄기": "ポップアップを閉じる",
|
"팝업 끄기": "ポップアップを閉じる",
|
||||||
"팝업 보기": "ポップアップ表示",
|
"팝업 보기": "ポップアップ表示",
|
||||||
"패키지 라이선스": "パッケージのライセンス",
|
"패키지 라이선스": "パッケージのライセンス",
|
||||||
|
"패키지에 {0} 이 없습니다": "パッケージに {0} がありません",
|
||||||
"페르시아어": "ペルシャ語",
|
"페르시아어": "ペルシャ語",
|
||||||
"페이지 열기": "ページを開く",
|
"페이지 열기": "ページを開く",
|
||||||
"페이지 지우기": "ページを削除",
|
"페이지 지우기": "ページを削除",
|
||||||
|
|
@ -1809,6 +1845,7 @@
|
||||||
"폴더가 없습니다": "フォルダーがありません",
|
"폴더가 없습니다": "フォルダーがありません",
|
||||||
"폴더는 보여도 그 안의 동영상 · 파일은 이 권한이 있어야 보입니다. 허용 화면에서 JJ_MKVMaker 를 켜고 돌아오세요.": "フォルダーは見えても、中の動画・ファイルはこの権限が必要です。許可画面で JJ_MKVMaker をオンにして戻ってください。",
|
"폴더는 보여도 그 안의 동영상 · 파일은 이 권한이 있어야 보입니다. 허용 화면에서 JJ_MKVMaker 를 켜고 돌아오세요.": "フォルダーは見えても、中の動画・ファイルはこの権限が必要です。許可画面で JJ_MKVMaker をオンにして戻ってください。",
|
||||||
"폴더를 만들 수 없습니다: {0}": "フォルダーを作成できません: {0}",
|
"폴더를 만들 수 없습니다: {0}": "フォルダーを作成できません: {0}",
|
||||||
|
"폴더를 자기 안으로 복사 · 이동할 수 없습니다": "フォルダーを自分自身の中にコピー · 移動できません",
|
||||||
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "フォルダーを自分自身の中へ{0}ことはできません: {1}",
|
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "フォルダーを自分自身の中へ{0}ことはできません: {1}",
|
||||||
"폴더만 lsync 로 옮길 수 있습니다.": "lsync へ移せるのはフォルダーだけです。",
|
"폴더만 lsync 로 옮길 수 있습니다.": "lsync へ移せるのはフォルダーだけです。",
|
||||||
"폴란드어": "ポーランド語",
|
"폴란드어": "ポーランド語",
|
||||||
|
|
@ -1818,6 +1855,7 @@
|
||||||
"표시 지우기": "マークを解除",
|
"표시 지우기": "マークを解除",
|
||||||
"표준": "標準",
|
"표준": "標準",
|
||||||
"푸는 중": "展開中",
|
"푸는 중": "展開中",
|
||||||
|
"푸는 중: {0}": "展開中: {0}",
|
||||||
"풀지 못했습니다: {0}": "展開できませんでした: {0}",
|
"풀지 못했습니다: {0}": "展開できませんでした: {0}",
|
||||||
"프랑스어": "フランス語",
|
"프랑스어": "フランス語",
|
||||||
"프로그램": "プログラム",
|
"프로그램": "プログラム",
|
||||||
|
|
@ -1898,6 +1936,8 @@
|
||||||
"확인 창에서 알린 뒤 허용합니다. 지우기 (--delete) 가 있으면 늘 막습니다. 끄면 늘 막습니다": "確認ウィンドウで知らせたうえで許可します。削除 (--delete) があるときは常に禁止します。オフにすると常に禁止します",
|
"확인 창에서 알린 뒤 허용합니다. 지우기 (--delete) 가 있으면 늘 막습니다. 끄면 늘 막습니다": "確認ウィンドウで知らせたうえで許可します。削除 (--delete) があるときは常に禁止します。オフにすると常に禁止します",
|
||||||
"확인됨": "確認済み",
|
"확인됨": "確認済み",
|
||||||
"확장 설치": "拡張機能のインストール",
|
"확장 설치": "拡張機能のインストール",
|
||||||
|
"확장 설치: {0}": "拡張機能のインストール: {0}",
|
||||||
|
"확장을 설치할 수 없습니다 ({0}): {1}": "拡張機能をインストールできません ({0}): {1}",
|
||||||
"확장자": "拡張子",
|
"확장자": "拡張子",
|
||||||
"확장자별 재생 프로그램": "拡張子ごとの再生プログラム",
|
"확장자별 재생 프로그램": "拡張子ごとの再生プログラム",
|
||||||
"환경 설정": "環境設定",
|
"환경 설정": "環境設定",
|
||||||
|
|
|
||||||
|
|
@ -141,6 +141,7 @@
|
||||||
"JPG 품질 {0}": "JPG 质量 {0}",
|
"JPG 품질 {0}": "JPG 质量 {0}",
|
||||||
"JavaScript 사용": "启用 JavaScript",
|
"JavaScript 사용": "启用 JavaScript",
|
||||||
"LCM-LoRA (SD1.5, 4단계로 빠르게)": "LCM-LoRA (SD1.5,4 步快速生成)",
|
"LCM-LoRA (SD1.5, 4단계로 빠르게)": "LCM-LoRA (SD1.5,4 步快速生成)",
|
||||||
|
"LibreOffice 를 먼저 설치해야 합니다": "需要先安装 LibreOffice",
|
||||||
"MKV · AI 작업": "MKV · AI 任务",
|
"MKV · AI 작업": "MKV · AI 任务",
|
||||||
"MKV · 자막 (jj_mkv)": "MKV · 字幕(jj_mkv)",
|
"MKV · 자막 (jj_mkv)": "MKV · 字幕(jj_mkv)",
|
||||||
"MKV · 자막 저장 위치": "MKV · 字幕保存位置",
|
"MKV · 자막 저장 위치": "MKV · 字幕保存位置",
|
||||||
|
|
@ -179,6 +180,7 @@
|
||||||
"PC 전체 사용량\nCPU {0}%\n메모리 {1} / {2}GB ({3}%){4}": "整机使用率\nCPU {0}%\n内存 {1} / {2}GB({3}%){4}",
|
"PC 전체 사용량\nCPU {0}%\n메모리 {1} / {2}GB ({3}%){4}": "整机使用率\nCPU {0}%\n内存 {1} / {2}GB({3}%){4}",
|
||||||
"PDF 로 만들기": "制作 PDF",
|
"PDF 로 만들기": "制作 PDF",
|
||||||
"PDF 로 바꾸는 중: {0}": "正在转换为 PDF: {0}",
|
"PDF 로 바꾸는 중: {0}": "正在转换为 PDF: {0}",
|
||||||
|
"PDF 로 바꾸지 못했습니다 ({0}) {1}": "无法转换为 PDF({0}){1}",
|
||||||
"PDF 를 만들지 못했습니다: {0}": "无法制作 PDF: {0}",
|
"PDF 를 만들지 못했습니다: {0}": "无法制作 PDF: {0}",
|
||||||
"PDF 를 열 수 없습니다: {0}": "无法打开 PDF: {0}",
|
"PDF 를 열 수 없습니다: {0}": "无法打开 PDF: {0}",
|
||||||
"PDF 에 넣을 그림 선택": "选择要加入 PDF 的图片",
|
"PDF 에 넣을 그림 선택": "选择要加入 PDF 的图片",
|
||||||
|
|
@ -195,11 +197,13 @@
|
||||||
"TAESD (빠른 디코더)": "TAESD (快速解码器)",
|
"TAESD (빠른 디코더)": "TAESD (快速解码器)",
|
||||||
"VLC 가 설치되어 있지 않습니다. 설치하면 목록에 나타납니다 (videolan.org).": "未安装 VLC。安装后会出现在列表中(videolan.org)。",
|
"VLC 가 설치되어 있지 않습니다. 설치하면 목록에 나타납니다 (videolan.org).": "未安装 VLC。安装后会出现在列表中(videolan.org)。",
|
||||||
"VLC 로 열기": "用 VLC 打开",
|
"VLC 로 열기": "用 VLC 打开",
|
||||||
|
"WebDAV {0} 실패: {1} {2}{3}": "WebDAV {0} 失败: {1} {2}{3}",
|
||||||
"WebDAV · OpenSubtitles 등. 서버 목록과 아이디는 남깁니다": "WebDAV · OpenSubtitles 等。保留服务器列表和用户名",
|
"WebDAV · OpenSubtitles 등. 서버 목록과 아이디는 남깁니다": "WebDAV · OpenSubtitles 等。保留服务器列表和用户名",
|
||||||
"WebDAV · OpenSubtitles 비밀번호를 이 기기의 안전 저장소에 둡니다. 끄면 저장하지 않고 (있던 것도 지움) 앱을 켤 때마다 다시 넣습니다": "将 WebDAV · OpenSubtitles 密码保存在本设备的安全存储中。关闭后不保存 (已有的也会删除),每次启动应用时重新输入",
|
"WebDAV · OpenSubtitles 비밀번호를 이 기기의 안전 저장소에 둡니다. 끄면 저장하지 않고 (있던 것도 지움) 앱을 켤 때마다 다시 넣습니다": "将 WebDAV · OpenSubtitles 密码保存在本设备的安全存储中。关闭后不保存 (已有的也会删除),每次启动应用时重新输入",
|
||||||
"WebDAV 서버 \"{0}\" 을(를) 지울까요?": "删除 WebDAV 服务器“{0}”吗?",
|
"WebDAV 서버 \"{0}\" 을(를) 지울까요?": "删除 WebDAV 服务器“{0}”吗?",
|
||||||
"WebDAV 서버 고치기": "编辑 WebDAV 服务器",
|
"WebDAV 서버 고치기": "编辑 WebDAV 服务器",
|
||||||
"WebDAV 서버 목록과 그 저장된 비밀번호도 지워집니다. 동영상 목록 · 즐겨찾기 · 파일은 그대로입니다": "WebDAV 服务器列表及其保存的密码也会被删除。视频列表 · 收藏 · 文件保持不变",
|
"WebDAV 서버 목록과 그 저장된 비밀번호도 지워집니다. 동영상 목록 · 즐겨찾기 · 파일은 그대로입니다": "WebDAV 服务器列表及其保存的密码也会被删除。视频列表 · 收藏 · 文件保持不变",
|
||||||
|
"WebDAV 서버 설정이 없습니다 ({0})": "没有 WebDAV 服务器设置({0})",
|
||||||
"WebDAV 서버 추가": "添加 WebDAV 服务器",
|
"WebDAV 서버 추가": "添加 WebDAV 服务器",
|
||||||
"WebDAV 에서 받는 중": "正在从 WebDAV 下载",
|
"WebDAV 에서 받는 중": "正在从 WebDAV 下载",
|
||||||
"WebDAV 원본에 씁니다 (PC 의 폴더는 바뀌면 바로 맞춤). 짧을수록 빨리 맞추지만 서버 · 배터리를 더 씁니다.": "用于 WebDAV 源 (电脑上的文件夹一有更改就同步)。间隔越短同步越快,但会更多占用服务器和电池。",
|
"WebDAV 원본에 씁니다 (PC 의 폴더는 바뀌면 바로 맞춤). 짧을수록 빨리 맞추지만 서버 · 배터리를 더 씁니다.": "用于 WebDAV 源 (电脑上的文件夹一有更改就同步)。间隔越短同步越快,但会更多占用服务器和电池。",
|
||||||
|
|
@ -245,6 +249,7 @@
|
||||||
"cookies.txt (Netscape 형식)": "cookies.txt(Netscape 格式)",
|
"cookies.txt (Netscape 형식)": "cookies.txt(Netscape 格式)",
|
||||||
"cookies.txt 파일…": "cookies.txt 文件…",
|
"cookies.txt 파일…": "cookies.txt 文件…",
|
||||||
"cron (분 시 일 월 요일) · 한 줄에 하나": "cron (分 时 日 月 星期) · 每行一个",
|
"cron (분 시 일 월 요일) · 한 줄에 하나": "cron (分 时 日 月 星期) · 每行一个",
|
||||||
|
"cron 은 다섯 칸입니다 (분 시 일 월 요일)": "cron 有五个字段(分 时 日 月 星期)",
|
||||||
"ffmpeg 를 실행할 수 없습니다: {0}": "无法运行 ffmpeg: {0}",
|
"ffmpeg 를 실행할 수 없습니다: {0}": "无法运行 ffmpeg: {0}",
|
||||||
"ffmpeg 오류 (코드 {0})\n{1}": "ffmpeg 错误(代码 {0})\n{1}",
|
"ffmpeg 오류 (코드 {0})\n{1}": "ffmpeg 错误(代码 {0})\n{1}",
|
||||||
"http:// 주소는 아이디 · 비밀번호와 파일이 암호화되지 않고 그대로 갑니다. 같은 네트워크의 다른 사람이 볼 수 있으니 서버가 https 를 지원하면 https:// 로 바꾸세요.": "http:// 地址会以未加密方式发送用户名、密码和文件。同一网络中的其他人可以看到,如果服务器支持 https,请改为 https://。",
|
"http:// 주소는 아이디 · 비밀번호와 파일이 암호화되지 않고 그대로 갑니다. 같은 네트워크의 다른 사람이 볼 수 있으니 서버가 https 를 지원하면 https:// 로 바꾸세요.": "http:// 地址会以未加密方式发送用户名、密码和文件。同一网络中的其他人可以看到,如果服务器支持 https,请改为 https://。",
|
||||||
|
|
@ -252,6 +257,7 @@
|
||||||
"lsync 로 이동": "移到 lsync",
|
"lsync 로 이동": "移到 lsync",
|
||||||
"quit 시작": "开始退出",
|
"quit 시작": "开始退出",
|
||||||
"robocopy 옵션": "robocopy 选项",
|
"robocopy 옵션": "robocopy 选项",
|
||||||
|
"robocopy 종료 코드 {0}": "robocopy 退出代码 {0}",
|
||||||
"rsync --delete · robocopy /PURGE. 끄면 대상에 더하기 · 바꾸기만": "rsync --delete · robocopy /PURGE。关闭时只在目标中添加 · 更新",
|
"rsync --delete · robocopy /PURGE. 끄면 대상에 더하기 · 바꾸기만": "rsync --delete · robocopy /PURGE。关闭时只在目标中添加 · 更新",
|
||||||
"rsync 가 없습니다 (환경 설정 > 파일 탐색기에서 내려받기 · 경로 지정)": "没有 rsync (设置 > 文件浏览器中下载 · 指定路径)",
|
"rsync 가 없습니다 (환경 설정 > 파일 탐색기에서 내려받기 · 경로 지정)": "没有 rsync (设置 > 文件浏览器中下载 · 指定路径)",
|
||||||
"rsync 가져오기": "获取 rsync",
|
"rsync 가져오기": "获取 rsync",
|
||||||
|
|
@ -265,9 +271,12 @@
|
||||||
"rsync 실행 파일": "rsync 可执行文件",
|
"rsync 실행 파일": "rsync 可执行文件",
|
||||||
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > Rsync 에서 확인하세요.": "找不到 rsync 可执行文件。请检查 设置 > Rsync。",
|
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > Rsync 에서 확인하세요.": "找不到 rsync 可执行文件。请检查 设置 > Rsync。",
|
||||||
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > 파일 탐색기에서 경로를 확인하세요.": "找不到 rsync 可执行文件。请在 设置 > 文件浏览器 中检查路径。",
|
"rsync 실행 파일을 찾을 수 없습니다. 환경 설정 > 파일 탐색기에서 경로를 확인하세요.": "找不到 rsync 可执行文件。请在 设置 > 文件浏览器 中检查路径。",
|
||||||
|
"rsync 실행 파일이 없습니다": "缺少 rsync 可执行文件",
|
||||||
"rsync 양쪽 (⇄)": "rsync 双向 (⇄)",
|
"rsync 양쪽 (⇄)": "rsync 双向 (⇄)",
|
||||||
"rsync 에 고르기": "选为 rsync",
|
"rsync 에 고르기": "选为 rsync",
|
||||||
"rsync 옵션": "rsync 选项",
|
"rsync 옵션": "rsync 选项",
|
||||||
|
"rsync 종료 코드 {0}": "rsync 退出代码 {0}",
|
||||||
|
"settings.json 없음": "缺少 settings.json",
|
||||||
"stable-diffusion.cpp (Windows · CPU · Vulkan)": "stable-diffusion.cpp (Windows · CPU · Vulkan)",
|
"stable-diffusion.cpp (Windows · CPU · Vulkan)": "stable-diffusion.cpp (Windows · CPU · Vulkan)",
|
||||||
"stable-diffusion.cpp (Windows · NVIDIA CUDA 12)": "stable-diffusion.cpp (Windows · NVIDIA CUDA 12)",
|
"stable-diffusion.cpp (Windows · NVIDIA CUDA 12)": "stable-diffusion.cpp (Windows · NVIDIA CUDA 12)",
|
||||||
"v{0} 받는 중": "正在下载 v{0}",
|
"v{0} 받는 중": "正在下载 v{0}",
|
||||||
|
|
@ -304,8 +313,10 @@
|
||||||
"{0} 외 {1}개": "{0} 等 {1} 个",
|
"{0} 외 {1}개": "{0} 等 {1} 个",
|
||||||
"{0} 은(는) 이미 이 폴더에 있어 옮길 것이 없습니다.\n{1}": "{0} 已在此文件夹中,无需移动。\n{1}",
|
"{0} 은(는) 이미 이 폴더에 있어 옮길 것이 없습니다.\n{1}": "{0} 已在此文件夹中,无需移动。\n{1}",
|
||||||
"{0} 을 담았습니다. 넣을 폴더에서 [붙여넣기] 를 누르세요 ({1}).": "已暂存 {0}。请在目标文件夹中点按 [粘贴] ({1})。",
|
"{0} 을 담았습니다. 넣을 폴더에서 [붙여넣기] 를 누르세요 ({1}).": "已暂存 {0}。请在目标文件夹中点按 [粘贴] ({1})。",
|
||||||
|
"{0} 을(를) 받지 못했습니다 ({1})": "无法下载 {0}({1})",
|
||||||
"{0} 을(를) 설치했습니다.": "已安装 {0}。",
|
"{0} 을(를) 설치했습니다.": "已安装 {0}。",
|
||||||
"{0} 을(를) 지울까요?": "要删除 {0} 吗?",
|
"{0} 을(를) 지울까요?": "要删除 {0} 吗?",
|
||||||
|
"{0} 의 SHA256 이 다릅니다 (손상되었거나 다른 파일). 설치를 멈췄습니다.": "{0} 的 SHA256 不一致(已损坏或是其他文件)。已停止安装。",
|
||||||
"{0} 이 비어 있습니다 (카드 · USB · 디스크를 넣은 뒤 다시 누르세요).": "{0} 为空 (插入存储卡、U 盘或光盘后再点按)。",
|
"{0} 이 비어 있습니다 (카드 · USB · 디스크를 넣은 뒤 다시 누르세요).": "{0} 为空 (插入存储卡、U 盘或光盘后再点按)。",
|
||||||
"{0} 인코더가 FFmpeg 에 없습니다.": "FFmpeg 中没有 {0} 编码器。",
|
"{0} 인코더가 FFmpeg 에 없습니다.": "FFmpeg 中没有 {0} 编码器。",
|
||||||
"{0} 전체": "{0} 全部",
|
"{0} 전체": "{0} 全部",
|
||||||
|
|
@ -401,6 +412,7 @@
|
||||||
"같은 화질이면 H.264 먼저 받기": "相同画质时优先 H.264",
|
"같은 화질이면 H.264 먼저 받기": "相同画质时优先 H.264",
|
||||||
"개수": "数量",
|
"개수": "数量",
|
||||||
"거꾸로": "倒序",
|
"거꾸로": "倒序",
|
||||||
|
"거꾸로 된 범위: {0}": "范围顺序颠倒: {0}",
|
||||||
"건너뛰기": "跳过",
|
"건너뛰기": "跳过",
|
||||||
"건너뜀 (출력 폴더의 파일): {0}": "已跳过(输出文件夹中的文件): {0}",
|
"건너뜀 (출력 폴더의 파일): {0}": "已跳过(输出文件夹中的文件): {0}",
|
||||||
"건너뜁니다": "跳过",
|
"건너뜁니다": "跳过",
|
||||||
|
|
@ -441,6 +453,7 @@
|
||||||
"공용 폴더에 받은 파일 (동영상 · 그림 등)": "下载到公共文件夹的文件 (视频、图片等)",
|
"공용 폴더에 받은 파일 (동영상 · 그림 등)": "下载到公共文件夹的文件 (视频、图片等)",
|
||||||
"관리 메뉴": "管理菜单",
|
"관리 메뉴": "管理菜单",
|
||||||
"광고 건너뛰는 중…": "正在跳过广告…",
|
"광고 건너뛰는 중…": "正在跳过广告…",
|
||||||
|
"권한 없음": "无权限",
|
||||||
"권한 허용 화면 열기": "打开权限授予界面",
|
"권한 허용 화면 열기": "打开权限授予界面",
|
||||||
"권한이 없습니다": "没有权限",
|
"권한이 없습니다": "没有权限",
|
||||||
"그 파일 하나만": "仅该文件",
|
"그 파일 하나만": "仅该文件",
|
||||||
|
|
@ -462,6 +475,7 @@
|
||||||
"그림을 바꿔 만들기": "基于图片生成",
|
"그림을 바꿔 만들기": "基于图片生成",
|
||||||
"그림을 받을 수 없습니다 ({0})": "无法获取图片 ({0})",
|
"그림을 받을 수 없습니다 ({0})": "无法获取图片 ({0})",
|
||||||
"그림을 올릴 수 없습니다 ({0})": "无法上传图片 ({0})",
|
"그림을 올릴 수 없습니다 ({0})": "无法上传图片 ({0})",
|
||||||
|
"그림을 읽을 수 없습니다": "无法读取图片",
|
||||||
"그림을 페이지로 넣기 (이 페이지 뒤)": "将图片作为页面加入 (本页之后)",
|
"그림을 페이지로 넣기 (이 페이지 뒤)": "将图片作为页面加入 (本页之后)",
|
||||||
"그림이 거의 같고 마지막 단계가 10배쯤 빠릅니다 (받아 두었을 때)": "图片几乎相同,最后一步快约 10 倍 (已下载时)",
|
"그림이 거의 같고 마지막 단계가 10배쯤 빠릅니다 (받아 두었을 때)": "图片几乎相同,最后一步快约 10 倍 (已下载时)",
|
||||||
"글을 격자에 반영": "将文本应用到网格",
|
"글을 격자에 반영": "将文本应用到网格",
|
||||||
|
|
@ -575,6 +589,7 @@
|
||||||
"다른 언어로 번역 (AI · 이 {0}에서)": "翻译为其他语言(AI · 在此{0}上)",
|
"다른 언어로 번역 (AI · 이 {0}에서)": "翻译为其他语言(AI · 在此{0}上)",
|
||||||
"다른 이름으로 저장": "另存为",
|
"다른 이름으로 저장": "另存为",
|
||||||
"다른 이름으로 저장: {0} ({1})": "另存为: {0}({1})",
|
"다른 이름으로 저장: {0} ({1})": "另存为: {0}({1})",
|
||||||
|
"다른 저장소로는 이름만 바꿀 수 없습니다": "不能仅通过重命名移到其他存储",
|
||||||
"다른 창 폴더로": "到另一窗格的文件夹",
|
"다른 창 폴더로": "到另一窗格的文件夹",
|
||||||
"다른 창에서 열기": "在另一窗格中打开",
|
"다른 창에서 열기": "在另一窗格中打开",
|
||||||
"다른 창으로 복사": "复制到另一窗格",
|
"다른 창으로 복사": "复制到另一窗格",
|
||||||
|
|
@ -786,6 +801,7 @@
|
||||||
"모두 풀기": "全部解压",
|
"모두 풀기": "全部解压",
|
||||||
"모든 작업 취소": "取消所有任务",
|
"모든 작업 취소": "取消所有任务",
|
||||||
"목": "四",
|
"목": "四",
|
||||||
|
"목록": "列表",
|
||||||
"목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "隐藏列表 · 视频旁 · 视频上方出现的广告区域",
|
"목록 · 영상 옆 · 영상 위에 나오는 광고 영역을 감춥니다": "隐藏列表 · 视频旁 · 视频上方出现的广告区域",
|
||||||
"목록 보기": "查看列表",
|
"목록 보기": "查看列表",
|
||||||
"목록에서 빼기": "从列表中移除",
|
"목록에서 빼기": "从列表中移除",
|
||||||
|
|
@ -800,6 +816,7 @@
|
||||||
"무엇이 바뀌는지 비교하는 중…": "正在比较将要更改的内容…",
|
"무엇이 바뀌는지 비교하는 중…": "正在比较将要更改的内容…",
|
||||||
"무한": "无限制",
|
"무한": "无限制",
|
||||||
"문서 미리보기": "文档预览",
|
"문서 미리보기": "文档预览",
|
||||||
|
"문서 미리보기 컴포넌트를 먼저 설치하세요": "请先安装文档预览组件",
|
||||||
"문자셋 경고": "字符集警告",
|
"문자셋 경고": "字符集警告",
|
||||||
"묻기": "询问",
|
"묻기": "询问",
|
||||||
"물어보지 않기": "不询问",
|
"물어보지 않기": "不询问",
|
||||||
|
|
@ -828,6 +845,7 @@
|
||||||
"받기 ({0})": "下载 ({0})",
|
"받기 ({0})": "下载 ({0})",
|
||||||
"받기 화면으로": "前往下载画面",
|
"받기 화면으로": "前往下载画面",
|
||||||
"받는 중": "正在下载",
|
"받는 중": "正在下载",
|
||||||
|
"받는 중: {0}": "正在下载: {0}",
|
||||||
"받는 중이거나 일시정지한 다운로드가 있어 건너뜁니다 (이어받기가 깨지지 않게)": "有正在下载或已暂停的下载,已跳过(以便继续下载)",
|
"받는 중이거나 일시정지한 다운로드가 있어 건너뜁니다 (이어받기가 깨지지 않게)": "有正在下载或已暂停的下载,已跳过(以便继续下载)",
|
||||||
"받는 중인 다운로드 {0}개": "正在下载 {0} 个",
|
"받는 중인 다운로드 {0}개": "正在下载 {0} 个",
|
||||||
"받는 중인 다운로드가 없습니다.": "没有正在进行的下载。",
|
"받는 중인 다운로드가 없습니다.": "没有正在进行的下载。",
|
||||||
|
|
@ -876,8 +894,11 @@
|
||||||
"번역 모델: NLLB-200 (로컬) ": "翻译模型: NLLB-200(本地) ",
|
"번역 모델: NLLB-200 (로컬) ": "翻译模型: NLLB-200(本地) ",
|
||||||
"번역 모델: NLLB-200 (이 {0}에서만) ": "翻译模型: NLLB-200(仅在此{0}上) ",
|
"번역 모델: NLLB-200 (이 {0}에서만) ": "翻译模型: NLLB-200(仅在此{0}上) ",
|
||||||
"번역 모델을 먼저 불러와야 합니다.": "必须先加载翻译模型。",
|
"번역 모델을 먼저 불러와야 합니다.": "必须先加载翻译模型。",
|
||||||
|
"번역 서버 응답 {0}": "翻译服务器响应 {0}",
|
||||||
"번역 시작": "开始翻译",
|
"번역 시작": "开始翻译",
|
||||||
|
"번역 응답의 개수가 다릅니다 ({0} / {1})": "翻译结果的数量不一致({0} / {1})",
|
||||||
"번역할 언어 (jj_mkv\\파일명_언어코드.srt 로 저장 후 MKV 에 추가)": "要翻译的语言(保存为 jj_mkv\\文件名_语言代码.srt 后加入 MKV)",
|
"번역할 언어 (jj_mkv\\파일명_언어코드.srt 로 저장 후 MKV 에 추가)": "要翻译的语言(保存为 jj_mkv\\文件名_语言代码.srt 后加入 MKV)",
|
||||||
|
"범위 밖 값: {0} ({1}~{2})": "超出范围的值: {0}({1}~{2})",
|
||||||
"베트남어": "越南语",
|
"베트남어": "越南语",
|
||||||
"벵골어": "孟加拉语",
|
"벵골어": "孟加拉语",
|
||||||
"변경 내용을 저장하지 않고 나갈까요?": "不保存更改就离开吗?",
|
"변경 내용을 저장하지 않고 나갈까요?": "不保存更改就离开吗?",
|
||||||
|
|
@ -985,11 +1006,13 @@
|
||||||
"서버 설정 고치기": "修改服务器设置",
|
"서버 설정 고치기": "修改服务器设置",
|
||||||
"서버 설정과 이 기기에 저장된 비밀번호를 지웁니다. 서버의 파일은 그대로입니다. 이 서버를 쓰는 동기화 · 복사는 다시 넣을 때까지 연결되지 않습니다.": "删除服务器设置和本设备上保存的密码。服务器上的文件保持不变。使用此服务器的同步 · 复制在重新添加之前无法连接。",
|
"서버 설정과 이 기기에 저장된 비밀번호를 지웁니다. 서버의 파일은 그대로입니다. 이 서버를 쓰는 동기화 · 복사는 다시 넣을 때까지 연결되지 않습니다.": "删除服务器设置和本设备上保存的密码。服务器上的文件保持不变。使用此服务器的同步 · 复制在重新添加之前无法连接。",
|
||||||
"서버 인증서를 확인할 수 없습니다": "无法验证服务器证书",
|
"서버 인증서를 확인할 수 없습니다": "无法验证服务器证书",
|
||||||
|
"서버 저장 공간 부족": "服务器存储空间不足",
|
||||||
"서버가 https 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 https:// 로 바꾸세요.": "服务器要求改用 https 地址 ({0})。请将服务器设置中的地址改为 https://。",
|
"서버가 https 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 https:// 로 바꾸세요.": "服务器要求改用 https 地址 ({0})。请将服务器设置中的地址改为 https://。",
|
||||||
"서버가 거절했습니다 ({0}): {1}": "服务器拒绝 ({0}): {1}",
|
"서버가 거절했습니다 ({0}): {1}": "服务器拒绝 ({0}): {1}",
|
||||||
"서버가 그림을 돌려주지 않았습니다": "服务器没有返回图片",
|
"서버가 그림을 돌려주지 않았습니다": "服务器没有返回图片",
|
||||||
"서버가 너무 오래 답하지 않습니다": "服务器长时间没有响应",
|
"서버가 너무 오래 답하지 않습니다": "服务器长时间没有响应",
|
||||||
"서버가 다른 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 확인하세요.": "服务器要求改用其他地址 ({0})。请检查服务器设置中的地址。",
|
"서버가 다른 주소로 옮기라고 합니다 ({0}). 서버 설정의 주소를 확인하세요.": "服务器要求改用其他地址 ({0})。请检查服务器设置中的地址。",
|
||||||
|
"서버가 이 기능을 허용하지 않음": "服务器不允许此操作",
|
||||||
"서버에 닿지 않습니다": "无法连接服务器",
|
"서버에 닿지 않습니다": "无法连接服务器",
|
||||||
"서버에서 이 계정의 권한을 확인하세요.": "请在服务器上检查此账户的权限。",
|
"서버에서 이 계정의 권한을 확인하세요.": "请在服务器上检查此账户的权限。",
|
||||||
"서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.": "需要与服务器在同一网络,或打开 VPN (如 Tailscale)。打开后点 [重试]。",
|
"서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.": "需要与服务器在同一网络,或打开 VPN (如 Tailscale)。打开后点 [重试]。",
|
||||||
|
|
@ -1027,6 +1050,7 @@
|
||||||
"설치 실패": "安装失败",
|
"설치 실패": "安装失败",
|
||||||
"설치 준비 완료": "准备安装",
|
"설치 준비 완료": "准备安装",
|
||||||
"설치 파일: {0}\n이제 앱을 지운 뒤, 파일 앱에서 이 파일을 눌러 설치하세요.": "安装文件: {0}\n请先卸载应用,然后在文件应用中点按此文件进行安装。",
|
"설치 파일: {0}\n이제 앱을 지운 뒤, 파일 앱에서 이 파일을 눌러 설치하세요.": "安装文件: {0}\n请先卸载应用,然后在文件应用中点按此文件进行安装。",
|
||||||
|
"설치 파일을 풀 수 없습니다 (msiexec {0})": "无法解压安装文件(msiexec {0})",
|
||||||
"설치 허용 필요": "需要安装权限",
|
"설치 허용 필요": "需要安装权限",
|
||||||
"설치 화면을 열 수 없습니다: {0}": "无法打开安装界面: {0}",
|
"설치 화면을 열 수 없습니다: {0}": "无法打开安装界面: {0}",
|
||||||
"설치가 끝나면 프로그램이 다시 시작됩니다.": "安装完成后程序将重新启动。",
|
"설치가 끝나면 프로그램이 다시 시작됩니다.": "安装完成后程序将重新启动。",
|
||||||
|
|
@ -1103,6 +1127,7 @@
|
||||||
"실행한 rsync 가 없습니다. Rsync 화면에서 → · ← · ⇄ 로 실행하면 여기에 자동으로 등록됩니다.": "还没有运行过 rsync。在 Rsync 画面用 → · ← · ⇄ 运行后会自动登记到这里。",
|
"실행한 rsync 가 없습니다. Rsync 화면에서 → · ← · ⇄ 로 실행하면 여기에 자동으로 등록됩니다.": "还没有运行过 rsync。在 Rsync 画面用 → · ← · ⇄ 运行后会自动登记到这里。",
|
||||||
"싱크": "同步",
|
"싱크": "同步",
|
||||||
"쓰레드 확인 (AI · 변환 작업이 멈출 때까지)": "线程检查(直到 AI · 转换任务停止)",
|
"쓰레드 확인 (AI · 변환 작업이 멈출 때까지)": "线程检查(直到 AI · 转换任务停止)",
|
||||||
|
"쓸 수 없는 이름입니다": "不能使用此名称",
|
||||||
"아랍어": "阿拉伯语",
|
"아랍어": "阿拉伯语",
|
||||||
"아래 프로그램이 없어 일부 기능을 쓸 수 없습니다. 공식 배포처에서 내려받아 프로그램 폴더에 설치할까요?": "由于缺少以下程序,部分功能无法使用。要从官方来源下载并安装到程序文件夹吗?",
|
"아래 프로그램이 없어 일부 기능을 쓸 수 없습니다. 공식 배포처에서 내려받아 프로그램 폴더에 설치할까요?": "由于缺少以下程序,部分功能无法使用。要从官方来源下载并安装到程序文件夹吗?",
|
||||||
"아래로": "向下",
|
"아래로": "向下",
|
||||||
|
|
@ -1110,6 +1135,7 @@
|
||||||
"아무것도 안 함": "不执行任何操作",
|
"아무것도 안 함": "不执行任何操作",
|
||||||
"아이디": "用户名",
|
"아이디": "用户名",
|
||||||
"아이디 (선택)": "用户名(可选)",
|
"아이디 (선택)": "用户名(可选)",
|
||||||
|
"아이디 · 비밀번호를 확인하세요": "请检查用户名和密码",
|
||||||
"아이디 또는 비밀번호가 맞지 않습니다": "用户名或密码错误",
|
"아이디 또는 비밀번호가 맞지 않습니다": "用户名或密码错误",
|
||||||
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "可在设置中填写用户名 · 密码(可选,可增加每日下载次数)。",
|
"아이디·비밀번호는 환경 설정에서 넣을 수 있습니다 (선택, 하루 받기 횟수가 늘어남).": "可在设置中填写用户名 · 密码(可选,可增加每日下载次数)。",
|
||||||
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "图标 · 列表外观: X-plore (缩略图 · 两行) · Windows 资源管理器 (彩色图标 · 列) · Total Commander (紧凑列表 · [文件夹])",
|
"아이콘 · 목록 모양: X-plore (썸네일 · 두 줄) · Windows 탐색기 (컬러 아이콘 · 열) · Total Commander (촘촘한 목록 · [폴더])": "图标 · 列表外观: X-plore (缩略图 · 两行) · Windows 资源管理器 (彩色图标 · 列) · Total Commander (紧凑列表 · [文件夹])",
|
||||||
|
|
@ -1160,6 +1186,8 @@
|
||||||
"업데이트 · 설치하고 남은 파일": "更新 · 安装残留",
|
"업데이트 · 설치하고 남은 파일": "更新 · 安装残留",
|
||||||
"업데이트 실패: {0}": "更新失败: {0}",
|
"업데이트 실패: {0}": "更新失败: {0}",
|
||||||
"업데이트로 바뀐 기본값 알림": "更新所更改默认值的通知",
|
"업데이트로 바뀐 기본값 알림": "更新所更改默认值的通知",
|
||||||
|
"없는 경로": "路径不存在",
|
||||||
|
"없는 경로: {0}": "路径不存在: {0}",
|
||||||
"없음": "无",
|
"없음": "无",
|
||||||
"없음: 세부 정보의 [이동] 을 처음 누를 때 폴더를 골라 하나 만듭니다": "无: 首次在详细信息中点击[移动]时选择文件夹并创建",
|
"없음: 세부 정보의 [이동] 을 처음 누를 때 폴더를 골라 하나 만듭니다": "无: 首次在详细信息中点击[移动]时选择文件夹并创建",
|
||||||
"엔진": "引擎",
|
"엔진": "引擎",
|
||||||
|
|
@ -1206,6 +1234,7 @@
|
||||||
"오른쪽 90°": "向右 90°",
|
"오른쪽 90°": "向右 90°",
|
||||||
"오픈 소스 라이선스": "开源许可",
|
"오픈 소스 라이선스": "开源许可",
|
||||||
"올려 둔 버전이 없습니다.": "没有已发布的版本。",
|
"올려 둔 버전이 없습니다.": "没有已发布的版本。",
|
||||||
|
"올리기": "上传",
|
||||||
"올린 것": "提高后",
|
"올린 것": "提高后",
|
||||||
"올린 것 (AI)": "提高后 (AI)",
|
"올린 것 (AI)": "提高后 (AI)",
|
||||||
"올린 것으로 계속 보기": "继续查看提高后的图片",
|
"올린 것으로 계속 보기": "继续查看提高后的图片",
|
||||||
|
|
@ -1318,6 +1347,7 @@
|
||||||
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "本设备每张约 {0} (按上次耗时)",
|
"이 기기에서 한 장 약 {0} (지난번 걸린 시간 기준)": "本设备每张约 {0} (按上次耗时)",
|
||||||
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "本设备每张约 {0} · 共约 {1} (按上次耗时)",
|
"이 기기에서 한 장 약 {0} · 모두 약 {1} (지난번 걸린 시간 기준)": "本设备每张约 {0} · 共约 {1} (按上次耗时)",
|
||||||
"이 기기에서는 AI 번역을 쓸 수 없습니다.": "此设备无法使用 AI 翻译。",
|
"이 기기에서는 AI 번역을 쓸 수 없습니다.": "此设备无法使用 AI 翻译。",
|
||||||
|
"이 기기에서는 쓸 수 없는 컴포넌트입니다": "此组件在本设备上不可用",
|
||||||
"이 기기용 파일 없음": "没有此设备的文件",
|
"이 기기용 파일 없음": "没有此设备的文件",
|
||||||
"이 기기의 안전 저장소를 쓸 수 없어 비밀번호를 저장하지 못했습니다": "本设备的安全存储不可用,无法保存密码",
|
"이 기기의 안전 저장소를 쓸 수 없어 비밀번호를 저장하지 못했습니다": "本设备的安全存储不可用,无法保存密码",
|
||||||
"이 기기의 폴더": "本设备上的文件夹",
|
"이 기기의 폴더": "本设备上的文件夹",
|
||||||
|
|
@ -1488,6 +1518,9 @@
|
||||||
"작업하다 남은 임시 파일 · 받다 만 다운로드 (.part 등) · 받다 만 AI 모델 · 업데이트하고 남은 파일 · 지난 작업 기록을 찾아 지웁니다. 받은 동영상 · 만든 MKV · 자막은 지우지 않고, 진행 중인 작업 · 다운로드가 쓰는 것은 건너뜁니다": "查找并删除任务残留的临时文件 · 未完成的下载(.part 等)· 未下载完的 AI 模型 · 更新残留 · 旧任务记录。不会删除已下载的视频 · 制作的 MKV · 字幕,正在进行的任务 · 下载所用的文件会跳过",
|
"작업하다 남은 임시 파일 · 받다 만 다운로드 (.part 등) · 받다 만 AI 모델 · 업데이트하고 남은 파일 · 지난 작업 기록을 찾아 지웁니다. 받은 동영상 · 만든 MKV · 자막은 지우지 않고, 진행 중인 작업 · 다운로드가 쓰는 것은 건너뜁니다": "查找并删除任务残留的临时文件 · 未完成的下载(.part 等)· 未下载完的 AI 模型 · 更新残留 · 旧任务记录。不会删除已下载的视频 · 制作的 MKV · 字幕,正在进行的任务 · 下载所用的文件会跳过",
|
||||||
"작은 용량": "小体积",
|
"작은 용량": "小体积",
|
||||||
"잘못된 varint (위치 {0})": "无效的 varint(位置 {0})",
|
"잘못된 varint (위치 {0})": "无效的 varint(位置 {0})",
|
||||||
|
"잘못된 간격: {0}": "无效的间隔: {0}",
|
||||||
|
"잘못된 범위: {0}": "无效的范围: {0}",
|
||||||
|
"잘못된 칸: {0}": "无效的字段: {0}",
|
||||||
"재개": "继续",
|
"재개": "继续",
|
||||||
"재생": "播放",
|
"재생": "播放",
|
||||||
"재생 목록": "播放列表",
|
"재생 목록": "播放列表",
|
||||||
|
|
@ -1719,6 +1752,7 @@
|
||||||
"칠한 시간이 없어 동기화하지 않습니다.": "没有涂色的时间,因此不会同步。",
|
"칠한 시간이 없어 동기화하지 않습니다.": "没有涂色的时间,因此不会同步。",
|
||||||
"칸에 보이는 옵션: {0}\n저장된 옵션: {1}\n\n고친 옵션을 저장하고 실행할까요?": "输入框中的选项: {0}\n已保存的选项: {1}\n\n保存修改的选项并执行吗?",
|
"칸에 보이는 옵션: {0}\n저장된 옵션: {1}\n\n고친 옵션을 저장하고 실행할까요?": "输入框中的选项: {0}\n已保存的选项: {1}\n\n保存修改的选项并执行吗?",
|
||||||
"컴포넌트": "组件",
|
"컴포넌트": "组件",
|
||||||
|
"컴포넌트 목록을 받을 수 없습니다 ({0})": "无法获取组件列表({0})",
|
||||||
"켜기": "开启",
|
"켜기": "开启",
|
||||||
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "开启后双击会直接翻看其中的图片;关闭则打开文件列表 (选择解压)。",
|
"켜면 두 번 눌렀을 때 안의 그림을 바로 넘겨 봅니다. 끄면 목록 (골라서 풀기) 을 엽니다.": "开启后双击会直接翻看其中的图片;关闭则打开文件列表 (选择解压)。",
|
||||||
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "开启时会下载并安装转换器 (约 420MB)。关闭时会删除。",
|
"켜면 변환기를 내려받아 설치합니다 (약 420MB). 끄면 지웁니다.": "开启时会下载并安装转换器 (约 420MB)。关闭时会删除。",
|
||||||
|
|
@ -1772,10 +1806,12 @@
|
||||||
"파일이 깨졌습니다": "文件已损坏",
|
"파일이 깨졌습니다": "文件已损坏",
|
||||||
"파일이 깨졌습니다 · [다시 받기] 를 눌러 주세요": "文件已损坏 · 请点按 [重新下载]",
|
"파일이 깨졌습니다 · [다시 받기] 를 눌러 주세요": "文件已损坏 · 请点按 [重新下载]",
|
||||||
"파일이 보이지 않습니다: \"모든 파일에 대한 접근\" 권한이 없습니다": "文件不可见: 没有“所有文件访问”权限",
|
"파일이 보이지 않습니다: \"모든 파일에 대한 접근\" 권한이 없습니다": "文件不可见: 没有“所有文件访问”权限",
|
||||||
|
"파일이 손상되었습니다 (SHA-256 다름): {0}": "文件已损坏(SHA-256 不一致): {0}",
|
||||||
"파일이 없습니다 (지워졌거나 옮겨짐)": "找不到文件 (已删除或移动)",
|
"파일이 없습니다 (지워졌거나 옮겨짐)": "找不到文件 (已删除或移动)",
|
||||||
"팝업 끄기": "关闭弹出窗口",
|
"팝업 끄기": "关闭弹出窗口",
|
||||||
"팝업 보기": "弹出窗口观看",
|
"팝업 보기": "弹出窗口观看",
|
||||||
"패키지 라이선스": "软件包许可",
|
"패키지 라이선스": "软件包许可",
|
||||||
|
"패키지에 {0} 이 없습니다": "包中缺少 {0}",
|
||||||
"페르시아어": "波斯语",
|
"페르시아어": "波斯语",
|
||||||
"페이지 열기": "打开页面",
|
"페이지 열기": "打开页面",
|
||||||
"페이지 지우기": "删除页面",
|
"페이지 지우기": "删除页面",
|
||||||
|
|
@ -1809,6 +1845,7 @@
|
||||||
"폴더가 없습니다": "文件夹不存在",
|
"폴더가 없습니다": "文件夹不存在",
|
||||||
"폴더는 보여도 그 안의 동영상 · 파일은 이 권한이 있어야 보입니다. 허용 화면에서 JJ_MKVMaker 를 켜고 돌아오세요.": "虽然能看到文件夹,但其中的视频和文件需要此权限。请在权限界面开启 JJ_MKVMaker 后返回。",
|
"폴더는 보여도 그 안의 동영상 · 파일은 이 권한이 있어야 보입니다. 허용 화면에서 JJ_MKVMaker 를 켜고 돌아오세요.": "虽然能看到文件夹,但其中的视频和文件需要此权限。请在权限界面开启 JJ_MKVMaker 后返回。",
|
||||||
"폴더를 만들 수 없습니다: {0}": "无法创建文件夹: {0}",
|
"폴더를 만들 수 없습니다: {0}": "无法创建文件夹: {0}",
|
||||||
|
"폴더를 자기 안으로 복사 · 이동할 수 없습니다": "不能将文件夹复制或移动到其自身内部",
|
||||||
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "不能将文件夹{0}到其自身内部: {1}",
|
"폴더를 자기 자신 안으로 {0} 수 없습니다: {1}": "不能将文件夹{0}到其自身内部: {1}",
|
||||||
"폴더만 lsync 로 옮길 수 있습니다.": "只有文件夹可以移到 lsync。",
|
"폴더만 lsync 로 옮길 수 있습니다.": "只有文件夹可以移到 lsync。",
|
||||||
"폴란드어": "波兰语",
|
"폴란드어": "波兰语",
|
||||||
|
|
@ -1818,6 +1855,7 @@
|
||||||
"표시 지우기": "清除标记",
|
"표시 지우기": "清除标记",
|
||||||
"표준": "标准",
|
"표준": "标准",
|
||||||
"푸는 중": "正在解压",
|
"푸는 중": "正在解压",
|
||||||
|
"푸는 중: {0}": "正在解压: {0}",
|
||||||
"풀지 못했습니다: {0}": "无法解压: {0}",
|
"풀지 못했습니다: {0}": "无法解压: {0}",
|
||||||
"프랑스어": "法语",
|
"프랑스어": "法语",
|
||||||
"프로그램": "程序",
|
"프로그램": "程序",
|
||||||
|
|
@ -1898,6 +1936,8 @@
|
||||||
"확인 창에서 알린 뒤 허용합니다. 지우기 (--delete) 가 있으면 늘 막습니다. 끄면 늘 막습니다": "在确认窗口中提示后允许。有删除 (--delete) 时始终阻止。关闭后始终阻止",
|
"확인 창에서 알린 뒤 허용합니다. 지우기 (--delete) 가 있으면 늘 막습니다. 끄면 늘 막습니다": "在确认窗口中提示后允许。有删除 (--delete) 时始终阻止。关闭后始终阻止",
|
||||||
"확인됨": "已校验",
|
"확인됨": "已校验",
|
||||||
"확장 설치": "安装扩展",
|
"확장 설치": "安装扩展",
|
||||||
|
"확장 설치: {0}": "安装扩展: {0}",
|
||||||
|
"확장을 설치할 수 없습니다 ({0}): {1}": "无法安装扩展({0}): {1}",
|
||||||
"확장자": "扩展名",
|
"확장자": "扩展名",
|
||||||
"확장자별 재생 프로그램": "按扩展名设置播放程序",
|
"확장자별 재생 프로그램": "按扩展名设置播放程序",
|
||||||
"환경 설정": "设置",
|
"환경 설정": "设置",
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:crypto/crypto.dart';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
import '../core/app_update.dart' show updateRepo;
|
import '../core/app_update.dart' show updateRepo;
|
||||||
|
import '../l10n/tr.dart';
|
||||||
|
|
||||||
/// 컴포넌트 목록 (GitHub 릴리스 "components" 의 components.json) 주소
|
/// 컴포넌트 목록 (GitHub 릴리스 "components" 의 components.json) 주소
|
||||||
const componentsManifestUrl = 'https://github.com/$updateRepo/releases/download/components/components.json';
|
const componentsManifestUrl = 'https://github.com/$updateRepo/releases/download/components/components.json';
|
||||||
|
|
@ -95,7 +96,7 @@ class ComponentStore {
|
||||||
final req = await _http.getUrl(Uri.parse(manifestUrl));
|
final req = await _http.getUrl(Uri.parse(manifestUrl));
|
||||||
final res = await req.close();
|
final res = await req.close();
|
||||||
final body = await res.transform(utf8.decoder).join();
|
final body = await res.transform(utf8.decoder).join();
|
||||||
if (res.statusCode != 200) throw ComponentException('컴포넌트 목록을 받을 수 없습니다 (${res.statusCode})');
|
if (res.statusCode != 200) throw ComponentException(trf('컴포넌트 목록을 받을 수 없습니다 ({0})', [res.statusCode]));
|
||||||
return ComponentManifest.parse(body);
|
return ComponentManifest.parse(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,7 +106,7 @@ class ComponentStore {
|
||||||
_cancel = false;
|
_cancel = false;
|
||||||
final m = await manifest();
|
final m = await manifest();
|
||||||
final files = m.files(id, platform);
|
final files = m.files(id, platform);
|
||||||
if (files == null) throw const ComponentException('이 기기에서는 쓸 수 없는 컴포넌트입니다');
|
if (files == null) throw ComponentException(tr('이 기기에서는 쓸 수 없는 컴포넌트입니다'));
|
||||||
final dir = dirOf(id);
|
final dir = dirOf(id);
|
||||||
final dl = Directory(p.join(dir.path, '_download'));
|
final dl = Directory(p.join(dir.path, '_download'));
|
||||||
await dl.create(recursive: true);
|
await dl.create(recursive: true);
|
||||||
|
|
@ -113,20 +114,20 @@ class ComponentStore {
|
||||||
final got = <(ComponentFile, File)>[];
|
final got = <(ComponentFile, File)>[];
|
||||||
for (final f in files) {
|
for (final f in files) {
|
||||||
final out = File(p.join(dl.path, f.name.isEmpty ? p.basename(Uri.parse(f.url).path) : f.name));
|
final out = File(p.join(dl.path, f.name.isEmpty ? p.basename(Uri.parse(f.url).path) : f.name));
|
||||||
await _download(f, out, (d) => onProgress?.call('받는 중: ${f.name}', d));
|
await _download(f, out, (d) => onProgress?.call(trf('받는 중: {0}', [f.name]), d));
|
||||||
got.add((f, out));
|
got.add((f, out));
|
||||||
}
|
}
|
||||||
for (final (f, file) in got) {
|
for (final (f, file) in got) {
|
||||||
if (_cancel) throw const ComponentException('취소했습니다');
|
if (_cancel) throw ComponentException(tr('취소했습니다'));
|
||||||
switch (f.kind) {
|
switch (f.kind) {
|
||||||
case 'msi':
|
case 'msi':
|
||||||
onProgress?.call('푸는 중: ${f.name}', null);
|
onProgress?.call(trf('푸는 중: {0}', [f.name]), null);
|
||||||
await _runMsiAdmin(file.path, p.join(dir.path, 'app'));
|
await _runMsiAdmin(file.path, p.join(dir.path, 'app'));
|
||||||
case 'zip':
|
case 'zip':
|
||||||
onProgress?.call('푸는 중: ${f.name}', null);
|
onProgress?.call(trf('푸는 중: {0}', [f.name]), null);
|
||||||
await extractFileToDisk(file.path, p.join(dir.path, 'jre'));
|
await extractFileToDisk(file.path, p.join(dir.path, 'jre'));
|
||||||
case 'oxt':
|
case 'oxt':
|
||||||
onProgress?.call('확장 설치: ${f.name}', null);
|
onProgress?.call(trf('확장 설치: {0}', [f.name]), null);
|
||||||
await _addExtension(id, file.path);
|
await _addExtension(id, file.path);
|
||||||
default:
|
default:
|
||||||
await file.copy(p.join(dir.path, p.basename(file.path)));
|
await file.copy(p.join(dir.path, p.basename(file.path)));
|
||||||
|
|
@ -148,7 +149,7 @@ class ComponentStore {
|
||||||
Future<void> _download(ComponentFile f, File out, void Function(double? progress) onProgress) async {
|
Future<void> _download(ComponentFile f, File out, void Function(double? progress) onProgress) async {
|
||||||
final req = await _http.getUrl(Uri.parse(f.url));
|
final req = await _http.getUrl(Uri.parse(f.url));
|
||||||
final res = await req.close();
|
final res = await req.close();
|
||||||
if (res.statusCode != 200) throw ComponentException('받을 수 없습니다 (${res.statusCode}): ${f.url}');
|
if (res.statusCode != 200) throw ComponentException(trf('받을 수 없습니다 ({0}): {1}', [res.statusCode, f.url]));
|
||||||
final total = res.contentLength > 0 ? res.contentLength : f.size;
|
final total = res.contentLength > 0 ? res.contentLength : f.size;
|
||||||
final sink = out.openWrite();
|
final sink = out.openWrite();
|
||||||
final hash = AccumulatorSink<Digest>();
|
final hash = AccumulatorSink<Digest>();
|
||||||
|
|
@ -156,7 +157,7 @@ class ComponentStore {
|
||||||
var done = 0;
|
var done = 0;
|
||||||
try {
|
try {
|
||||||
await for (final chunk in res) {
|
await for (final chunk in res) {
|
||||||
if (_cancel) throw const ComponentException('취소했습니다');
|
if (_cancel) throw ComponentException(tr('취소했습니다'));
|
||||||
sink.add(chunk);
|
sink.add(chunk);
|
||||||
hasher.add(chunk);
|
hasher.add(chunk);
|
||||||
done += chunk.length;
|
done += chunk.length;
|
||||||
|
|
@ -169,7 +170,7 @@ class ComponentStore {
|
||||||
final sum = hash.events.single.toString();
|
final sum = hash.events.single.toString();
|
||||||
if (f.sha256 != null && f.sha256!.isNotEmpty && sum != f.sha256) {
|
if (f.sha256 != null && f.sha256!.isNotEmpty && sum != f.sha256) {
|
||||||
await out.delete();
|
await out.delete();
|
||||||
throw ComponentException('파일이 손상되었습니다 (SHA-256 다름): ${f.name}');
|
throw ComponentException(trf('파일이 손상되었습니다 (SHA-256 다름): {0}', [f.name]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -177,7 +178,7 @@ class ComponentStore {
|
||||||
Future<void> _runMsiAdmin(String msi, String target) async {
|
Future<void> _runMsiAdmin(String msi, String target) async {
|
||||||
await Directory(target).create(recursive: true);
|
await Directory(target).create(recursive: true);
|
||||||
final r = await Process.run('msiexec', ['/a', msi, '/qn', 'TARGETDIR=$target']);
|
final r = await Process.run('msiexec', ['/a', msi, '/qn', 'TARGETDIR=$target']);
|
||||||
if (r.exitCode != 0) throw ComponentException('설치 파일을 풀 수 없습니다 (msiexec ${r.exitCode})');
|
if (r.exitCode != 0) throw ComponentException(trf('설치 파일을 풀 수 없습니다 (msiexec {0})', [r.exitCode]));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ───────── 문서 미리보기 (LibreOffice) ─────────
|
// ───────── 문서 미리보기 (LibreOffice) ─────────
|
||||||
|
|
@ -217,17 +218,17 @@ class ComponentStore {
|
||||||
|
|
||||||
Future<void> _addExtension(String id, String oxt) async {
|
Future<void> _addExtension(String id, String oxt) async {
|
||||||
final office = soffice(id);
|
final office = soffice(id);
|
||||||
if (office == null) throw const ComponentException('LibreOffice 를 먼저 설치해야 합니다');
|
if (office == null) throw ComponentException(tr('LibreOffice 를 먼저 설치해야 합니다'));
|
||||||
final unopkg = p.join(p.dirname(office), 'unopkg.com');
|
final unopkg = p.join(p.dirname(office), 'unopkg.com');
|
||||||
final r = await Process.run(unopkg, ['add', '--suppress-license', '-env:UserInstallation=${_profileUrl(id)}', oxt],
|
final r = await Process.run(unopkg, ['add', '--suppress-license', '-env:UserInstallation=${_profileUrl(id)}', oxt],
|
||||||
environment: _env(id));
|
environment: _env(id));
|
||||||
if (r.exitCode != 0) throw ComponentException('확장을 설치할 수 없습니다 (${r.exitCode}): ${r.stderr}');
|
if (r.exitCode != 0) throw ComponentException(trf('확장을 설치할 수 없습니다 ({0}): {1}', [r.exitCode, r.stderr]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 문서를 PDF 로 ([outDir] 에 만든 PDF 경로)
|
/// 문서를 PDF 로 ([outDir] 에 만든 PDF 경로)
|
||||||
Future<String> convertToPdf(String input, String outDir, {String id = 'docs'}) async {
|
Future<String> convertToPdf(String input, String outDir, {String id = 'docs'}) async {
|
||||||
final office = soffice(id);
|
final office = soffice(id);
|
||||||
if (office == null) throw const ComponentException('문서 미리보기 컴포넌트를 먼저 설치하세요');
|
if (office == null) throw ComponentException(tr('문서 미리보기 컴포넌트를 먼저 설치하세요'));
|
||||||
await Directory(outDir).create(recursive: true);
|
await Directory(outDir).create(recursive: true);
|
||||||
final r = await Process.run(office, [
|
final r = await Process.run(office, [
|
||||||
'--headless', '--norestore', '--nologo', '--nodefault',
|
'--headless', '--norestore', '--nologo', '--nodefault',
|
||||||
|
|
@ -236,7 +237,7 @@ class ComponentStore {
|
||||||
], environment: _env(id)).timeout(const Duration(minutes: 3));
|
], environment: _env(id)).timeout(const Duration(minutes: 3));
|
||||||
final out = p.join(outDir, '${p.basenameWithoutExtension(input)}.pdf');
|
final out = p.join(outDir, '${p.basenameWithoutExtension(input)}.pdf');
|
||||||
if (!File(out).existsSync()) {
|
if (!File(out).existsSync()) {
|
||||||
throw ComponentException('PDF 로 바꾸지 못했습니다 (${r.exitCode}) ${'${r.stderr}'.trim()}');
|
throw ComponentException(trf('PDF 로 바꾸지 못했습니다 ({0}) {1}', [r.exitCode, '${r.stderr}'.trim()]));
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import '../core/webdav.dart';
|
||||||
import '../services/image_ai.dart' show AiService;
|
import '../services/image_ai.dart' show AiService;
|
||||||
import '../services/app_shell.dart' show appIconOf;
|
import '../services/app_shell.dart' show appIconOf;
|
||||||
import '../services/secret_store.dart';
|
import '../services/secret_store.dart';
|
||||||
|
import '../l10n/tr.dart';
|
||||||
|
|
||||||
/// MKV 세부 정보의 이동 버튼 하나: 표시 이름 · 옮길 폴더
|
/// MKV 세부 정보의 이동 버튼 하나: 표시 이름 · 옮길 폴더
|
||||||
class MoveTarget {
|
class MoveTarget {
|
||||||
|
|
@ -1238,7 +1239,7 @@ class SettingsStore {
|
||||||
if (await bak.exists()) {
|
if (await bak.exists()) {
|
||||||
try {
|
try {
|
||||||
final s = _parse(await bak.readAsString());
|
final s = _parse(await bak.readAsString());
|
||||||
problem = SettingsLoadProblem(restoredFromBackup: true, brokenCopy: null, error: 'settings.json 없음');
|
problem = SettingsLoadProblem(restoredFromBackup: true, brokenCopy: null, error: tr('settings.json 없음'));
|
||||||
_scrub.add(bak);
|
_scrub.add(bak);
|
||||||
return s;
|
return s;
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import '../core/file_ops.dart';
|
||||||
import '../core/sync_preview.dart' show isRsyncDeleteOption;
|
import '../core/sync_preview.dart' show isRsyncDeleteOption;
|
||||||
import '../core/sync_tools.dart';
|
import '../core/sync_tools.dart';
|
||||||
import '../core/vfs.dart';
|
import '../core/vfs.dart';
|
||||||
|
import '../l10n/tr.dart';
|
||||||
|
|
||||||
/// 복사 · 이동 한 번 (파일 탐색기). 방법 (현재 방식 · rsync · robocopy) 과 상관없이 같은 진행 상태를 알린다:
|
/// 복사 · 이동 한 번 (파일 탐색기). 방법 (현재 방식 · rsync · robocopy) 과 상관없이 같은 진행 상태를 알린다:
|
||||||
/// - 위쪽: 고른 항목 (폴더) 중 몇 번째인지 · 전체 진행률
|
/// - 위쪽: 고른 항목 (폴더) 중 몇 번째인지 · 전체 진행률
|
||||||
|
|
@ -184,7 +185,7 @@ class TransferJob extends ChangeNotifier {
|
||||||
for (var i = 0; i < sources.length; i++) {
|
for (var i = 0; i < sources.length; i++) {
|
||||||
final s = sources[i];
|
final s = sources[i];
|
||||||
if ((isDav(s) || FileSystemEntity.isDirectorySync(s)) && isSameOrInside(dest, s)) {
|
if ((isDav(s) || FileSystemEntity.isDirectorySync(s)) && isSameOrInside(dest, s)) {
|
||||||
throw FileSystemException('폴더를 자기 안으로 복사 · 이동할 수 없습니다', s);
|
throw FileSystemException(tr('폴더를 자기 안으로 복사 · 이동할 수 없습니다'), s);
|
||||||
}
|
}
|
||||||
filesTotal[i] = await countFiles(s);
|
filesTotal[i] = await countFiles(s);
|
||||||
// 앱이 직접 복사할 때만 (robocopy · rsync 는 그 프로그램이 진행을 알려 줌)
|
// 앱이 직접 복사할 때만 (robocopy · rsync 는 그 프로그램이 진행을 알려 줌)
|
||||||
|
|
@ -290,7 +291,7 @@ class TransferJob extends ChangeNotifier {
|
||||||
|
|
||||||
Future<void> _runRsync() async {
|
Future<void> _runRsync() async {
|
||||||
final exe = rsyncExe;
|
final exe = rsyncExe;
|
||||||
if (exe == null || exe.isEmpty) throw StateError('rsync 실행 파일이 없습니다');
|
if (exe == null || exe.isEmpty) throw StateError(tr('rsync 실행 파일이 없습니다'));
|
||||||
final windows = Platform.isWindows;
|
final windows = Platform.isWindows;
|
||||||
Future<void> one(List<int> idx) async {
|
Future<void> one(List<int> idx) async {
|
||||||
final out = RsyncOutput();
|
final out = RsyncOutput();
|
||||||
|
|
@ -328,7 +329,7 @@ class TransferJob extends ChangeNotifier {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
if (!rsyncOk(code)) throw ProcessException(exe, const [], 'rsync 종료 코드 $code\n${log.take(8).join('\n')}', code);
|
if (!rsyncOk(code)) throw ProcessException(exe, const [], '${trf('rsync 종료 코드 {0}', [code])}\n${log.take(8).join('\n')}', code);
|
||||||
for (final i in idx) {
|
for (final i in idx) {
|
||||||
filesDone[i] = filesTotal[i];
|
filesDone[i] = filesTotal[i];
|
||||||
made.add(p.join(dest, p.basename(sources[i])));
|
made.add(p.join(dest, p.basename(sources[i])));
|
||||||
|
|
@ -386,7 +387,7 @@ class TransferJob extends ChangeNotifier {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
if (!robocopyOk(code)) throw ProcessException('robocopy', const [], 'robocopy 종료 코드 $code', code);
|
if (!robocopyOk(code)) throw ProcessException('robocopy', const [], trf('robocopy 종료 코드 {0}', [code]), code);
|
||||||
}
|
}
|
||||||
filesDone[index] = filesTotal[index];
|
filesDone[index] = filesTotal[index];
|
||||||
made.add(p.join(dest, p.basename(s)));
|
made.add(p.join(dest, p.basename(s)));
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
/// 예: "0 9-17 * * 1-5" 평일 9시~17시 59분, "0 0-5 * * *" 매일 0시~5시 59분, "0 */2 * * 0,6" 주말 2시간마다 1시간씩.
|
/// 예: "0 9-17 * * 1-5" 평일 9시~17시 59분, "0 0-5 * * *" 매일 0시~5시 59분, "0 */2 * * 0,6" 주말 2시간마다 1시간씩.
|
||||||
library;
|
library;
|
||||||
|
|
||||||
|
import '../l10n/tr.dart';
|
||||||
|
|
||||||
/// cron 글 한 줄
|
/// cron 글 한 줄
|
||||||
class CronExpr {
|
class CronExpr {
|
||||||
final Set<int> minutes, hours, days, months, weekdays;
|
final Set<int> minutes, hours, days, months, weekdays;
|
||||||
|
|
@ -23,7 +25,7 @@ class CronExpr {
|
||||||
/// 잘못된 글이면 FormatException
|
/// 잘못된 글이면 FormatException
|
||||||
static CronExpr parse(String text) {
|
static CronExpr parse(String text) {
|
||||||
final f = text.trim().split(RegExp(r'\s+'));
|
final f = text.trim().split(RegExp(r'\s+'));
|
||||||
if (f.length != 5) throw FormatException('cron 은 다섯 칸입니다 (분 시 일 월 요일)', text);
|
if (f.length != 5) throw FormatException(tr('cron 은 다섯 칸입니다 (분 시 일 월 요일)'), text);
|
||||||
final wd = _field(f[4], 0, 7, _dows).map((d) => d == 7 ? 0 : d).toSet();
|
final wd = _field(f[4], 0, 7, _dows).map((d) => d == 7 ? 0 : d).toSet();
|
||||||
return CronExpr._(text.trim(), _field(f[0], 0, 59), _field(f[1], 0, 23), _field(f[2], 1, 31), _field(f[3], 1, 12, _mons),
|
return CronExpr._(text.trim(), _field(f[0], 0, 59), _field(f[1], 0, 23), _field(f[2], 1, 31), _field(f[3], 1, 12, _mons),
|
||||||
wd, f[2] == '*', f[4] == '*');
|
wd, f[2] == '*', f[4] == '*');
|
||||||
|
|
@ -40,16 +42,16 @@ class CronExpr {
|
||||||
static Set<int> _field(String s, int lo, int hi, [Map<String, int> names = const {}]) {
|
static Set<int> _field(String s, int lo, int hi, [Map<String, int> names = const {}]) {
|
||||||
int num(String x) {
|
int num(String x) {
|
||||||
final n = names[x.toUpperCase()] ?? int.tryParse(x);
|
final n = names[x.toUpperCase()] ?? int.tryParse(x);
|
||||||
if (n == null || n < lo || n > hi) throw FormatException('범위 밖 값: $x ($lo~$hi)');
|
if (n == null || n < lo || n > hi) throw FormatException(trf('범위 밖 값: {0} ({1}~{2})', [x, lo, hi]));
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
final out = <int>{};
|
final out = <int>{};
|
||||||
for (final part in s.split(',')) {
|
for (final part in s.split(',')) {
|
||||||
final stepParts = part.split('/');
|
final stepParts = part.split('/');
|
||||||
if (stepParts.length > 2) throw FormatException('잘못된 칸: $part');
|
if (stepParts.length > 2) throw FormatException(trf('잘못된 칸: {0}', [part]));
|
||||||
final step = stepParts.length == 2 ? int.tryParse(stepParts[1]) : 1;
|
final step = stepParts.length == 2 ? int.tryParse(stepParts[1]) : 1;
|
||||||
if (step == null || step < 1) throw FormatException('잘못된 간격: $part');
|
if (step == null || step < 1) throw FormatException(trf('잘못된 간격: {0}', [part]));
|
||||||
final range = stepParts[0];
|
final range = stepParts[0];
|
||||||
int a, b;
|
int a, b;
|
||||||
if (range == '*') {
|
if (range == '*') {
|
||||||
|
|
@ -57,10 +59,10 @@ class CronExpr {
|
||||||
b = hi;
|
b = hi;
|
||||||
} else if (range.contains('-')) {
|
} else if (range.contains('-')) {
|
||||||
final r = range.split('-');
|
final r = range.split('-');
|
||||||
if (r.length != 2) throw FormatException('잘못된 범위: $part');
|
if (r.length != 2) throw FormatException(trf('잘못된 범위: {0}', [part]));
|
||||||
a = num(r[0]);
|
a = num(r[0]);
|
||||||
b = num(r[1]);
|
b = num(r[1]);
|
||||||
if (b < a) throw FormatException('거꾸로 된 범위: $part');
|
if (b < a) throw FormatException(trf('거꾸로 된 범위: {0}', [part]));
|
||||||
} else {
|
} else {
|
||||||
a = num(range);
|
a = num(range);
|
||||||
b = stepParts.length == 2 ? hi : a;
|
b = stepParts.length == 2 ? hi : a;
|
||||||
|
|
|
||||||
|
|
@ -569,7 +569,7 @@ class FileOps {
|
||||||
static Future<String> rename(String path, String newName) async {
|
static Future<String> rename(String path, String newName) async {
|
||||||
final name = newName.trim();
|
final name = newName.trim();
|
||||||
if (name.isEmpty || name.contains(RegExp(r'[\\/:*?"<>|]'))) {
|
if (name.isEmpty || name.contains(RegExp(r'[\\/:*?"<>|]'))) {
|
||||||
throw FileSystemException('쓸 수 없는 이름입니다', name);
|
throw FileSystemException(tr('쓸 수 없는 이름입니다'), name);
|
||||||
}
|
}
|
||||||
if (isDav(path)) {
|
if (isDav(path)) {
|
||||||
final target = vJoin(vDirname(path), name);
|
final target = vJoin(vDirname(path), name);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import 'package:pdfrx/pdfrx.dart';
|
||||||
|
|
||||||
import 'playlist.dart' show naturalCompare;
|
import 'playlist.dart' show naturalCompare;
|
||||||
import 'vfs.dart';
|
import 'vfs.dart';
|
||||||
|
import '../l10n/tr.dart';
|
||||||
|
|
||||||
/// 그림 보기 (만화 보기) 의 기본 대상 확장자 (환경 설정에서 바꿈)
|
/// 그림 보기 (만화 보기) 의 기본 대상 확장자 (환경 설정에서 바꿈)
|
||||||
const defaultImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
|
const defaultImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'bmp'];
|
||||||
|
|
@ -207,7 +208,7 @@ Future<PdfDocument> imagePageDocument(String path, {required String tempDir, req
|
||||||
final local = await vLocalCopy(path, tempDir);
|
final local = await vLocalCopy(path, tempDir);
|
||||||
final bytes = await File(local).readAsBytes();
|
final bytes = await File(local).readAsBytes();
|
||||||
final decoded = img.decodeImage(bytes);
|
final decoded = img.decodeImage(bytes);
|
||||||
if (decoded == null) throw FormatException('그림을 읽을 수 없습니다', vBasename(path));
|
if (decoded == null) throw FormatException(tr('그림을 읽을 수 없습니다'), vBasename(path));
|
||||||
final jpeg = extOf(path) == 'jpg' || extOf(path) == 'jpeg' ? bytes : Uint8List.fromList(img.encodeJpg(decoded, quality: 92));
|
final jpeg = extOf(path) == 'jpg' || extOf(path) == 'jpeg' ? bytes : Uint8List.fromList(img.encodeJpg(decoded, quality: 92));
|
||||||
return PdfDocument.createFromJpegData(jpeg,
|
return PdfDocument.createFromJpegData(jpeg,
|
||||||
width: decoded.width * 0.75, height: decoded.height * 0.75, sourceName: sourceName);
|
width: decoded.width * 0.75, height: decoded.height * 0.75, sourceName: sourceName);
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import 'dart:io';
|
||||||
import 'package:path/path.dart' as p;
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
import 'webdav.dart';
|
import 'webdav.dart';
|
||||||
|
import '../l10n/tr.dart';
|
||||||
|
|
||||||
/// 로컬 경로와 WebDAV 경로 (`dav://<서버 id>/<경로>`) 를 같이 다루는 도구.
|
/// 로컬 경로와 WebDAV 경로 (`dav://<서버 id>/<경로>`) 를 같이 다루는 도구.
|
||||||
/// 로컬 경로는 원래 코드 (dart:io) 를 그대로 쓰고, dav:// 만 여기서 WebDAV 로 처리한다.
|
/// 로컬 경로는 원래 코드 (dart:io) 를 그대로 쓰고, dav:// 만 여기서 WebDAV 로 처리한다.
|
||||||
|
|
@ -198,7 +199,7 @@ Future<void> vRename(String from, String to) async {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (isDav(from) || isDav(to)) throw FileSystemException('다른 저장소로는 이름만 바꿀 수 없습니다', from);
|
if (isDav(from) || isDav(to)) throw FileSystemException(tr('다른 저장소로는 이름만 바꿀 수 없습니다'), from);
|
||||||
if (FileSystemEntity.isDirectorySync(from)) {
|
if (FileSystemEntity.isDirectorySync(from)) {
|
||||||
await Directory(from).rename(to);
|
await Directory(from).rename(to);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import '../l10n/tr.dart';
|
||||||
|
|
||||||
/// 앱 안 웹 브라우저의 페이지 번역 (환경 설정 > 웹 브라우저 > 웹 페이지 자동 번역).
|
/// 앱 안 웹 브라우저의 페이지 번역 (환경 설정 > 웹 브라우저 > 웹 페이지 자동 번역).
|
||||||
///
|
///
|
||||||
|
|
@ -256,7 +257,7 @@ class WebPageTranslator {
|
||||||
static List<(String, String)> parseGoogleResponse(String body, int count) {
|
static List<(String, String)> parseGoogleResponse(String body, int count) {
|
||||||
final v = jsonDecode(body);
|
final v = jsonDecode(body);
|
||||||
if (v is! List || v.length != count) {
|
if (v is! List || v.length != count) {
|
||||||
throw FormatException('번역 응답의 개수가 다릅니다 (${v is List ? v.length : '?'} / $count)');
|
throw FormatException(trf('번역 응답의 개수가 다릅니다 ({0} / {1})', [v is List ? v.length : '?', count]));
|
||||||
}
|
}
|
||||||
return [
|
return [
|
||||||
for (final x in v)
|
for (final x in v)
|
||||||
|
|
@ -272,7 +273,7 @@ class WebPageTranslator {
|
||||||
req.add(utf8.encode(body));
|
req.add(utf8.encode(body));
|
||||||
final res = await req.close().timeout(const Duration(seconds: 20));
|
final res = await req.close().timeout(const Duration(seconds: 20));
|
||||||
final text = await res.transform(utf8.decoder).join().timeout(const Duration(seconds: 20));
|
final text = await res.transform(utf8.decoder).join().timeout(const Duration(seconds: 20));
|
||||||
if (res.statusCode != 200) throw HttpException('번역 서버 응답 ${res.statusCode}', uri: url);
|
if (res.statusCode != 200) throw HttpException(trf('번역 서버 응답 {0}', [res.statusCode]), uri: url);
|
||||||
return text;
|
return text;
|
||||||
} finally {
|
} finally {
|
||||||
client.close(force: true);
|
client.close(force: true);
|
||||||
|
|
|
||||||
|
|
@ -140,14 +140,15 @@ class DavClient {
|
||||||
final hint = switch (res.statusCode) {
|
final hint = switch (res.statusCode) {
|
||||||
// 54: 비밀번호가 틀린 것이 아니라 저장된 것이 없다 (동기화 · 복사 오류에도 그대로 보인다)
|
// 54: 비밀번호가 틀린 것이 아니라 저장된 것이 없다 (동기화 · 복사 오류에도 그대로 보인다)
|
||||||
401 when server.password.isEmpty => ' (${tr('저장된 비밀번호가 없습니다. 한 번만 다시 넣어 주세요')})',
|
401 when server.password.isEmpty => ' (${tr('저장된 비밀번호가 없습니다. 한 번만 다시 넣어 주세요')})',
|
||||||
401 => ' (아이디 · 비밀번호를 확인하세요)',
|
401 => ' (${tr('아이디 · 비밀번호를 확인하세요')})',
|
||||||
403 => ' (권한 없음)',
|
403 => ' (${tr('권한 없음')})',
|
||||||
404 => ' (없는 경로)',
|
404 => ' (${tr('없는 경로')})',
|
||||||
405 => ' (서버가 이 기능을 허용하지 않음)',
|
405 => ' (${tr('서버가 이 기능을 허용하지 않음')})',
|
||||||
507 => ' (서버 저장 공간 부족)',
|
507 => ' (${tr('서버 저장 공간 부족')})',
|
||||||
_ => '',
|
_ => '',
|
||||||
};
|
};
|
||||||
throw DavException('WebDAV $what 실패: ${res.statusCode} ${res.reasonPhrase}$hint', status: res.statusCode);
|
// 상태 번호 앞의 빈칸은 그대로 둔다 (explainFileError 가 " 401" 등으로 오류 종류를 가른다)
|
||||||
|
throw DavException(trf('WebDAV {0} 실패: {1} {2}{3}', [what, res.statusCode, res.reasonPhrase, hint]), status: res.statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const _propfindBody = '<?xml version="1.0" encoding="utf-8"?>'
|
static const _propfindBody = '<?xml version="1.0" encoding="utf-8"?>'
|
||||||
|
|
@ -164,8 +165,8 @@ class DavClient {
|
||||||
req.add(bytes);
|
req.add(bytes);
|
||||||
final res = await req.close();
|
final res = await req.close();
|
||||||
final text = await res.transform(utf8.decoder).join();
|
final text = await res.transform(utf8.decoder).join();
|
||||||
if (res.statusCode == 404) throw DavException('없는 경로: $rel', status: 404);
|
if (res.statusCode == 404) throw DavException(trf('없는 경로: {0}', [rel]), status: 404);
|
||||||
if (res.statusCode != 207 && res.statusCode != 200) _fail('목록', res, text);
|
if (res.statusCode != 207 && res.statusCode != 200) _fail(tr('목록'), res, text);
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -231,7 +232,7 @@ class DavClient {
|
||||||
await res.drain<void>();
|
await res.drain<void>();
|
||||||
if (res.statusCode == 201 || res.statusCode == 200) return;
|
if (res.statusCode == 201 || res.statusCode == 200) return;
|
||||||
if (res.statusCode == 405 && (await stat(rel))?.isDir == true) return; // 이미 있음
|
if (res.statusCode == 405 && (await stat(rel))?.isDir == true) return; // 이미 있음
|
||||||
_fail('폴더 만들기', res);
|
_fail(tr('폴더 만들기'), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 위 폴더까지 차례로 만든다
|
/// 위 폴더까지 차례로 만든다
|
||||||
|
|
@ -249,7 +250,7 @@ class DavClient {
|
||||||
final res = await (await _open('DELETE', uriOf(rel, dir: st?.isDir ?? false))).close();
|
final res = await (await _open('DELETE', uriOf(rel, dir: st?.isDir ?? false))).close();
|
||||||
await res.drain<void>();
|
await res.drain<void>();
|
||||||
if (res.statusCode == 404) return;
|
if (res.statusCode == 404) return;
|
||||||
if (res.statusCode >= 300) _fail('지우기', res);
|
if (res.statusCode >= 300) _fail(tr('지우기'), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _moveOrCopy(String method, String from, String to, {bool overwrite = false}) async {
|
Future<void> _moveOrCopy(String method, String from, String to, {bool overwrite = false}) async {
|
||||||
|
|
@ -261,7 +262,7 @@ class DavClient {
|
||||||
if (st?.isDir ?? false) req.headers.set('Depth', 'infinity');
|
if (st?.isDir ?? false) req.headers.set('Depth', 'infinity');
|
||||||
final res = await req.close();
|
final res = await req.close();
|
||||||
await res.drain<void>();
|
await res.drain<void>();
|
||||||
if (res.statusCode >= 300) _fail(method == 'MOVE' ? '이동' : '복사', res);
|
if (res.statusCode >= 300) _fail(method == 'MOVE' ? tr('이동') : tr('복사'), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> move(String from, String to, {bool overwrite = false}) => _moveOrCopy('MOVE', from, to, overwrite: overwrite);
|
Future<void> move(String from, String to, {bool overwrite = false}) => _moveOrCopy('MOVE', from, to, overwrite: overwrite);
|
||||||
|
|
@ -272,7 +273,7 @@ class DavClient {
|
||||||
final res = await (await _open('GET', uriOf(rel))).close();
|
final res = await (await _open('GET', uriOf(rel))).close();
|
||||||
if (res.statusCode != 200) {
|
if (res.statusCode != 200) {
|
||||||
await res.drain<void>();
|
await res.drain<void>();
|
||||||
_fail('받기', res);
|
_fail(tr('받기'), res);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
@ -284,7 +285,7 @@ class DavClient {
|
||||||
await req.addStream(data);
|
await req.addStream(data);
|
||||||
final res = await req.close();
|
final res = await req.close();
|
||||||
await res.drain<void>();
|
await res.drain<void>();
|
||||||
if (res.statusCode >= 300) _fail('올리기', res);
|
if (res.statusCode >= 300) _fail(tr('올리기'), res);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 남은 용량 · 쓴 용량 (바이트, 서버가 알려 주지 않으면 null)
|
/// 남은 용량 · 쓴 용량 (바이트, 서버가 알려 주지 않으면 null)
|
||||||
|
|
@ -338,7 +339,7 @@ class DavRegistry {
|
||||||
|
|
||||||
static DavClient client(String id) {
|
static DavClient client(String id) {
|
||||||
final s = _servers[id];
|
final s = _servers[id];
|
||||||
if (s == null) throw DavException('WebDAV 서버 설정이 없습니다 ($id)');
|
if (s == null) throw DavException(trf('WebDAV 서버 설정이 없습니다 ({0})', [id]));
|
||||||
return _clients.putIfAbsent(id, () => DavClient(s));
|
return _clients.putIfAbsent(id, () => DavClient(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'package:path/path.dart' as p;
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
|
|
||||||
import '../../core/sync_tools.dart';
|
import '../../core/sync_tools.dart';
|
||||||
|
import '../../l10n/tr.dart';
|
||||||
|
|
||||||
/// Windows 용 rsync: 처음 쓸 때 MSYS2 공식 저장소에서 패키지를 받아 (SHA256 고정 검증)
|
/// Windows 용 rsync: 처음 쓸 때 MSYS2 공식 저장소에서 패키지를 받아 (SHA256 고정 검증)
|
||||||
/// 설정 폴더의 rsync\ 에 rsync.exe 와 필요한 DLL 만 풀어 둔다 (앱 업데이트로 지워지지 않게).
|
/// 설정 폴더의 rsync\ 에 rsync.exe 와 필요한 DLL 만 풀어 둔다 (앱 업데이트로 지워지지 않게).
|
||||||
|
|
@ -34,10 +35,10 @@ class RsyncInstaller {
|
||||||
final f = File(p.join(work.path, name));
|
final f = File(p.join(work.path, name));
|
||||||
final req = await http.getUrl(Uri.parse('$msys2Repo$name'));
|
final req = await http.getUrl(Uri.parse('$msys2Repo$name'));
|
||||||
final res = await req.close();
|
final res = await req.close();
|
||||||
if (res.statusCode != 200) throw HttpException('$name 을(를) 받지 못했습니다 (${res.statusCode})');
|
if (res.statusCode != 200) throw HttpException(trf('{0} 을(를) 받지 못했습니다 ({1})', [name, res.statusCode]));
|
||||||
await res.pipe(f.openWrite());
|
await res.pipe(f.openWrite());
|
||||||
final got = (await sha256.bind(f.openRead()).first).toString();
|
final got = (await sha256.bind(f.openRead()).first).toString();
|
||||||
if (got != sha) throw StateError('$name 의 SHA256 이 다릅니다 (손상되었거나 다른 파일). 설치를 멈췄습니다.');
|
if (got != sha) throw StateError(trf('{0} 의 SHA256 이 다릅니다 (손상되었거나 다른 파일). 설치를 멈췄습니다.', [name]));
|
||||||
final t = await Process.run('tar', ['-xf', f.path, '-C', work.path, 'usr/bin']);
|
final t = await Process.run('tar', ['-xf', f.path, '-C', work.path, 'usr/bin']);
|
||||||
if (t.exitCode != 0) throw ProcessException('tar', [f.path], '${t.stderr}', t.exitCode);
|
if (t.exitCode != 0) throw ProcessException('tar', [f.path], '${t.stderr}', t.exitCode);
|
||||||
}
|
}
|
||||||
|
|
@ -45,7 +46,7 @@ class RsyncInstaller {
|
||||||
await Directory(target).create(recursive: true);
|
await Directory(target).create(recursive: true);
|
||||||
for (final n in msys2RsyncFiles) {
|
for (final n in msys2RsyncFiles) {
|
||||||
final src = File(p.join(bin.path, n));
|
final src = File(p.join(bin.path, n));
|
||||||
if (!await src.exists()) throw StateError('패키지에 $n 이 없습니다');
|
if (!await src.exists()) throw StateError(trf('패키지에 {0} 이 없습니다', [n]));
|
||||||
await src.copy(p.join(target, n));
|
await src.copy(p.join(target, n));
|
||||||
}
|
}
|
||||||
final exe = p.join(target, 'rsync.exe');
|
final exe = p.join(target, 'rsync.exe');
|
||||||
|
|
|
||||||
|
|
@ -128,15 +128,8 @@ Future<void> _setDownloaded(BuildContext context, AppComponent x, bool on) async
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
// 단계 글 ("받는 중: 파일") 의 앞부분만 번역
|
// 단계 글 ("받는 중: 파일") 은 ComponentStore 가 화면 언어로 만들어 보낸다 (59)
|
||||||
String trStep(String s) {
|
await store.install(x.id, onProgress: (s, d) => step.value = (s, d));
|
||||||
for (final k in ['받는 중', '푸는 중', '확장 설치']) {
|
|
||||||
if (s.startsWith('$k:')) return '${tr(k)}:${s.substring(k.length + 1)}';
|
|
||||||
}
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
await store.install(x.id, onProgress: (s, d) => step.value = (trStep(s), d));
|
|
||||||
done = true;
|
done = true;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error = e;
|
error = e;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ if (isLockedError(e)) {
|
||||||
return (tr('마스터 비밀번호가 필요합니다'), tr('이 서버의 저장된 비밀번호를 쓰려면 마스터 비밀번호를 넣으세요.'));
|
return (tr('마스터 비밀번호가 필요합니다'), tr('이 서버의 저장된 비밀번호를 쓰려면 마스터 비밀번호를 넣으세요.'));
|
||||||
}
|
}
|
||||||
final s = e.toLowerCase();
|
final s = e.toLowerCase();
|
||||||
|
// 59: 오류 글은 화면 언어로 바뀌어 온다 - 한국어 글과 바뀐 글 둘 다 본다
|
||||||
|
bool has(String ko) => s.contains(ko.toLowerCase()) || s.contains(tr(ko).toLowerCase());
|
||||||
if (dav && (s.contains('socketexception') || s.contains('connection refused') || s.contains('failed host lookup') ||
|
if (dav && (s.contains('socketexception') || s.contains('connection refused') || s.contains('failed host lookup') ||
|
||||||
s.contains('network is unreachable') || s.contains('no route') || s.contains('timed out') ||
|
s.contains('network is unreachable') || s.contains('no route') || s.contains('timed out') ||
|
||||||
s.contains('timeoutexception') || s.contains('connection reset') || s.contains('connection closed'))) {
|
s.contains('timeoutexception') || s.contains('connection reset') || s.contains('connection closed'))) {
|
||||||
|
|
@ -33,7 +35,7 @@ if (isLockedError(e)) {
|
||||||
tr('서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.'),
|
tr('서버와 같은 네트워크에 있거나 VPN (예: Tailscale) 이 켜져 있어야 합니다. 켠 뒤 [다시 시도] 를 누르세요.'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (s.contains(' 401') || s.contains('status: 401') || s.contains('아이디 · 비밀번호')) {
|
if (s.contains(' 401') || s.contains('status: 401') || has('아이디 · 비밀번호를 확인하세요')) {
|
||||||
// 54: 비밀번호가 틀린 것이 아니라 저장된 것이 없다 (예전 판 설치 · 앱 다시 설치 등)
|
// 54: 비밀번호가 틀린 것이 아니라 저장된 것이 없다 (예전 판 설치 · 앱 다시 설치 등)
|
||||||
if (noPassword) {
|
if (noPassword) {
|
||||||
return (
|
return (
|
||||||
|
|
@ -49,8 +51,8 @@ if (isLockedError(e)) {
|
||||||
tr('집 NAS 처럼 자체 서명 인증서면 [서버 설정 고치기] 에서 "인증서 확인 안 함" 을 켜세요.'),
|
tr('집 NAS 처럼 자체 서명 인증서면 [서버 설정 고치기] 에서 "인증서 확인 안 함" 을 켜세요.'),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (s.contains(' 403') || s.contains('권한 없음')) return (tr('이 폴더를 볼 권한이 없습니다'), tr('서버에서 이 계정의 권한을 확인하세요.'));
|
if (s.contains(' 403') || has('권한 없음')) return (tr('이 폴더를 볼 권한이 없습니다'), tr('서버에서 이 계정의 권한을 확인하세요.'));
|
||||||
if (s.contains(' 404') || s.contains('없는 경로')) return (tr('폴더가 없습니다'), tr('다른 곳에서 지웠거나 옮겼을 수 있습니다. 위 폴더로 가 보세요.'));
|
if (s.contains(' 404') || has('없는 경로')) return (tr('폴더가 없습니다'), tr('다른 곳에서 지웠거나 옮겼을 수 있습니다. 위 폴더로 가 보세요.'));
|
||||||
if (s.contains('permission denied') || s.contains('pathaccessexception') || s.contains('errno = 13')) {
|
if (s.contains('permission denied') || s.contains('pathaccessexception') || s.contains('errno = 13')) {
|
||||||
return (
|
return (
|
||||||
tr('이 폴더를 읽을 권한이 없습니다'),
|
tr('이 폴더를 읽을 권한이 없습니다'),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,9 @@
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
import 'package:jj_mkvmaker/app/i18n_controller.dart';
|
||||||
|
import 'package:jj_mkvmaker/core/webdav.dart';
|
||||||
|
import 'package:jj_mkvmaker/l10n/tr.dart';
|
||||||
import 'package:jj_mkvmaker/ui/file_error.dart';
|
import 'package:jj_mkvmaker/ui/file_error.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
|
@ -28,4 +33,31 @@ void main() {
|
||||||
expect(title, '이 폴더는 Android 가 막아 볼 수 없습니다');
|
expect(title, '이 폴더는 Android 가 막아 볼 수 없습니다');
|
||||||
expect(body, contains('내보내기'));
|
expect(body, contains('내보내기'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('59: WebDAV 오류 글이 화면 언어로 오고, 바뀐 글로도 오류 종류를 가른다 (ja)', () async {
|
||||||
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
// 시험 바인딩은 HttpClient 를 늘 400 을 돌려주는 가짜로 바꾼다 - 이 시험은 진짜 로컬 서버에 닿아야 한다
|
||||||
|
final saved = HttpOverrides.current;
|
||||||
|
HttpOverrides.global = null;
|
||||||
|
addTearDown(() => HttpOverrides.global = saved);
|
||||||
|
await i18n.apply('ja', save: false);
|
||||||
|
addTearDown(() => i18n.apply('ko', save: false));
|
||||||
|
for (final (status, title) in [(401, '아이디 또는 비밀번호가 맞지 않습니다'), (403, '이 폴더를 볼 권한이 없습니다'), (404, '폴더가 없습니다')]) {
|
||||||
|
final srv = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
||||||
|
srv.listen((r) async {
|
||||||
|
await r.drain<void>(); // 본문을 다 읽고 답한다 (실제 서버처럼)
|
||||||
|
if (status == 401) r.response.headers.set(HttpHeaders.wwwAuthenticateHeader, 'Basic realm="t"');
|
||||||
|
r.response.statusCode = status;
|
||||||
|
await r.response.close();
|
||||||
|
});
|
||||||
|
final c = DavClient(DavServer(id: 'e', name: 'e', url: 'http://127.0.0.1:${srv.port}/dav', user: 'u', password: 'p'));
|
||||||
|
final e = await c.list('/x').then<Object?>((_) => null, onError: (Object e) => e);
|
||||||
|
c.close();
|
||||||
|
await srv.close(force: true);
|
||||||
|
expect(e, isA<DavException>(), reason: '$status');
|
||||||
|
final msg = '$e';
|
||||||
|
expect(RegExp('[가-힣]').hasMatch(msg), isFalse, reason: '$status: 한국어가 남음 - $msg');
|
||||||
|
expect(explainFileError(msg, dav: true).$1, tr(title), reason: '$status: $msg');
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue