Merge commit '53a7418' into next

review_fix
RyuJongJin 2026-10-18 04:11:01 +09:00
commit 6b6c23dc49
14 changed files with 168 additions and 13 deletions

View File

@ -644,6 +644,7 @@
"가져온 즐겨찾기 ({0})": "Imported bookmarks ({0})", "가져온 즐겨찾기 ({0})": "Imported bookmarks ({0})",
"가져올 즐겨찾기가 없습니다.": "No bookmarks to import.", "가져올 즐겨찾기가 없습니다.": "No bookmarks to import.",
"간격": "Step", "간격": "Step",
"갈 곳: {0}": "To: {0}",
"감지한 언어: {0} (자동 감지)": "Detected language: {0} (auto-detect)", "감지한 언어: {0} (자동 감지)": "Detected language: {0} (auto-detect)",
"감지한 언어: {0} - 틀렸으면 다른 언어로 다시 만드세요": "Detected language: {0} - if it is wrong, make them again with another language", "감지한 언어: {0} - 틀렸으면 다른 언어로 다시 만드세요": "Detected language: {0} - if it is wrong, make them again with another language",
"감지한 원어가 만들 언어와 다를 때만 내려받기 {0}": "Downloaded only if the detected language differs from the subtitle language {0}", "감지한 원어가 만들 언어와 다를 때만 내려받기 {0}": "Downloaded only if the detected language differs from the subtitle language {0}",
@ -742,6 +743,7 @@
"공용 폴더에 받은 파일 (동영상 · 그림 등)": "Files downloaded to shared folders (videos, images, etc.)", "공용 폴더에 받은 파일 (동영상 · 그림 등)": "Files downloaded to shared folders (videos, images, etc.)",
"공유": "Share", "공유": "Share",
"공유 (다른 앱으로 보내기)": "Share (send to another app)", "공유 (다른 앱으로 보내기)": "Share (send to another app)",
"공유 안의 폴더 · 비우면 공유의 맨 위": "A folder inside the share · empty = top of the share",
"공유 이름": "Share name", "공유 이름": "Share name",
"공유 중": "Sharing", "공유 중": "Sharing",
"공유 창을 열 수 없습니다.": "Can't open the share sheet.", "공유 창을 열 수 없습니다.": "Can't open the share sheet.",
@ -857,6 +859,7 @@
"나중에": "Later", "나중에": "Later",
"날짜": "Date", "날짜": "Date",
"날짜: 바뀐 때": "Date: modified", "날짜: 바뀐 때": "Date: modified",
"날짜: 찍은 때": "Date: taken",
"날짜: 찍은 때 (사진, 없으면 바뀐 때)": "Date: taken (photos; otherwise modified)", "날짜: 찍은 때 (사진, 없으면 바뀐 때)": "Date: taken (photos; otherwise modified)",
"남는 것": "What stays", "남는 것": "What stays",
"남은 {0}장": "{0} left", "남은 {0}장": "{0} left",
@ -1039,6 +1042,7 @@
"덮어쓴 파일은 되돌릴 수 없습니다.": "Overwritten files can't be restored.", "덮어쓴 파일은 되돌릴 수 없습니다.": "Overwritten files can't be restored.",
"덮어씁니다": "overwrites it", "덮어씁니다": "overwrites it",
"덴마크어": "Danish", "덴마크어": "Danish",
"도메인 · 작업 그룹": "Domain / workgroup",
"도메인 · 작업 그룹 (보통 비움)": "Domain / workgroup (usually empty)", "도메인 · 작업 그룹 (보통 비움)": "Domain / workgroup (usually empty)",
"독일어": "German", "독일어": "German",
"돌아가기": "Go back", "돌아가기": "Go back",
@ -1307,6 +1311,7 @@
"받은 AI 모델 ({0}) 을 Download/JJ_MKVMaker 에 복사해 두었다가 다시 설치한 뒤 되살리기 (잠시 {0} 더 필요)": "Copy downloaded AI models ({0}) to Download/JJ_MKVMaker and restore them after reinstalling (needs {0} more space for a while)", "받은 AI 모델 ({0}) 을 Download/JJ_MKVMaker 에 복사해 두었다가 다시 설치한 뒤 되살리기 (잠시 {0} 더 필요)": "Copy downloaded AI models ({0}) to Download/JJ_MKVMaker and restore them after reinstalling (needs {0} more space for a while)",
"받은 AI 모델 (그림 · 자막) - 다시 받아야 합니다 (약 {0})": "Downloaded AI models (images · subtitles) - must be downloaded again (about {0})", "받은 AI 모델 (그림 · 자막) - 다시 받아야 합니다 (약 {0})": "Downloaded AI models (images · subtitles) - must be downloaded again (about {0})",
"받은 AI 자막 모델": "Downloaded AI subtitle models", "받은 AI 자막 모델": "Downloaded AI subtitle models",
"받은 곳에서 알려 준 해시를 붙여넣으세요": "Paste the hash published by the source",
"받은 동영상을 편집 목록에 추가: {0}": "Added the received video to the edit list: {0}", "받은 동영상을 편집 목록에 추가: {0}": "Added the received video to the edit list: {0}",
"받은 업데이트 · 필수 프로그램 · Chrome 엔진을 설치하고 남은 임시 파일": "Temporary files left from installing updates · required programs · the Chrome engine", "받은 업데이트 · 필수 프로그램 · Chrome 엔진을 설치하고 남은 임시 파일": "Temporary files left from installing updates · required programs · the Chrome engine",
"받은 자막을 한국어로 번역해 함께 추가 (한국어 자막이 없을 때)": "Translate received subtitles to Korean and add them too (when there are no Korean subtitles)", "받은 자막을 한국어로 번역해 함께 추가 (한국어 자막이 없을 때)": "Translate received subtitles to Korean and add them too (when there are no Korean subtitles)",
@ -1374,6 +1379,7 @@
"보조 DNS (비워 둘 수 있음)": "Secondary DNS (may be empty)", "보조 DNS (비워 둘 수 있음)": "Secondary DNS (may be empty)",
"보통": "Normal", "보통": "Normal",
"보통 (0.25, 기본)": "Normal (0.25, default)", "보통 (0.25, 기본)": "Normal (0.25, default)",
"보통 비워 둡니다": "Usually left empty",
"보통: {0}": "Normal: {0}", "보통: {0}": "Normal: {0}",
"복사": "Copy", "복사": "Copy",
"복사 (붙여넣기로)": "Copy (to paste)", "복사 (붙여넣기로)": "Copy (to paste)",
@ -1424,6 +1430,7 @@
"비공개 · 회원 전용 영상입니다.": "This is a private · members-only video.", "비공개 · 회원 전용 영상입니다.": "This is a private · members-only video.",
"비교하지 못했습니다: {0}": "Couldn't compare: {0}", "비교하지 못했습니다: {0}": "Couldn't compare: {0}",
"비교할 값 붙여넣기 (받은 곳의 해시)": "Paste a value to compare (hash from the source)", "비교할 값 붙여넣기 (받은 곳의 해시)": "Paste a value to compare (hash from the source)",
"비교할 해시": "Hash to compare",
"비밀번호": "Password", "비밀번호": "Password",
"비밀번호 (개인 키만 쓰면 비움)": "Password (leave empty if using only a private key)", "비밀번호 (개인 키만 쓰면 비움)": "Password (leave empty if using only a private key)",
"비밀번호 (선택)": "Password (optional)", "비밀번호 (선택)": "Password (optional)",
@ -1452,7 +1459,9 @@
"비어 있습니다": "Empty", "비어 있습니다": "Empty",
"비어 있음": "Empty", "비어 있음": "Empty",
"비우기": "Empty", "비우기": "Empty",
"비우면 로그인한 곳 · 예: /volume1/video · 탭의 맨 위가 됩니다": "Empty = where you log in · e.g. /volume1/video · becomes the top of the tab",
"비우면 지움": "Empty = remove", "비우면 지움": "Empty = remove",
"비우면 홈 폴더 · 예: /volume1/video · 탭의 맨 위가 됩니다": "Empty = home folder · e.g. /volume1/video · becomes the top of the tab",
"빈 이름": "Empty name", "빈 이름": "Empty name",
"빈 폴더 {0}개 지움": "Deleted {0} empty folders", "빈 폴더 {0}개 지움": "Deleted {0} empty folders",
"빈 폴더 그대로": "Leave empty folders", "빈 폴더 그대로": "Leave empty folders",
@ -1635,6 +1644,7 @@
"시작 · 웹 브라우저": "Startup · web browser", "시작 · 웹 브라우저": "Startup · web browser",
"시작 메뉴에 등록": "Add to Start menu", "시작 메뉴에 등록": "Add to Start menu",
"시작 안 함 (모니터링에서 시작)": "Don't start (start from Monitor)", "시작 안 함 (모니터링에서 시작)": "Don't start (start from Monitor)",
"시작 폴더": "Start folder",
"시작 폴더 (공유 안, 비우면 맨 위)": "Start folder (inside the share, top if empty)", "시작 폴더 (공유 안, 비우면 맨 위)": "Start folder (inside the share, top if empty)",
"시작 폴더 (비우면 로그인한 곳)": "Start folder (empty = where you log in)", "시작 폴더 (비우면 로그인한 곳)": "Start folder (empty = where you log in)",
"시작 폴더 (비우면 홈 폴더)": "Start folder (home folder if empty)", "시작 폴더 (비우면 홈 폴더)": "Start folder (home folder if empty)",
@ -2555,6 +2565,7 @@
"탐색기에서 동영상을 열 때": "When opening a video from Explorer", "탐색기에서 동영상을 열 때": "When opening a video from Explorer",
"탐색기에서 연 동영상을 재생할 창": "Window to play videos opened from Explorer", "탐색기에서 연 동영상을 재생할 창": "Window to play videos opened from Explorer",
"태국어": "Thai", "태국어": "Thai",
"탭에 보입니다 · 비우면 주소": "Shown on the tab · address if empty",
"터키어": "Turkish", "터키어": "Turkish",
"토": "Sat", "토": "Sat",
"토렌트 · 마그넷 다운로드": "Torrent · magnet download", "토렌트 · 마그넷 다운로드": "Torrent · magnet download",

