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())