kone
sub_icon

소미소프트

파일 구글 번역기) kr_tr_7.pyw

2026-04-22 20:36:11
유틸
조회 12216 · 좋아요 9
양식
<div>
    <table><tbody><tr><th colspan="2"><p style="margin: 0.5rem 0px; display: flex; justify-content: center; align-items: center;">=</p></th></tr><tr><td colspan="2"><p style="margin: 0.5rem 0px; display: flex; justify-content: center; align-items: center;">=</p></td></tr><tr><td><p style="margin: 0.5rem 0px; display: flex; justify-content: center; align-items: center;">=</p></td><td><p style="margin: 0.5rem 0px;">=</p></td></tr><tr><td><p style="margin: 0.5rem 0px; display: flex; justify-content: center; align-items: center;">=</p></td><td><p style="margin: 0.5rem 0px;">=</p></td></tr><tr><td><p style="margin: 0.5rem 0px; display: flex; justify-content: center; align-items: center;">=</p></td><td><p style="margin: 0.5rem 0px;">=</p></td></tr><tr><th colspan="2"><p style="margin: 0.5rem 0px; display: flex; justify-content: center; align-items: center;">=</p></th></tr><tr><td colspan="2"><p style="margin: 0.5rem 0px; display: flex; justify-content: center; align-items: center;">=</p></td></tr><tr><th colspan="2"><p style="margin: 0.5rem 0px; display: flex; justify-content: center; align-items: center;">=</p></th></tr><tr><td colspan="2"><p style="margin: 0.5rem 0px; display: flex; justify-content: center; align-items: center;">=</p></td></tr></tbody></table>
</div>

kr_tr_7.pyw

링크

aHR0cHM6Ly90cmFuc2Zlci5pdC90L2REQmhxZjVYa1JBSg==

단일로도 어느정도 쓸 수 있을텐데,
게임 번역하려면 추출한 다음 사용하는게 안정적이고 빠름

파이썬 설치되어 있어야 함
그록이 자꾸 바쁘다고 팅겨서 제미니에게 부탁함

AI 번역 돌릴줄 모르거나
컴 사양이 안되는 경우 쓸만할듯

코드
import os
import re
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext, ttk
import threading
import urllib.parse
import requests
import time

def google_translate(text, src='ja', dest='ko'):
    if not text.strip(): return text
    if not re.search(r'[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF]', text):
        return text

    try:
        url = f"https://translate.googleapis.com/translate_a/single?client=gtx&sl={src}&tl={dest}&dt=t&q={urllib.parse.quote(text)}"
        headers = {'User-Agent': 'Mozilla/5.0'}
        res = requests.get(url, headers=headers, timeout=5)
        res.raise_for_status()
        
        parts = res.json()[0]
        result = "".join([p[0] for p in parts if p and p[0]]).strip()
        
        # 마침표 보정 로직
        if not text.strip().endswith('.') and result.endswith('.'):
            result = result[:-1].strip()
            
        return result if result else text
    except Exception:
        return text