View File

@ -644,6 +644,7 @@
"가져온 즐겨찾기 ({0})": "取り込んだブックマーク({0})", "가져온 즐겨찾기 ({0})": "取り込んだブックマーク({0})",
"가져올 즐겨찾기가 없습니다.": "取り込むブックマークがありません。", "가져올 즐겨찾기가 없습니다.": "取り込むブックマークがありません。",
"간격": "間隔", "간격": "間隔",
"갈 곳: {0}": "移動先: {0}",
"감지한 언어: {0} (자동 감지)": "検出した言語: {0} (自動検出)", "감지한 언어: {0} (자동 감지)": "検出した言語: {0} (自動検出)",
"감지한 언어: {0} - 틀렸으면 다른 언어로 다시 만드세요": "検出した言語: {0} - 違っていれば別の言語で作り直してください", "감지한 언어: {0} - 틀렸으면 다른 언어로 다시 만드세요": "検出した言語: {0} - 違っていれば別の言語で作り直してください",
"감지한 원어가 만들 언어와 다를 때만 내려받기 {0}": "検出した言語が作成する言語と異なる場合のみダウンロード {0}", "감지한 원어가 만들 언어와 다를 때만 내려받기 {0}": "検出した言語が作成する言語と異なる場合のみダウンロード {0}",
@ -742,6 +743,7 @@
"공용 폴더에 받은 파일 (동영상 · 그림 등)": "共有フォルダーにダウンロードしたファイル (動画・画像など)", "공용 폴더에 받은 파일 (동영상 · 그림 등)": "共有フォルダーにダウンロードしたファイル (動画・画像など)",
"공유": "共有", "공유": "共有",
"공유 (다른 앱으로 보내기)": "共有 (他のアプリに送る)", "공유 (다른 앱으로 보내기)": "共有 (他のアプリに送る)",
"공유 안의 폴더 · 비우면 공유의 맨 위": "共有内のフォルダー · 空なら共有の一番上",
"공유 이름": "共有名", "공유 이름": "共有名",
"공유 중": "共有中", "공유 중": "共有中",
"공유 창을 열 수 없습니다.": "共有画面を開けません。", "공유 창을 열 수 없습니다.": "共有画面を開けません。",
@ -857,6 +859,7 @@
"나중에": "後で", "나중에": "後で",
"날짜": "日付", "날짜": "日付",
"날짜: 바뀐 때": "日付: 更新日時", "날짜: 바뀐 때": "日付: 更新日時",
"날짜: 찍은 때": "日付: 撮影日時",
"날짜: 찍은 때 (사진, 없으면 바뀐 때)": "日付: 撮影日時 (写真、なければ更新日時)", "날짜: 찍은 때 (사진, 없으면 바뀐 때)": "日付: 撮影日時 (写真、なければ更新日時)",
"남는 것": "残るもの", "남는 것": "残るもの",
"남은 {0}장": "残り {0} 枚", "남은 {0}장": "残り {0} 枚",
@ -1039,6 +1042,7 @@
"덮어쓴 파일은 되돌릴 수 없습니다.": "上書きしたファイルは元に戻せません。", "덮어쓴 파일은 되돌릴 수 없습니다.": "上書きしたファイルは元に戻せません。",
"덮어씁니다": "上書きします", "덮어씁니다": "上書きします",
"덴마크어": "デンマーク語", "덴마크어": "デンマーク語",
"도메인 · 작업 그룹": "ドメイン・ワークグループ",
"도메인 · 작업 그룹 (보통 비움)": "ドメイン・ワークグループ (通常は空欄)", "도메인 · 작업 그룹 (보통 비움)": "ドメイン・ワークグループ (通常は空欄)",
"독일어": "ドイツ語", "독일어": "ドイツ語",
"돌아가기": "戻る", "돌아가기": "戻る",
@ -1307,6 +1311,7 @@
"받은 AI 모델 ({0}) 을 Download/JJ_MKVMaker 에 복사해 두었다가 다시 설치한 뒤 되살리기 (잠시 {0} 더 필요)": "ダウンロードした AI モデル ({0}) を Download/JJ_MKVMaker にコピーし、再インストール後に復元する (一時的に {0} 余分に必要)", "받은 AI 모델 ({0}) 을 Download/JJ_MKVMaker 에 복사해 두었다가 다시 설치한 뒤 되살리기 (잠시 {0} 더 필요)": "ダウンロードした AI モデル ({0}) を Download/JJ_MKVMaker にコピーし、再インストール後に復元する (一時的に {0} 余分に必要)",
"받은 AI 모델 (그림 · 자막) - 다시 받아야 합니다 (약 {0})": "ダウンロードした AI モデル (画像・字幕) - 再ダウンロードが必要です (約 {0})", "받은 AI 모델 (그림 · 자막) - 다시 받아야 합니다 (약 {0})": "ダウンロードした AI モデル (画像・字幕) - 再ダウンロードが必要です (約 {0})",
"받은 AI 자막 모델": "ダウンロード済みの AI 字幕モデル", "받은 AI 자막 모델": "ダウンロード済みの AI 字幕モデル",
"받은 곳에서 알려 준 해시를 붙여넣으세요": "入手元が示したハッシュを貼り付けてください",
"받은 동영상을 편집 목록에 추가: {0}": "受け取った動画を編集リストに追加: {0}", "받은 동영상을 편집 목록에 추가: {0}": "受け取った動画を編集リストに追加: {0}",
"받은 업데이트 · 필수 프로그램 · Chrome 엔진을 설치하고 남은 임시 파일": "更新・必須プログラム・Chrome エンジンのインストールで残った一時ファイル", "받은 업데이트 · 필수 프로그램 · Chrome 엔진을 설치하고 남은 임시 파일": "更新・必須プログラム・Chrome エンジンのインストールで残った一時ファイル",
"받은 자막을 한국어로 번역해 함께 추가 (한국어 자막이 없을 때)": "受け取った字幕を韓国語に翻訳して一緒に追加(韓国語字幕がないとき)", "받은 자막을 한국어로 번역해 함께 추가 (한국어 자막이 없을 때)": "受け取った字幕を韓国語に翻訳して一緒に追加(韓国語字幕がないとき)",
@ -1374,6 +1379,7 @@
"보조 DNS (비워 둘 수 있음)": "代替 DNS (空欄可)", "보조 DNS (비워 둘 수 있음)": "代替 DNS (空欄可)",
"보통": "普通", "보통": "普通",
"보통 (0.25, 기본)": "普通 (0.25、既定)", "보통 (0.25, 기본)": "普通 (0.25、既定)",
"보통 비워 둡니다": "通常は空欄",
"보통: {0}": "普通: {0}", "보통: {0}": "普通: {0}",
"복사": "コピー", "복사": "コピー",
"복사 (붙여넣기로)": "コピー (貼り付け用)", "복사 (붙여넣기로)": "コピー (貼り付け用)",
@ -1424,6 +1430,7 @@
"비공개 · 회원 전용 영상입니다.": "非公開・メンバー限定の動画です。", "비공개 · 회원 전용 영상입니다.": "非公開・メンバー限定の動画です。",
"비교하지 못했습니다: {0}": "比較できませんでした: {0}", "비교하지 못했습니다: {0}": "比較できませんでした: {0}",
"비교할 값 붙여넣기 (받은 곳의 해시)": "比較する値を貼り付け (入手元のハッシュ)", "비교할 값 붙여넣기 (받은 곳의 해시)": "比較する値を貼り付け (入手元のハッシュ)",
"비교할 해시": "比較するハッシュ",
"비밀번호": "パスワード", "비밀번호": "パスワード",
"비밀번호 (개인 키만 쓰면 비움)": "パスワード (秘密鍵だけを使う場合は空欄)", "비밀번호 (개인 키만 쓰면 비움)": "パスワード (秘密鍵だけを使う場合は空欄)",
"비밀번호 (선택)": "パスワード(任意)", "비밀번호 (선택)": "パスワード(任意)",
@ -1452,7 +1459,9 @@
"비어 있습니다": "空です", "비어 있습니다": "空です",
"비어 있음": "空", "비어 있음": "空",
"비우기": "空にする", "비우기": "空にする",
"비우면 로그인한 곳 · 예: /volume1/video · 탭의 맨 위가 됩니다": "空ならログインした場所 · 例: /volume1/video · タブの一番上になります",
"비우면 지움": "空なら削除", "비우면 지움": "空なら削除",
"비우면 홈 폴더 · 예: /volume1/video · 탭의 맨 위가 됩니다": "空ならホームフォルダー · 例: /volume1/video · タブの一番上になります",
"빈 이름": "空の名前", "빈 이름": "空の名前",
"빈 폴더 {0}개 지움": "空フォルダー {0} 個を削除", "빈 폴더 {0}개 지움": "空フォルダー {0} 個を削除",
"빈 폴더 그대로": "空フォルダーはそのまま", "빈 폴더 그대로": "空フォルダーはそのまま",
@ -1635,6 +1644,7 @@
"시작 · 웹 브라우저": "起動・ウェブブラウザー", "시작 · 웹 브라우저": "起動・ウェブブラウザー",
"시작 메뉴에 등록": "スタートメニューに登録", "시작 메뉴에 등록": "スタートメニューに登録",
"시작 안 함 (모니터링에서 시작)": "開始しない (モニタリングで開始)", "시작 안 함 (모니터링에서 시작)": "開始しない (モニタリングで開始)",
"시작 폴더": "開始フォルダー",
"시작 폴더 (공유 안, 비우면 맨 위)": "開始フォルダー (共有内、空欄なら最上位)", "시작 폴더 (공유 안, 비우면 맨 위)": "開始フォルダー (共有内、空欄なら最上位)",
"시작 폴더 (비우면 로그인한 곳)": "開始フォルダー (空欄ならログインした場所)", "시작 폴더 (비우면 로그인한 곳)": "開始フォルダー (空欄ならログインした場所)",
"시작 폴더 (비우면 홈 폴더)": "開始フォルダー (空欄ならホームフォルダー)", "시작 폴더 (비우면 홈 폴더)": "開始フォルダー (空欄ならホームフォルダー)",
@ -2555,6 +2565,7 @@
"탐색기에서 동영상을 열 때": "エクスプローラーで動画を開いたとき", "탐색기에서 동영상을 열 때": "エクスプローラーで動画を開いたとき",
"탐색기에서 연 동영상을 재생할 창": "エクスプローラーで開いた動画を再生するウィンドウ", "탐색기에서 연 동영상을 재생할 창": "エクスプローラーで開いた動画を再生するウィンドウ",
"태국어": "タイ語", "태국어": "タイ語",
"탭에 보입니다 · 비우면 주소": "タブに表示 · 空ならアドレス",
"터키어": "トルコ語", "터키어": "トルコ語",
"토": "土", "토": "土",
"토렌트 · 마그넷 다운로드": "トレント・マグネットのダウンロード", "토렌트 · 마그넷 다운로드": "トレント・マグネットのダウンロード",

