230 lines
9.1 KiB
Python
230 lines
9.1 KiB
Python
import sys
|
|
import keyboard
|
|
import pyperclip
|
|
from PySide6.QtCore import QTimer, QEvent, Qt, QSettings
|
|
from PySide6.QtWidgets import (
|
|
QApplication, QMainWindow, QVBoxLayout, QCheckBox, QPushButton, QMessageBox, QWidget, QLabel, QLineEdit
|
|
)
|
|
from translatepy.translators.bing import BingTranslate
|
|
from translatepy.translators.deepl import DeeplTranslate
|
|
from translatepy.translators.google import GoogleTranslate
|
|
from translatepy.translators.libre import LibreTranslate
|
|
from translatepy.translators.mymemory import MyMemoryTranslate
|
|
from translatepy.translators.reverso import ReversoTranslate
|
|
from translatepy.translators.yandex import YandexTranslate
|
|
from translatepy.translators.microsoft import MicrosoftTranslate
|
|
|
|
|
|
class MultiTranslatorApp(QMainWindow):
|
|
def __init__(self):
|
|
super().__init__()
|
|
self.setWindowTitle("다중 번역기 설정")
|
|
self.setGeometry(100, 100, 400, 600)
|
|
|
|
# QSettings 초기화
|
|
self.settings = QSettings("MultiTranslatorApp", "TranslatorSettings")
|
|
|
|
# 번역 요청 카운터
|
|
self.request_count = {
|
|
"Bing": 0,
|
|
"DeepL": 0,
|
|
"Google": 0,
|
|
"LibreTranslate": 0,
|
|
"MyMemory": 0,
|
|
"Reverso": 0,
|
|
"Yandex": 0,
|
|
"Microsoft": 0
|
|
}
|
|
|
|
# GUI 레이아웃
|
|
self.central_widget = QWidget()
|
|
self.setCentralWidget(self.central_widget)
|
|
self.layout = QVBoxLayout(self.central_widget)
|
|
|
|
# 번역기 체크박스 및 API 키 필드 생성
|
|
self.translator_settings = {
|
|
"Bing": {"checkbox": QCheckBox("Bing Translate"), "api_key": QLineEdit()},
|
|
"DeepL": {"checkbox": QCheckBox("DeepL Translate"), "api_key": QLineEdit()},
|
|
"Google": {"checkbox": QCheckBox("Google Translate"), "api_key": None},
|
|
"LibreTranslate": {"checkbox": QCheckBox("LibreTranslate"), "api_key": None},
|
|
"MyMemory": {"checkbox": QCheckBox("MyMemory Translate"), "api_key": None},
|
|
"Reverso": {"checkbox": QCheckBox("Reverso Translate"), "api_key": None},
|
|
"Yandex": {"checkbox": QCheckBox("Yandex Translate"), "api_key": QLineEdit()},
|
|
"Microsoft": {"checkbox": QCheckBox("Microsoft Translate"), "api_key": QLineEdit()}
|
|
}
|
|
|
|
# 번역기 옵션 UI 구성
|
|
for name, widgets in self.translator_settings.items():
|
|
checkbox = widgets["checkbox"]
|
|
api_key_field = widgets["api_key"]
|
|
|
|
self.layout.addWidget(checkbox)
|
|
if api_key_field: # API 키 필드가 있는 경우
|
|
api_key_field.setPlaceholderText(f"{name} API 키 입력")
|
|
api_key_field.setVisible(False)
|
|
self.layout.addWidget(api_key_field)
|
|
|
|
checkbox.stateChanged.connect(lambda state, name=name: self.toggle_api_key_field(name, state))
|
|
|
|
# 자동 번역 토글
|
|
self.auto_translate_toggle = QCheckBox("클립보드 변경 시 자동 번역")
|
|
self.layout.addWidget(self.auto_translate_toggle)
|
|
self.auto_translate_toggle.stateChanged.connect(self.toggle_auto_translate)
|
|
|
|
# 적용 버튼
|
|
self.apply_button = QPushButton("설정 적용")
|
|
self.apply_button.clicked.connect(self.apply_settings)
|
|
self.layout.addWidget(self.apply_button)
|
|
|
|
# 번역기 초기화
|
|
self.selected_services = []
|
|
|
|
# 클립보드 감지 관련
|
|
self.auto_translate_enabled = False
|
|
self.last_clipboard_content = ""
|
|
self.clipboard_timer = QTimer(self)
|
|
self.clipboard_timer.timeout.connect(self.monitor_clipboard)
|
|
|
|
# 단축키 등록
|
|
keyboard.add_hotkey("ctrl+shift+t", lambda: self.run_translation_in_main_thread())
|
|
|
|
# ESC 키로 창 최소화
|
|
self.installEventFilter(self)
|
|
|
|
# 이전 설정 복원
|
|
self.load_settings()
|
|
|
|
def load_settings(self):
|
|
"""QSettings에서 체크박스 상태 및 API 키를 불러옵니다."""
|
|
for name, widgets in self.translator_settings.items():
|
|
checkbox = widgets["checkbox"]
|
|
api_key_field = widgets["api_key"]
|
|
|
|
# 체크박스 상태 복원
|
|
state = self.settings.value(f"{name}_checked", False, type=bool)
|
|
checkbox.setChecked(state)
|
|
|
|
# API 키 복원
|
|
if api_key_field:
|
|
api_key = self.settings.value(f"{name}_api_key", "", type=str)
|
|
api_key_field.setText(api_key)
|
|
|
|
def save_settings(self):
|
|
"""QSettings에 체크박스 상태 및 API 키를 저장합니다."""
|
|
for name, widgets in self.translator_settings.items():
|
|
checkbox = widgets["checkbox"]
|
|
api_key_field = widgets["api_key"]
|
|
|
|
# 체크박스 상태 저장
|
|
self.settings.setValue(f"{name}_checked", checkbox.isChecked())
|
|
|
|
# API 키 저장
|
|
if api_key_field:
|
|
self.settings.setValue(f"{name}_api_key", api_key_field.text())
|
|
|
|
def toggle_api_key_field(self, name, state):
|
|
"""API 키 입력 필드의 가시성을 토글합니다."""
|
|
api_key_field = self.translator_settings[name]["api_key"]
|
|
if api_key_field:
|
|
api_key_field.setVisible(state == Qt.Checked)
|
|
|
|
def apply_settings(self):
|
|
"""선택된 번역기를 업데이트하고 설정을 저장합니다."""
|
|
self.selected_services = []
|
|
for name, widgets in self.translator_settings.items():
|
|
checkbox = widgets["checkbox"]
|
|
api_key_field = widgets["api_key"]
|
|
|
|
if checkbox.isChecked():
|
|
# 필요한 번역기 추가
|
|
if name == "Bing":
|
|
self.selected_services.append(BingTranslate())
|
|
elif name == "DeepL":
|
|
self.selected_services.append(DeeplTranslate(api_key=api_key_field.text()))
|
|
elif name == "Google":
|
|
self.selected_services.append(GoogleTranslate())
|
|
elif name == "LibreTranslate":
|
|
self.selected_services.append(LibreTranslate())
|
|
elif name == "MyMemory":
|
|
self.selected_services.append(MyMemoryTranslate())
|
|
elif name == "Reverso":
|
|
self.selected_services.append(ReversoTranslate())
|
|
elif name == "Yandex":
|
|
self.selected_services.append(YandexTranslate(api_key=api_key_field.text()))
|
|
elif name == "Microsoft":
|
|
self.selected_services.append(MicrosoftTranslate(api_key=api_key_field.text()))
|
|
|
|
# 설정 저장
|
|
self.save_settings()
|
|
|
|
# 창 최소화
|
|
self.showMinimized()
|
|
|
|
def toggle_auto_translate(self):
|
|
if self.auto_translate_toggle.isChecked():
|
|
self.auto_translate_enabled = True
|
|
self.last_clipboard_content = pyperclip.paste()
|
|
self.clipboard_timer.start(500) # 0.5초마다 클립보드 감지
|
|
else:
|
|
self.auto_translate_enabled = False
|
|
self.clipboard_timer.stop()
|
|
|
|
def monitor_clipboard(self):
|
|
if not self.auto_translate_enabled:
|
|
return
|
|
clipboard_text = pyperclip.paste()
|
|
if clipboard_text != self.last_clipboard_content:
|
|
self.last_clipboard_content = clipboard_text
|
|
self.run_translation_in_main_thread()
|
|
|
|
def run_translation_in_main_thread(self):
|
|
"""메인 스레드에서 번역 실행."""
|
|
QTimer.singleShot(0, self.run_translation)
|
|
|
|
def run_translation(self):
|
|
# 클립보드 텍스트 가져오기
|
|
clipboard_text = pyperclip.paste()
|
|
if not clipboard_text.strip():
|
|
self.show_popup("클립보드에 텍스트가 없습니다.")
|
|
return
|
|
|
|
# 번역 결과 생성
|
|
results = []
|
|
for service in self.selected_services:
|
|
try:
|
|
result = service.translate(clipboard_text, "Korean")
|
|
service_name = service.__class__.__name__.replace("Translate", "")
|
|
# 요청 카운트 증가
|
|
if service_name in self.request_count:
|
|
self.request_count[service_name] += 1
|
|
|
|
# 번역 결과 추가
|
|
results.append(
|
|
f"[{service_name}]\n{result.result}\n\n(사용량: {self.request_count[service_name]}번 요청됨)"
|
|
)
|
|
except Exception as e:
|
|
service_name = service.__class__.__name__.replace("Translate", "")
|
|
results.append(f"[{service_name}] 번역 실패: {str(e)}")
|
|
|
|
# 결과 표시
|
|
self.show_popup("\n\n".join(results))
|
|
|
|
def show_popup(self, message):
|
|
popup = QMessageBox(self)
|
|
popup.setWindowTitle("번역 결과")
|
|
popup.setText(message)
|
|
popup.setStandardButtons(QMessageBox.Close)
|
|
popup.show()
|
|
|
|
def eventFilter(self, source, event):
|
|
if event.type() == QEvent.KeyPress and event.key() == Qt.Key_Escape:
|
|
self.showMinimized()
|
|
return super().eventFilter(source, event)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
app = QApplication(sys.argv)
|
|
window = MultiTranslatorApp()
|
|
window.show()
|
|
sys.exit(app.exec())
|