class AdvancedTranslator:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("하위 폴더 통합 번역기 v8.0 (큰따옴표 지원)")
        self.root.geometry("800x650")

        config_frame = tk.Frame(self.root)
        config_frame.pack(fill="x", padx=10, pady=5)

        # 구분자를 세미콜론(;)으로 사용하고 기본값에 큰따옴표(") 추가
        tk.Label(config_frame, text="번역 제외 문자 (';'로 구분):").grid(row=0, column=0, sticky="w")
        self.exclude_entry = tk.Entry(config_frame, width=50)
        self.exclude_entry.insert(0, '「; 」; <; >; "; ---; \\n; \\i; ,; [; ]; (; ); :; …; !; \\; :; (; ); ,') 
        self.exclude_entry.grid(row=0, column=1, padx=5, sticky="w")

        self.btn = tk.Button(self.root, text="폴더 선택 (하위 폴더 포함 번역 시작)", command=self.start_thread, 
                             height=2, bg="#4CAF50", fg="white", font=("맑은 고딕", 10, "bold"))
        self.btn.pack(fill="x", padx=10, pady=5)

        self.notebook = ttk.Notebook(self.root)
        self.notebook.pack(fill="both", expand=True, padx=10, pady=10)

        self.log_area = scrolledtext.ScrolledText(self.notebook, bg="#1e1e1e", fg="#ffffff", font=("맑은 고딕", 12))
        self.monitor_area = scrolledtext.ScrolledText(self.notebook, bg="#2d2d2d", fg="#a6e22e", font=("맑은 고딕", 12))
        
        self.notebook.add(self.log_area, text=" 전체 진행 로그 ")
        self.notebook.add(self.monitor_area, text=" 실시간 번역 비교 ")

        self.jp_pattern = re.compile(r'[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FFF]')

    def start_thread(self):
        path = filedialog.askdirectory()
        if not path: return
        self.btn.config(state='disabled')
        threading.Thread(target=self.process, args=(path,), daemon=True).start()

    def split_and_translate(self, text, exclude_chars):
        if not exclude_chars:
            return google_translate(text)

        # 특수 문자 및 큰따옴표를 안전하게 정규식 패턴으로 변환
        pattern = '|'.join(re.escape(char) for char in exclude_chars)
        tokens = re.split(f'({pattern})', text)
        
        translated_tokens = []
        for token in tokens:
            if not token: continue # 빈 문자열 건너뜀
            
            if token in exclude_chars:
                translated_tokens.append(token)
            elif self.jp_pattern.search(token):
                # 실제 번역 수행 (일본어 -> 한국어)
                translated_tokens.append(google_translate(token, src='ja', dest='ko'))
                time.sleep(0.15) 
            else:
                translated_tokens.append(token)
        
        return "".join(translated_tokens)

    def process(self, root_path):
        raw_excludes = self.exclude_entry.get().split(";")
        exclude_chars = [x.strip() for x in raw_excludes if x.strip()]
        
        all_files = []
        for root, dirs, files in os.walk(root_path):
            for file in files:
                if file.lower().endswith(('.txt', '.json', '.ini', '.csv')):
                    all_files.append(os.path.join(root, file))

        parent_dir = os.path.dirname(root_path)
        folder_name = os.path.basename(root_path)
        out_root_dir = os.path.join(parent_dir, f"{folder_name}_Translated")
        
        self.log_insert(f"🚀 총 {len(all_files)}개의 파일을 찾았습니다.\n")
        self.log_insert(f"🏠 저장 위치: {out_root_dir}\n{'-'*50}\n")

        for i, file_path in enumerate(all_files):
            rel_path = os.path.relpath(file_path, root_path)
            save_path = os.path.join(out_root_dir, rel_path)
            os.makedirs(os.path.dirname(save_path), exist_ok=True)
            
            self.log_insert(f"📄 [{i+1}/{len(all_files)}] {rel_path} 번역 중...\n")
            
            content_lines = []
            for enc in ['shift_jis', 'utf-8-sig', 'cp932', 'utf-8', 'euc-kr']:
                try:
                    with open(file_path, 'r', encoding=enc) as f:
                        content_lines = f.readlines()
                    break
                except: continue

            translated_lines = []
            for line in content_lines:
                if self.jp_pattern.search(line):
                    origin = line.rstrip('\n\r')
                    translated = self.split_and_translate(origin, exclude_chars)
                    self.monitor_insert(f"파일: {rel_path}\n원문: {origin}\n번역: {translated}\n{'-'*20}\n")
                    translated_lines.append(translated + '\n')
                else:
                    translated_lines.append(line)

            with open(save_path, 'w', encoding='utf-8-sig') as f:
                f.writelines(translated_lines)

        self.btn.config(state='normal')
        messagebox.showinfo("완료", "큰따옴표를 포함한 모든 파일 번역이 완료되었습니다.")

    def log_insert(self, msg):
        self.log_area.insert(tk.END, msg)
        self.log_area.see(tk.END)

    def monitor_insert(self, msg):
        self.monitor_area.insert(tk.END, msg)
        self.monitor_area.see(tk.END)

if __name__ == "__main__":
    app = AdvancedTranslator()
    app.root.mainloop()