View File

@ -644,6 +644,7 @@
"가져온 즐겨찾기 ({0})": "导入的书签({0})", "가져온 즐겨찾기 ({0})": "导入的书签({0})",
"가져올 즐겨찾기가 없습니다.": "没有可导入的书签。", "가져올 즐겨찾기가 없습니다.": "没有可导入的书签。",
"간격": "间隔", "간격": "间隔",
"갈 곳: {0}": "目标: {0}",
"감지한 언어: {0} (자동 감지)": "检测到的语言:{0}(自动检测)", "감지한 언어: {0} (자동 감지)": "检测到的语言:{0}(自动检测)",
"감지한 언어: {0} - 틀렸으면 다른 언어로 다시 만드세요": "检测到的语言:{0} - 如有误,请用其他语言重新生成", "감지한 언어: {0} - 틀렸으면 다른 언어로 다시 만드세요": "检测到的语言:{0} - 如有误,请用其他语言重新生成",
"감지한 원어가 만들 언어와 다를 때만 내려받기 {0}": "仅当检测到的语言与要生成的语言不同时下载 {0}", "감지한 원어가 만들 언어와 다를 때만 내려받기 {0}": "仅当检测到的语言与要生成的语言不同时下载 {0}",
@ -742,6 +743,7 @@
"공용 폴더에 받은 파일 (동영상 · 그림 등)": "下载到公共文件夹的文件 (视频、图片等)", "공용 폴더에 받은 파일 (동영상 · 그림 등)": "下载到公共文件夹的文件 (视频、图片等)",
"공유": "分享", "공유": "分享",
"공유 (다른 앱으로 보내기)": "分享 (发送到其他应用)", "공유 (다른 앱으로 보내기)": "分享 (发送到其他应用)",
"공유 안의 폴더 · 비우면 공유의 맨 위": "共享内的文件夹 · 为空则为共享的最上层",
"공유 이름": "共享名称", "공유 이름": "共享名称",
"공유 중": "共享中", "공유 중": "共享中",
"공유 창을 열 수 없습니다.": "无法打开分享窗口。", "공유 창을 열 수 없습니다.": "无法打开分享窗口。",
@ -857,6 +859,7 @@
"나중에": "以后再说", "나중에": "以后再说",
"날짜": "日期", "날짜": "日期",
"날짜: 바뀐 때": "日期: 修改时间", "날짜: 바뀐 때": "日期: 修改时间",
"날짜: 찍은 때": "日期: 拍摄时间",
"날짜: 찍은 때 (사진, 없으면 바뀐 때)": "日期: 拍摄时间 (照片; 否则为修改时间)", "날짜: 찍은 때 (사진, 없으면 바뀐 때)": "日期: 拍摄时间 (照片; 否则为修改时间)",
"남는 것": "保留的内容", "남는 것": "保留的内容",
"남은 {0}장": "剩余 {0} 张", "남은 {0}장": "剩余 {0} 张",
@ -1039,6 +1042,7 @@
"덮어쓴 파일은 되돌릴 수 없습니다.": "被覆盖的文件无法恢复。", "덮어쓴 파일은 되돌릴 수 없습니다.": "被覆盖的文件无法恢复。",
"덮어씁니다": "覆盖", "덮어씁니다": "覆盖",
"덴마크어": "丹麦语", "덴마크어": "丹麦语",
"도메인 · 작업 그룹": "域 · 工作组",
"도메인 · 작업 그룹 (보통 비움)": "域 · 工作组 (通常留空)", "도메인 · 작업 그룹 (보통 비움)": "域 · 工作组 (通常留空)",
"독일어": "德语", "독일어": "德语",
"돌아가기": "返回", "돌아가기": "返回",
@ -1307,6 +1311,7 @@
"받은 AI 모델 ({0}) 을 Download/JJ_MKVMaker 에 복사해 두었다가 다시 설치한 뒤 되살리기 (잠시 {0} 더 필요)": "将已下载的 AI 模型 ({0}) 复制到 Download/JJ_MKVMaker,重新安装后恢复 (暂时需要额外 {0})", "받은 AI 모델 ({0}) 을 Download/JJ_MKVMaker 에 복사해 두었다가 다시 설치한 뒤 되살리기 (잠시 {0} 더 필요)": "将已下载的 AI 模型 ({0}) 复制到 Download/JJ_MKVMaker,重新安装后恢复 (暂时需要额外 {0})",
"받은 AI 모델 (그림 · 자막) - 다시 받아야 합니다 (약 {0})": "已下载的 AI 模型 (图片 · 字幕) - 需要重新下载 (约 {0})", "받은 AI 모델 (그림 · 자막) - 다시 받아야 합니다 (약 {0})": "已下载的 AI 模型 (图片 · 字幕) - 需要重新下载 (约 {0})",
"받은 AI 자막 모델": "已下载的 AI 字幕模型", "받은 AI 자막 모델": "已下载的 AI 字幕模型",
"받은 곳에서 알려 준 해시를 붙여넣으세요": "粘贴来源提供的哈希",
"받은 동영상을 편집 목록에 추가: {0}": "已将收到的视频加入编辑列表: {0}", "받은 동영상을 편집 목록에 추가: {0}": "已将收到的视频加入编辑列表: {0}",
"받은 업데이트 · 필수 프로그램 · Chrome 엔진을 설치하고 남은 임시 파일": "安装更新 · 必需程序 · Chrome 引擎后残留的临时文件", "받은 업데이트 · 필수 프로그램 · Chrome 엔진을 설치하고 남은 임시 파일": "安装更新 · 必需程序 · Chrome 引擎后残留的临时文件",
"받은 자막을 한국어로 번역해 함께 추가 (한국어 자막이 없을 때)": "将收到的字幕翻译成韩语并一并添加(没有韩语字幕时)", "받은 자막을 한국어로 번역해 함께 추가 (한국어 자막이 없을 때)": "将收到的字幕翻译成韩语并一并添加(没有韩语字幕时)",
@ -1374,6 +1379,7 @@
"보조 DNS (비워 둘 수 있음)": "备用 DNS (可留空)", "보조 DNS (비워 둘 수 있음)": "备用 DNS (可留空)",
"보통": "普通", "보통": "普通",
"보통 (0.25, 기본)": "普通 (0.25,默认)", "보통 (0.25, 기본)": "普通 (0.25,默认)",
"보통 비워 둡니다": "通常留空",
"보통: {0}": "普通:{0}", "보통: {0}": "普通:{0}",
"복사": "复制", "복사": "复制",
"복사 (붙여넣기로)": "复制 (用于粘贴)", "복사 (붙여넣기로)": "复制 (用于粘贴)",
@ -1424,6 +1430,7 @@
"비공개 · 회원 전용 영상입니다.": "这是私享 · 会员专享视频。", "비공개 · 회원 전용 영상입니다.": "这是私享 · 会员专享视频。",
"비교하지 못했습니다: {0}": "无法比较: {0}", "비교하지 못했습니다: {0}": "无法比较: {0}",
"비교할 값 붙여넣기 (받은 곳의 해시)": "粘贴要比较的值 (来源处的哈希)", "비교할 값 붙여넣기 (받은 곳의 해시)": "粘贴要比较的值 (来源处的哈希)",
"비교할 해시": "要比较的哈希",
"비밀번호": "密码", "비밀번호": "密码",
"비밀번호 (개인 키만 쓰면 비움)": "密码 (仅使用私钥时留空)", "비밀번호 (개인 키만 쓰면 비움)": "密码 (仅使用私钥时留空)",
"비밀번호 (선택)": "密码(可选)", "비밀번호 (선택)": "密码(可选)",
@ -1452,7 +1459,9 @@
"비어 있습니다": "空", "비어 있습니다": "空",
"비어 있음": "空", "비어 있음": "空",
"비우기": "清空", "비우기": "清空",
"비우면 로그인한 곳 · 예: /volume1/video · 탭의 맨 위가 됩니다": "为空则为登录位置 · 例: /volume1/video · 成为标签的最上层",
"비우면 지움": "留空则删除", "비우면 지움": "留空则删除",
"비우면 홈 폴더 · 예: /volume1/video · 탭의 맨 위가 됩니다": "为空则为主文件夹 · 例: /volume1/video · 成为标签的最上层",
"빈 이름": "空名称", "빈 이름": "空名称",
"빈 폴더 {0}개 지움": "已删除 {0} 个空文件夹", "빈 폴더 {0}개 지움": "已删除 {0} 个空文件夹",
"빈 폴더 그대로": "保留空文件夹", "빈 폴더 그대로": "保留空文件夹",
@ -1635,6 +1644,7 @@
"시작 · 웹 브라우저": "启动 · 网页浏览器", "시작 · 웹 브라우저": "启动 · 网页浏览器",
"시작 메뉴에 등록": "添加到开始菜单", "시작 메뉴에 등록": "添加到开始菜单",
"시작 안 함 (모니터링에서 시작)": "不开始 (在监控中开始)", "시작 안 함 (모니터링에서 시작)": "不开始 (在监控中开始)",
"시작 폴더": "起始文件夹",
"시작 폴더 (공유 안, 비우면 맨 위)": "起始文件夹 (共享内,留空则为最上层)", "시작 폴더 (공유 안, 비우면 맨 위)": "起始文件夹 (共享内,留空则为最上层)",
"시작 폴더 (비우면 로그인한 곳)": "起始文件夹 (留空则为登录位置)", "시작 폴더 (비우면 로그인한 곳)": "起始文件夹 (留空则为登录位置)",
"시작 폴더 (비우면 홈 폴더)": "起始文件夹 (留空则为主目录)", "시작 폴더 (비우면 홈 폴더)": "起始文件夹 (留空则为主目录)",
@ -2555,6 +2565,7 @@
"탐색기에서 동영상을 열 때": "从资源管理器打开视频时", "탐색기에서 동영상을 열 때": "从资源管理器打开视频时",
"탐색기에서 연 동영상을 재생할 창": "播放从资源管理器打开的视频的窗口", "탐색기에서 연 동영상을 재생할 창": "播放从资源管理器打开的视频的窗口",
"태국어": "泰语", "태국어": "泰语",
"탭에 보입니다 · 비우면 주소": "显示在标签上 · 为空则用地址",
"터키어": "土耳其语", "터키어": "土耳其语",
"토": "六", "토": "六",
"토렌트 · 마그넷 다운로드": "种子 · 磁力链接下载", "토렌트 · 마그넷 다운로드": "种子 · 磁力链接下载",

