Бывало у вас такое: находите крутую инди-игру или визуальную новеллу, а официальной русской локализации нет? Сидеть со смартфоном в руках и переводить экран через Google Переводчик - удовольствие сомнительное. Переключаться по Alt+Tab в браузер каждые две минуты - ломает всё погружение.
Посмотрев на существующие экранные переводчики, я понял, что они либо перегружены лишним функционалом, либо просят денег, либо просто неудобно сворачивают игру. В итоге я решил за пару вечеров собрать свой велосипед на Python: легковесную утилиту, которая по горячей клавише делает скриншот области, распознает текст, переводит его и выводит в красивом, прозрачном для кликов оверлее прямо поверх игры.
Скрытый текст
На тот момент я еще не знал куда я вообще лезу и лучше бы не знал
В этой статье я расскажу, как устроен проект, с какими болями Windows API пришлось столкнуться и как заставить графическое окно пропускать сквозь себя клики мыши.
Из чего собирался велосипед
Мне нужен был быстрый MVP, поэтому выбор пал на Python. Архитектура приложения состоит из четырех простых шагов: Захват экрана ➔ Распознавание (OCR) ➔ Перевод ➔ Вывод на экран.
Для реализации этого мини-конвейера я выбрал следующие библиотеки:
MSS (Multiple Screen Shots): Очень быстрая библиотека для создания скриншотов. В отличие от стандартного PIL, она делает снимки экрана за считанные миллисекунды, что критично для динамики.
EasyOCR: Готовый движок для распознавания текста на базе PyTorch. Почему не Tesseract? EasyOCR из коробки гораздо лучше справляется со сложными игровыми шрифтами и стилизованным текстом новелл прямо на локальной машине.
Deep Translator: Простая обертка для интеграции с переводчиками. Для первой версии я взял интеграцию с Google Translate (работает бесплатно и без ключей API).
Tkinter + ctypes (Win32 API): Стандартный GUI-движок Python для создания окна и низкоуровневая магия Windows для создания того самого «игрового оверлея».
Главная техническая боль: ограничения полноэкранного режима и магия Win32
Изначально я целился в перевод абсолютно любых игр, но столкнулся с суровой реальностью: в полноценном Fullscreen-режиме стандартные окна Windows поверх неё просто не отображаются.
Я так и не смог добиться адекватной работы приложения в «тяжелых» полноэкранных 3D-играх — в целом оно и понятно, ведь проект собран на коленке за один вечер. Но всё же я получил результат, который меня полностью устроил. Если рассматривать стандартную работу за ПК и использование различных программ, у которых не всегда есть русская локализация, то утилита показывает себя отлично, а главное - удобно. Запустил нужную прогу на английском, нажал хоткей, выделил текст и через 2-3 секунды получил перевод прямо перед глазами.
Чтобы оверлей работал максимально бесшовно в среде Windows (и в играх, запущенных в оконном режиме), пришлось подключить ctypes и залезть в дебри Windows API (user32.dll). Обычное окно Tkinter при клике по нему забирает фокус, из-за чего рабочая программа может свернуться или стать неактивной.
Нам нужно было задать окну специфические расширенные стили (Extended Window Styles) - WS_EX_TRANSPARENT и WS_EX_LAYERED, чтобы сделать его «призраком», пропускающим сквозь себя клики:
import tkinter as tk import ctypes root = tk.Tk() # Делаем окно поверх всех остальных root.attributes("-topmost", True) # Убираем рамки и заголовок окна root.overrideredirect(True) # Получаем дескриптор окна (HWND) через Win32 API hwnd = ctypes.windll.user32.GetParent(root.winfo_id()) # Достаем текущие стили окна style = ctypes.windll.user32.GetWindowLongW(hwnd, -20) # -20 это GWL_EXSTYLE # Добавляем флаги: # WS_EX_LAYERED (0x80000) — для поддержки прозрачности # WS_EX_TRANSPARENT (0x20) — заставляет окно игнорировать клики мыши style |= 0x80000 | 0x20 # Применяем новые стили обратно к окну ctypes.windll.user32.SetWindowLongW(hwnd, -20, style)
Теперь окно физически отображается на экране, но операционная система считает его прозрачным для мыши. Вы можете кликать прямо по тексту перевода, а клик будет уходить в приложение на заднем плане. Фокус не теряется, рабочий процесс не прерывается.
Честно про минусы и костыли
Так как это MVP, у текущей реализации есть свои компромиссы, о которых стоит сказать честно:
Размер сборки. Когда я упаковал проект в один независимый
.exeфайл через PyInstaller, его вес составил порядка 250 МБ. Это плата за локальныйEasyOCR, так как внутрь исполняемого файла упаковываются веса нейросети и библиотеки для работы с графикой.Зависимость от сети для перевода. Пока распознавание работает локально, сам перевод держится на бесплатном API Google Translate. Если упадет интернет — перевод пропадет. В будущем планирую добавить полностью офлайновые локальные модели перевода.
Как попробовать и планы на будущее
Проект полностью открытый. Если вы хотите посмотреть исходный код, предложить свой пул-реквест или просто скачать готовый собранный .exe файл и запустить его без установки Python, заглядывайте в мой репозиторий:
? Ссылка на репозиторий проекта на GitHub
В планах:
Добавить GUI-меню для выбора языков (сейчас зашито распознавание английского и перевод на русский).
Реализовать историю переводов в отдельном логе.
Добавить несколько OCR и дать пользователю выбор
Поработать над дизайном самого оверлея (сделать красивые скругленные углы и кастомные шрифты).
Локализовать на другие языки
Буду рад здоровой критике, советам по оптимизации Win32 API и вашим идеям! Какими экранными переводчиками пользуетесь вы и чего вам в них не хватает?
levge
О, да! Я тоже пытался такое написать, но для линукса. Терпения не хватило. Окно с переводом выводил на другой экран. Интересный факт, если взять скрин экрана номер 0, даёт все экраны сразу.
yanchino Автор
А на что конкретно терпения не хватило? И на чем конкретно писали? Планирую в будущем сделать версию под линукс. Но сейчас занят немного другим: перешел на C# Avalonia т.к. не понравился дизайн который получилось создать с помощью Tkinter.
victor_1212
в далеких 80х сделал подобное на PC, типа по просьбам трудящихся + для развлечения, две DOS TSR, первая подсвечивает слова, которых не находит в словаре, и позволяет словарь расширять и накапливать, независимая вторая TSR в real time переводит прямо на видео буфере, практически незаметно для глаза, используя hash lookup из словаря на диске,
хотелось посмотреть на что PC способны, когда они только появились, до этого только на mainframe
yanchino Автор
Сильно и олдскульно. Сейчас тоже пробую делать real time, но пока не очень получается. Да еще и проблема в том, что софт ориентирован под игры, а полноценный оверлей для full screen невозможно сделать т.к. античиты будут ругаться