9
댓글 8개
댓글 쓰기
04.22
번역 라이브러리는 googletrans==3.1.0a0 이거 인가…?
04.23
제미니에게 뭐라고 했더니 라이브러리 안 쓰는거 같음
ja 대신 en 하면 영어도 될라나
04.23
그건 대부분 영어로 이루어져있기 때문에 제외 단어 엄청 등록하는거 아니면 불가능할걸 게임 터짐
04.23
추출 상태로 돌리면 가능은 할거임 통으로 돌리면 터진다는 뜻
0 / 500
[직번][sanatuki]개변태아이돌♥ 에로에로세뇌라이브시작이야♥
동인
돋돋돋돋돋
05.10 23894 90
[업로드 갱신안내] [PC-모바일-Linux-macOS] [공식한글]-존재감 없는 여동생과의 소박한 일상 1.02
번역
Ghost
05.10 34970 82
[복구] 복구된지 오래된 용량 적은 게임 5개
복구
몬스터가아니다신이다
05.10 34424 81
[AI번역+검수] 후타) [Fence 14]자지가 생겨버린 우등생짱
동인
vereeeev
05.10 31386 183
버) RVNWaWRlb01ha2Vy 2026.02~04
영상
xjabdks
05.10 31311 139
[Minamihama Yoriko] 교배 라이선스 ~인기 없는 내가 최강 유전자?!~
동인
1uF
05.10 29974 185
[Itohana] 건방진 소꿉친구가 나를 빼앗으러 오는 승리 √
동인
1uF
05.10 32870 136
26.05.12, 90일) 1-2. RJ310786 ReBF v2.0. 개선 26.05.12.7z
복구
ㅇㅇ
05.10 16325 60
[Takeda Aranobu] 치처녀 풍기위원의 모두에게 말할수없는 음미한 부탁 9
동인
1uF
05.10 16382 55
[mahouya] 패배 엔드에서 레오나 공주가 범해지는 이야기
동인
고전발굴
05.10 19937 24
[후타주의] 후원보급,Br@n) 네로짱 + 통합편집
영상
비밀봉투
05.10 18822 77
[さるら] 축제에서 의상이 풀려버리는 만화
동인
bender
05.10 16307 42
[직번] [armadillo daiji] 갸루 모녀의 돈버는 방법2
동인
maha1004
05.10 35530 165
Nⓐjⓐr 41개 모음
영상
darkunicorn
05.10 21913 96
[구매보급][한국어자막판] 거유 메스○키 마왕님과 마족 메이드장이 더러운 자○에 아양 떨며 봉사하게 되는 이야기♪
소리
이름뭐하지
05.10 19595 68
[버전업알림] 교칙은 절대적이다
번역
rack11
05.10 40368 73
Br@n)벽람항로 임플래커블 + 통합편집
영상
비밀봉투
05.10 15261 80
[구매보급/미번/이종간/촉수] 서큐버스 헤븐
미번
루파조아
05.10 21146 32
AI, 셀레스포니아) 마카이 지구의 주민
야짤
miso5
05.10 10970 101
에바네시아 (스타레일)
영상
브레머튼
05.10 21540 101
[번역요청] Abyss Of Pleasure 0.2.6
미번
0000p
05.10 13775 48
AI) 무인도 사원 여행기 시즈하 첫H장면
야짤
zerocoke
05.10 7989 33
[구매보급/공식번역] RJ01567096 교칙은 절대적이다
번역
rack11
05.10 52243 183
[구매보급] RJ01605925 고대의 기사와 제물의 무녀 26.05.10
미번
gkqisq
05.10 15269 74
후원보급,Br@n)버튜버 시온,보탄 + 통합편집
영상
비밀봉투
05.10 21571 86
도트/움짤 교배 프레스
야짤
angkimozzi
05.10 18797 45
[구매보급] [버전업] RJ01582213 라스티 던전 2 ver1.0?? 26.05.10
미번
gkqisq
05.10 9074 51
[aI번역-노모] 거유 여성이 둘 없으면 발기하지 못하는 남편을 위해 친구를 데려온 아내 -총집편
동인
mybest
05.10 30304 125
미번) 할 수 있는 후배 아오이 짱! ~2인 동거 시작해버렸습니다~ (できる後輩アオイちゃん! ~二人ぐらし始まっちゃいました~)
미번
darkunicorn
05.10 11852 33
미번) 나츠이로 레슨 v1.1.0b (なついろレッスン~the last summer time)
미번
darkunicorn
05.10 15032 25