View File

@ -0,0 +1,79 @@
import 'dart:io';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart';
import 'package:jj_mkvmaker/app/app_controller.dart';
import 'package:jj_mkvmaker/app/i18n_controller.dart';
import 'package:jj_mkvmaker/platform/windows/desktop_storage_service.dart';
import 'package:jj_mkvmaker/platform/windows/process_media_tool.dart';
import 'package:jj_mkvmaker/services/platform_services.dart';
import 'package:jj_mkvmaker/ui/ftp_settings.dart';
import 'package:jj_mkvmaker/ui/sftp_settings.dart';
import 'package:jj_mkvmaker/ui/smb_settings.dart';
import 'package:jj_mkvmaker/ui/theme.dart';
import 'package:jj_mkvmaker/ui/webdav_settings.dart';
import 'package:path/path.dart' as p;
/// 관리자 지시 (10/18): 412 캡처의 잘림 고침 확인 - FTP · SFTP · SMB · WebDAV 서버 추가 창 (칸 이름은 짧게, 설명은 helper).
/// 크기 412 · 960, 언어 ko · en · ja. 실행: flutter test integration_test\windows_trunc_shot_test.dart -d windows
void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
final out = Platform.environment['JJ_SHOT_DIR'] ?? p.join(Directory.systemTemp.path, 'jj_shots_trunc');
for (final lang in ['ko', 'en', 'ja']) {
for (final (w, h) in [(412, 900), (960, 600)]) {
testWidgets('서버 추가 창 $lang ${w}x$h', (t) async {
t.view.physicalSize = Size(w.toDouble(), h.toDouble());
t.view.devicePixelRatio = 1;
addTearDown(t.view.reset);
await t.runAsync(() => i18n.apply(lang, save: false));
addTearDown(() => i18n.apply('ko', save: false));
final c = AppController(PlatformServices(mediaTool: ProcessMediaTool('x', 'y'), storage: DesktopStorageService()));
final navKey = GlobalKey<NavigatorState>();
final shotKey = GlobalKey();
await t.pumpWidget(RepaintBoundary(
key: shotKey,
child: MaterialApp(
theme: buildTheme(), debugShowCheckedModeBanner: false, navigatorKey: navKey, home: const Scaffold(body: SizedBox.expand())),
));
Future<void> settle([int n = 8]) async {
for (var i = 0; i < n; i++) {
await t.runAsync(() => Future<void>.delayed(const Duration(milliseconds: 60)));
await t.pump();
}
}
Future<void> shot(String name) async {
await settle(3);
final b = shotKey.currentContext!.findRenderObject()! as RenderRepaintBoundary;
final img = await t.runAsync(() => b.toImage());
final bytes = await t.runAsync(() => img!.toByteData(format: ui.ImageByteFormat.png));
Directory(out).createSync(recursive: true);
File(p.join(out, 'trunc_${name}_${lang}_$w.png')).writeAsBytesSync(bytes!.buffer.asUint8List());
}
for (final (name, open) in <(String, void Function(BuildContext))>[
('ftp', (ctx) => editFtpServer(ctx, c)),
('sftp', (ctx) => editSftpServer(ctx, c)),
('smb', (ctx) => editSmbServer(ctx, c)),
('webdav', (ctx) => editDavServer(ctx, c)),
]) {
open(navKey.currentContext!);
await settle();
await shot(name);
// 창 아래쪽 (시작 폴더 칸) 도
final scroll = find.descendant(of: find.byType(AlertDialog), matching: find.byType(Scrollable));
if (scroll.evaluate().isNotEmpty) {
await t.drag(scroll.first, const Offset(0, -600));
await settle(4);
await shot('${name}_bottom');
}
navKey.currentState!.popUntil((r) => r.isFirst);
await settle(4);
}
});
}
}
}

View File

@ -202,6 +202,11 @@ class _BatchRenameDialogState extends State<_BatchRenameDialog> {
child: DropdownButton<String>( child: DropdownButton<String>(
isExpanded: true, isExpanded: true,
value: _dateSource, value: _dateSource,
// 412 캡처 (10/18): 고른 뒤 상자에는 짧게 (펼친 목록은 긴 설명 그대로)
selectedItemBuilder: (_) => [
Text(tr('날짜: 찍은 때'), maxLines: 1, overflow: TextOverflow.ellipsis),
Text(tr('날짜: 바뀐 때'), maxLines: 1, overflow: TextOverflow.ellipsis),
],
items: [ items: [
DropdownMenuItem(value: 'photo', child: Text(tr('날짜: 찍은 때 (사진, 없으면 바뀐 때)'), overflow: TextOverflow.ellipsis)), DropdownMenuItem(value: 'photo', child: Text(tr('날짜: 찍은 때 (사진, 없으면 바뀐 때)'), overflow: TextOverflow.ellipsis)),
DropdownMenuItem(value: 'modified', child: Text(tr('날짜: 바뀐 때'), overflow: TextOverflow.ellipsis)), DropdownMenuItem(value: 'modified', child: Text(tr('날짜: 바뀐 때'), overflow: TextOverflow.ellipsis)),

View File

@ -2298,11 +2298,17 @@ class _ExplorerPageState extends State<ExplorerPage> {
child: Row(children: [ child: Row(children: [
const Icon(Icons.arrow_forward, size: 18, color: JjColors.accent), const Icon(Icons.arrow_forward, size: 18, color: JjColors.accent),
const SizedBox(width: 6), const SizedBox(width: 6),
// 412 캡처 (10/18): "갈 곳:" 은 늘 보이고, 폴더 이름이 길면 가운데를 줄인다 (전체 경로는 길게 눌러 · 마우스를 올려)
Expanded( Expanded(
child: Tooltip( child: Tooltip(
message: _displayPath(t.current), message: _displayPath(t.current),
child: Text(trf('복사 · 이동 갈 곳: {0}', [_folderName(t.current)]), triggerMode: TooltipTriggerMode.longPress,
maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 12.5)), child: LayoutBuilder(builder: (context, box) {
const style = TextStyle(fontSize: 12.5);
final label = trf('갈 곳: {0}', ['']);
final room = box.maxWidth - textWidth(context, label, style);
return Text('$label${middleEllipsis(context, _folderName(t.current), style, room)}', maxLines: 1, overflow: TextOverflow.clip, style: style);
}),
), ),
), ),
TextButton( TextButton(

View File

@ -89,7 +89,7 @@ Future<void> showFileHash(BuildContext context, String path) async {
const SizedBox(height: 10), const SizedBox(height: 10),
TextField( TextField(
controller: compare, controller: compare,
decoration: InputDecoration(labelText: tr('비교할 값 붙여넣기 (받은 곳의 해시)'), isDense: true), decoration: InputDecoration(labelText: tr('비교할 해시'), helperText: tr('받은 곳에서 알려 준 해시를 붙여넣으세요'), helperMaxLines: 3, isDense: true),
onChanged: (_) => set(() {}), onChanged: (_) => set(() {}),
), ),
if (match != null) if (match != null)

View File

@ -201,7 +201,7 @@ Future<FtpServer?> editFtpServer(BuildContext context, AppController c, {FtpServ
content: SizedBox( content: SizedBox(
width: 520, width: 520,
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
TextField(controller: name, decoration: InputDecoration(labelText: tr('이름 (탭에 보임, 비우면 주소)'))), TextField(controller: name, decoration: InputDecoration(labelText: tr('이름'), helperText: tr('탭에 보입니다 · 비우면 주소'), helperMaxLines: 3)),
Row(children: [ Row(children: [
Expanded( Expanded(
child: TextField( child: TextField(
@ -265,7 +265,7 @@ Future<FtpServer?> editFtpServer(BuildContext context, AppController c, {FtpServ
), ),
TextField( TextField(
controller: root, controller: root,
decoration: InputDecoration(labelText: tr('시작 폴더 (비우면 로그인한 곳)'), helperText: tr('예: /volume1/video · 탭의 맨 위가 됩니다'), helperMaxLines: 3), decoration: InputDecoration(labelText: tr('시작 폴더'), helperText: tr('비우면 로그인한 곳 · 예: /volume1/video · 탭의 맨 위가 됩니다'), helperMaxLines: 3),
), ),
if (security != 'none') ...[ if (security != 'none') ...[
const SizedBox(height: 6), const SizedBox(height: 6),

View File

@ -1,5 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/widgets.dart';
import '../core/vfs.dart'; import '../core/vfs.dart';
import '../l10n/tr.dart'; import '../l10n/tr.dart';
@ -25,3 +27,33 @@ String shortPath(String path, {int keep = 3}) {
final parts = friendlyPath(path).split(' › '); final parts = friendlyPath(path).split(' › ');
return parts.length <= keep ? parts.join(' › ') : ['…', ...parts.sublist(parts.length - keep)].join(' › '); return parts.length <= keep ? parts.join(' › ') : ['…', ...parts.sublist(parts.length - keep)].join(' › ');
} }
/// [text] 를 [style] 로 한 줄에 그렸을 때의 폭
double textWidth(BuildContext context, String text, TextStyle style) {
final tp = TextPainter(
text: TextSpan(text: text, style: DefaultTextStyle.of(context).style.merge(style)),
textDirection: Directionality.of(context),
textScaler: MediaQuery.textScalerOf(context),
maxLines: 1)
..layout();
final w = tp.width;
tp.dispose();
return w;
}
/// [text] 가 [maxWidth] 를 넘으면 가운데를 "…" 로 줄인다 (앞 · 끝이 보이게 - 412 캡처 10/18, 갈 곳 막대)
String middleEllipsis(BuildContext context, String text, TextStyle style, double maxWidth) {
if (maxWidth <= 0) return '…';
if (textWidth(context, text, style) <= maxWidth) return text;
var lo = 0, hi = text.length;
String cut(int n) => '${text.substring(0, (n + 1) ~/ 2)}…${text.substring(text.length - n ~/ 2)}';
while (lo < hi) {
final mid = (lo + hi + 1) ~/ 2;
if (textWidth(context, cut(mid), style) <= maxWidth) {
lo = mid;
} else {
hi = mid - 1;
}
}
return lo == 0 ? '…' : cut(lo);
}

View File

@ -248,7 +248,7 @@ Future<SftpServer?> editSftpServer(BuildContext context, AppController c, {SftpS
content: SizedBox( content: SizedBox(
width: 520, width: 520,
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
TextField(controller: name, decoration: InputDecoration(labelText: tr('이름 (탭에 보임, 비우면 주소)'))), TextField(controller: name, decoration: InputDecoration(labelText: tr('이름'), helperText: tr('탭에 보입니다 · 비우면 주소'), helperMaxLines: 3)),
Row(children: [ Row(children: [
Expanded( Expanded(
child: TextField( child: TextField(
@ -302,7 +302,7 @@ Future<SftpServer?> editSftpServer(BuildContext context, AppController c, {SftpS
), ),
TextField( TextField(
controller: root, controller: root,
decoration: InputDecoration(labelText: tr('시작 폴더 (비우면 홈 폴더)'), helperText: tr('예: /volume1/video · 탭의 맨 위가 됩니다'), helperMaxLines: 3), decoration: InputDecoration(labelText: tr('시작 폴더'), helperText: tr('비우면 홈 폴더 · 예: /volume1/video · 탭의 맨 위가 됩니다'), helperMaxLines: 3),
), ),
CheckboxListTile( CheckboxListTile(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,

View File

@ -185,7 +185,7 @@ Future<SmbServer?> editSmbServer(BuildContext context, AppController c, {SmbServ
content: SizedBox( content: SizedBox(
width: 520, width: 520,
child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ child: Column(mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [
TextField(controller: name, decoration: InputDecoration(labelText: tr('이름 (탭에 보임, 비우면 주소)'))), TextField(controller: name, decoration: InputDecoration(labelText: tr('이름'), helperText: tr('탭에 보입니다 · 비우면 주소'), helperMaxLines: 3)),
Row(children: [ Row(children: [
Expanded( Expanded(
child: TextField( child: TextField(
@ -227,7 +227,7 @@ Future<SmbServer?> editSmbServer(BuildContext context, AppController c, {SmbServ
decoration: InputDecoration(labelText: tr('공유 이름'), helperText: tr('예: video · home (\\\\서버\\공유 의 공유)'), helperMaxLines: 3), decoration: InputDecoration(labelText: tr('공유 이름'), helperText: tr('예: video · home (\\\\서버\\공유 의 공유)'), helperMaxLines: 3),
onChanged: (_) => set(() {}), onChanged: (_) => set(() {}),
), ),
TextField(controller: root, decoration: InputDecoration(labelText: tr('시작 폴더 (공유 안, 비우면 맨 위)'))), TextField(controller: root, decoration: InputDecoration(labelText: tr('시작 폴더'), helperText: tr('공유 안의 폴더 · 비우면 공유의 맨 위'), helperMaxLines: 3)),
TextField(controller: user, decoration: InputDecoration(labelText: tr('아이디 (비우면 게스트)'))), TextField(controller: user, decoration: InputDecoration(labelText: tr('아이디 (비우면 게스트)'))),
TextField( TextField(
controller: pass, controller: pass,
@ -241,7 +241,7 @@ Future<SmbServer?> editSmbServer(BuildContext context, AppController c, {SmbServ
), ),
), ),
), ),
TextField(controller: domain, decoration: InputDecoration(labelText: tr('도메인 · 작업 그룹 (보통 비움)'))), TextField(controller: domain, decoration: InputDecoration(labelText: tr('도메인 · 작업 그룹'), helperText: tr('보통 비워 둡니다'), helperMaxLines: 3)),
const SizedBox(height: 8), const SizedBox(height: 8),
if (testing) const LinearProgressIndicator(), if (testing) const LinearProgressIndicator(),
if (result != null) if (result != null)

View File

@ -158,7 +158,7 @@ Future<DavServer?> editDavServer(BuildContext context, AppController c, {DavServ
content: SizedBox( content: SizedBox(
width: 520, width: 520,
child: Column(mainAxisSize: MainAxisSize.min, children: [ child: Column(mainAxisSize: MainAxisSize.min, children: [
TextField(controller: name, decoration: InputDecoration(labelText: tr('이름 (탭에 보임, 비우면 주소)'))), TextField(controller: name, decoration: InputDecoration(labelText: tr('이름'), helperText: tr('탭에 보입니다 · 비우면 주소'), helperMaxLines: 3)),
TextField( TextField(
controller: url, controller: url,
keyboardType: TextInputType.url, keyboardType: TextInputType.url,

View File

@ -147,7 +147,7 @@ void main() {
..explorerLayout = 'single' ..explorerLayout = 'single'
..explorerOnePaneCopy = 'other'; ..explorerOnePaneCopy = 'other';
await open(tester); await open(tester);
expect(find.textContaining('복사 · 이동 갈 곳'), findsOneWidget); expect(find.textContaining('갈 곳: '), findsOneWidget);
expect(find.textContaining('갈 곳: right'), findsOneWidget, reason: '숨은 창의 폴더 이름 (전체 경로는 풍선 도움말)'); expect(find.textContaining('갈 곳: right'), findsOneWidget, reason: '숨은 창의 폴더 이름 (전체 경로는 풍선 도움말)');
await act(tester, () => tester.tap(find.text('doc.txt'))); await act(tester, () => tester.tap(find.text('doc.txt')));
await settle(tester, () => false, rounds: 15); await settle(tester, () => false, rounds: 15);

View File

@ -78,7 +78,7 @@ void main() {
await act(tester, () => tester.tap(find.text('WebDAV').last)); await act(tester, () => tester.tap(find.text('WebDAV').last));
await calm(tester); await calm(tester);
expect(find.text('WebDAV 서버 추가'), findsOneWidget); expect(find.text('WebDAV 서버 추가'), findsOneWidget);
await tester.enterText(find.widgetWithText(TextField, '이름 (탭에 보임, 비우면 주소)'), '집 NAS'); await tester.enterText(find.widgetWithText(TextField, '이름'), '집 NAS');
await tester.enterText(find.widgetWithText(TextField, '주소'), server.url); await tester.enterText(find.widgetWithText(TextField, '주소'), server.url);
await tester.enterText(find.widgetWithText(TextField, '아이디'), 'user'); await tester.enterText(find.widgetWithText(TextField, '아이디'), 'user');
await tester.enterText(find.widgetWithText(TextField, '비밀번호'), 'pass'); await tester.enterText(find.widgetWithText(TextField, '비밀번호'), 'pass');