Compare commits

..

No commits in common. "master" and "3.2.3" have entirely different histories.

28 changed files with 523 additions and 1671 deletions

View File

@ -78,7 +78,7 @@ jobs:
- name: Download release url
if: contains(github.ref, '/tags/')
uses: actions/download-artifact@v4.1.7
uses: actions/download-artifact@v1
with:
name: release_upload_url
path: ./

View File

@ -1,7 +1,5 @@
# Screen Translator
**The project is almost abandoned. I don't have time for it and I can only fix minor issues**
## Introduction
This software allows you to translate any text on screen.
@ -18,18 +16,12 @@ If the app fails to start complaining about missing dlls or there are any update
**OS X**: currently not supported.
### App translation
To install Hebrew translation of the app (thanks to [Y-PLONI](https://github.com/Y-PLONI)),
download [this](https://github.com/OneMoreGres/ScreenTranslator/releases/download/3.3.0/screentranslator_he.qm)
file and place it into the `translations` folder next to `screen-translator.exe`.
## Setup
The app doesn't have a main window.
After start it shows only the tray icon.
If the app detects invalid settings, it will show the error message via system tray.
If the app detects invalid settings, it will show the error message via system tray.
It will also highlight the section name in red on the left panel of the settings window.
Clicking on that section name will show a more detailed error message in the right panel (also in red).
@ -61,6 +53,9 @@ Then click `Ok` to close settings.
By default resources are downloaded to the one of the user's folders.
If `Portable` setting in `General` section is checked, then resources will be downloaded to the app's folder.
If you are experiencing crashes during the app usage, then try changing `tesseract library version` from `Optimized` to `Compatible`.
It provides the same functionality, but should work on the bigger variety of hardware.
Set `QTWEBENGINE_DISABLE_SANDBOX=1` environment variable when fail to start due to crash.
Answers to some frequently asked questions can be found in issues or

View File

@ -11,6 +11,5 @@
</qresource>
<qresource prefix="/translations">
<file alias="screentranslator_ru.qm">share/translations/screentranslator_ru.qm</file>
<file alias="screentranslator_he.qm">share/translations/screentranslator_he.qm</file>
</qresource>
</RCC>

View File

@ -8,7 +8,7 @@ DEPS_DIR=$$(ST_DEPS_DIR)
isEmpty(DEPS_DIR):DEPS_DIR=$$PWD/../deps
INCLUDEPATH += $$DEPS_DIR/include
LIBS += -L$$DEPS_DIR/lib
LIBS += -lhunspell -lleptonica -ltesseract
LIBS += -lhunspell -lleptonica
win32{
LIBS += -lUser32
@ -21,7 +21,7 @@ linux{
SOURCES += $$PWD/external/miniz/miniz.c
INCLUDEPATH += $$PWD/external
VER=3.3.0
VER=3.2.3
DEFINES += VERSION="$$VER"
VERSION = $$VER.0
QMAKE_TARGET_COMPANY = Gres
@ -117,8 +117,7 @@ OTHER_FILES += \
updates.json
TRANSLATIONS += \
share/translations/screentranslator_ru.ts \
share/translations/screentranslator_he.ts
share/translations/screentranslator_ru.ts
linux {
PREFIX = /usr

View File

@ -1,10 +1,5 @@
# Changes
## 3.3.0
* Use single tesseract library (not optimized and compatible versions)
* Improved recognition
## 3.2.3
* Fixed translators order persistance

View File

@ -1,10 +1,5 @@
# Изменения
## 3.3.0
* Использование единой библиотеки распознавания (без оптимизированной и совместимой версий)
* Улучшено распознавание
## 3.2.3
* Исправлено сохранение порядка переводчиков в настройках

View File

@ -47,7 +47,8 @@ os.environ['VERSION'] = app_version
flags = '' if os.getenv("DEBUG") is None else '-unsupported-allow-new-glibc'
additional_files = glob(ssl_dir + '/lib/lib*.so.*') + \
glob('/usr/lib/x86_64-linux-gnu/nss/*')
glob('/usr/lib/x86_64-linux-gnu/nss/*') + \
glob(dependencies_dir + '/lib/libtesseract-*.so')
out_lib_dir = install_dir + '/usr/lib'
os.makedirs(out_lib_dir, exist_ok=True)
for f in additional_files:

View File

@ -6,12 +6,27 @@ import platform
c.print('>> Installing tesseract')
install_dir = dependencies_dir
required_version = '5.2.0'
url = 'https://github.com/tesseract-ocr/tesseract/archive/{}.tar.gz'.format(required_version)
url = 'https://github.com/tesseract-ocr/tesseract/archive/5.1.0.tar.gz'
required_version = '5.1.0'
build_type_flag = 'Debug' if build_type == 'debug' else 'Release'
cache_file = install_dir + '/tesseract.cache'
# compatibility flags
compat_flags = ''
compat_flags += ' -D DISABLE_LEGACY_ENGINE=ON '
compat_flags += ' -D DISABLE_ARCHIVE=ON '
compat_flags += ' -D DISABLE_CURL=ON '
version_tag = os.environ.get('TAG', '')
if version_tag == 'compatible':
compat_flags += ' -D HAVE_AVX2=0 '
compat_flags += ' -D HAVE_FMA=0 '
lib_suffix = version_tag
if len(lib_suffix) > 0:
lib_suffix = '-' + lib_suffix
cache_file = install_dir + '/tesseract{}.cache'.format(lib_suffix)
cache_file_data = required_version + build_type_flag
def check_existing():
@ -27,25 +42,22 @@ def check_existing():
return False
if platform.system() == "Windows":
file_name_ver = required_version[0] + required_version[2]
dll = install_dir + '/bin/tesseract{}.dll'.format(file_name_ver)
lib = install_dir + '/lib/tesseract{}.lib'.format(file_name_ver)
if not os.path.exists(dll) or not os.path.exists(lib):
return False
c.symlink(dll, install_dir + '/bin/tesseract.dll')
c.symlink(lib, install_dir + '/lib/tesseract.lib')
lib = install_dir + '/bin/tesseract{}.dll'.format(lib_suffix)
orig_lib = install_dir + '/bin/tesseract51.dll'
elif platform.system() == "Darwin":
lib = install_dir + '/lib/libtesseract.{}.dylib'.format(required_version)
if not os.path.exists(lib):
return False
c.symlink(lib, install_dir + '/lib/libtesseract.dylib')
lib = install_dir + '/lib/libtesseract{}.dylib'.format(lib_suffix)
orig_lib = install_dir + '/lib/libtesseract.{}.dylib'.format(required_version)
else:
lib = install_dir + '/lib/libtesseract.so.{}'.format(required_version)
if not os.path.exists(lib):
return False
c.symlink(lib, install_dir + '/lib/libtesseract.so')
lib = install_dir + '/lib/libtesseract{}.so'.format(lib_suffix)
orig_lib = install_dir + '/lib/libtesseract.so.{}'.format(required_version)
return True
if os.path.exists(lib):
return True
if os.path.exists(orig_lib):
os.rename(orig_lib, lib)
return True
return False
if check_existing() and not 'FORCE' in os.environ:
@ -59,24 +71,60 @@ src_dir = os.path.abspath('tesseract_src')
c.extract(archive, '.')
c.symlink(c.get_archive_top_dir(archive), src_dir)
if platform.system() == "Windows":
# workaround for not found 'max'
modify_data = ''
modify_file = '{}/src/ccmain/thresholder.cpp'.format(src_dir)
with open(modify_file, 'r') as f:
modify_data = f.read()
if modify_data.find('<algorithm>') == -1:
modify_data = modify_data.replace(
'''<tuple>''',
'''<tuple>\n#include <algorithm>''')
with open(modify_file, 'w') as f:
f.write(modify_data)
# ignore libtiff
modify_data = ''
modify_file = '{}/CMakeLists.txt'.format(src_dir)
with open(modify_file, 'r') as f:
modify_data = f.read()
if modify_data.find('#pkg_check_modules(TIFF libtiff-4)') == -1:
modify_data = modify_data.replace(
'''pkg_check_modules(TIFF libtiff-4)''',
'''#pkg_check_modules(TIFF libtiff-4)''')
with open(modify_file, 'w') as f:
f.write(modify_data)
if platform.system() == "Linux":
# FIXME fix crash on ubuntu
modify_data = ''
modify_file = '{}/src/ccmain/tessedit.cpp'.format(src_dir)
with open(modify_file, 'r') as f:
modify_data = f.read()
lines = modify_data.split('\n')
for line in [250,253,255,256]:
if not lines[line].startswith('//'):
lines[line] = '// ' + lines[line]
modify_data = '\n'.join(lines)
with open(modify_file, 'w') as f:
f.write(modify_data)
c.ensure_got_path(install_dir)
c.recreate_dir(build_dir)
os.chdir(build_dir)
cmake_args = '"{0}" \
-DCMAKE_INSTALL_PREFIX="{1}" \
-DLeptonica_DIR="{1}/cmake" \
-DSW_BUILD=OFF \
-DBUILD_TRAINING_TOOLS=OFF \
-DBUILD_TESTS=OFF \
-DBUILD_SHARED_LIBS=ON \
-DDISABLE_CURL=ON \
-DDISABLE_ARCHIVE=ON \
-DUSE_SYSTEM_ICU=ON \
-DENABLE_LTO=ON \
-DGRAPHICS_DISABLED=ON \
-DDISABLED_LEGACY_ENGINE=ON \
cmake_args = '"{0}" -DCMAKE_INSTALL_PREFIX="{1}" -DLeptonica_DIR="{1}/cmake" \
-DBUILD_TRAINING_TOOLS=OFF -DBUILD_TESTS=OFF -DBUILD_SHARED_LIBS=ON -DSW_BUILD=OFF \
'.format(src_dir, install_dir)
if platform.system() == "Windows":
@ -87,6 +135,10 @@ if platform.system() == "Windows":
c.set_make_threaded()
c.run('cmake {}'.format(cmake_args))
if len(compat_flags) > 0:
c.run('cmake {} .'.format(compat_flags))
c.run('cmake {} .'.format(compat_flags)) # for sure :)
c.run('cmake --build . --config {}'.format(build_type_flag))
c.run('cmake --build . --target install --config {}'.format(build_type_flag))

View File

@ -29,8 +29,15 @@ def r(script):
r('get_qt.py')
r('get_qt_ssl.py')
r('get_leptonica.py')
os.environ['TAG'] = 'optimized'
r('get_tesseract.py')
os.environ['TAG'] = 'compatible'
r('get_tesseract.py')
del os.environ['TAG']
r('get_hunspell.py')
r('test.py')
r('build.py')

File diff suppressed because it is too large Load Diff

View File

@ -673,12 +673,12 @@ Check for updates to silence this warning</source>
<translation>неизвестные языки для перевода: %1 или %2</translation>
</message>
<message>
<location filename="../../src/ocr/tesseract.cpp" line="234"/>
<location filename="../../src/ocr/tesseract.cpp" line="255"/>
<source>init failed</source>
<translation>ошибка инициалиизации</translation>
</message>
<message>
<location filename="../../src/ocr/tesseract.cpp" line="294"/>
<location filename="../../src/ocr/tesseract.cpp" line="306"/>
<source>Failed to recognize text or no text selected</source>
<translation>Ошибка распознавания текста или нет текста в выделенной зоне</translation>
</message>
@ -697,12 +697,12 @@ in %1</source>
в %1</translation>
</message>
<message>
<location filename="../../src/capture/capturearea.cpp" line="28"/>
<location filename="../../src/capture/capturearea.cpp" line="27"/>
<source>No source language set</source>
<translation>Не задан исходный язык</translation>
</message>
<message>
<location filename="../../src/capture/capturearea.cpp" line="35"/>
<location filename="../../src/capture/capturearea.cpp" line="34"/>
<source>No target language set</source>
<translation>Не задан язык результата</translation>
</message>
@ -712,37 +712,37 @@ in %1</source>
<translation>Не восстанавливать интерфейс пользователя (размер и положения окна и т.д.)</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="189"/>
<location filename="../../src/settingseditor.cpp" line="197"/>
<source>&lt;p&gt;Optical character recognition (OCR) and translation tool&lt;/p&gt;</source>
<translation>&lt;p&gt;Инструмент оптического распознавания текста (OCR) и перевода&lt;/p&gt;</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="191"/>
<location filename="../../src/settingseditor.cpp" line="199"/>
<source>&lt;p&gt;Version: %1&lt;/p&gt;</source>
<translation>&lt;p&gt;Версия: %1&lt;/p&gt;</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="193"/>
<location filename="../../src/settingseditor.cpp" line="201"/>
<source>&lt;p&gt;Setup instructions: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;&lt;/p&gt;</source>
<translation>&lt;p&gt;Инструкции по установке: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;&lt;/p&gt;</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="195"/>
<location filename="../../src/settingseditor.cpp" line="202"/>
<source>&lt;p&gt;Changelog: &lt;a href=&quot;%1&quot;&gt;%2&lt;/a&gt;&lt;/p&gt;</source>
<translation>&lt;p&gt;Список изменений: &lt;a href=&quot;%1&quot;&gt;%2&lt;/a&gt;&lt;/p&gt;</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="197"/>
<location filename="../../src/settingseditor.cpp" line="204"/>
<source>&lt;p&gt;License: &lt;a href=&quot;%3&quot;&gt;MIT&lt;/a&gt;&lt;/p&gt;</source>
<translation>&lt;p&gt;Лицензия: &lt;a href=&quot;%3&quot;&gt;MIT&lt;/a&gt;&lt;/p&gt;</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="198"/>
<location filename="../../src/settingseditor.cpp" line="205"/>
<source>&lt;p&gt;Author: Gres (&lt;a href=&quot;mailto:%1&quot;&gt;%1&lt;/a&gt;)&lt;/p&gt;</source>
<translation>&lt;p&gt;Автор: Gres (&lt;a href=&quot;mailto:%1&quot;&gt;%1&lt;/a&gt;)&lt;/p&gt;</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="200"/>
<location filename="../../src/settingseditor.cpp" line="207"/>
<source>&lt;p&gt;Issues: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;&lt;/p&gt;</source>
<translation>&lt;p&gt;Поддержка: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;&lt;/p&gt;</translation>
</message>
@ -844,7 +844,7 @@ in %1</source>
<translation>Повторить захват</translation>
</message>
<message>
<location filename="../../src/represent/resultwidget.cpp" line="95"/>
<location filename="../../src/represent/resultwidget.cpp" line="93"/>
<source>Without correction:
</source>
<translation>Без коррекции:
@ -919,41 +919,42 @@ in %1</source>
<translation>сохранять пароль (небезопасно)</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="355"/>
<source>Library version</source>
<translation type="vanished">Версия</translation>
<translation>Версия</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="359"/>
<location filename="../../src/settingseditor.ui" line="369"/>
<source>User substitutions</source>
<translation>Пользовательская коррекция</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="382"/>
<location filename="../../src/settingseditor.ui" line="392"/>
<source>Use auto corrections (hunspell)</source>
<translation>Использовать автокоррекцию (hunspell)</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="389"/>
<location filename="../../src/settingseditor.ui" line="399"/>
<source>Use user substitutions</source>
<translation>Использовать пользовательскую коррекцию</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="396"/>
<location filename="../../src/settingseditor.ui" line="406"/>
<source>Hunspell dictionaries path:</source>
<translation>Путь к словарям Hunspell:</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="458"/>
<location filename="../../src/settingseditor.ui" line="468"/>
<source>Language:</source>
<translation>Язык:</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="494"/>
<location filename="../../src/settingseditor.ui" line="504"/>
<source> secs</source>
<translation> сек</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="434"/>
<location filename="../../src/settingseditor.ui" line="444"/>
<source>Ignore SSL errors</source>
<translation>Игнорировать ошибки SSL</translation>
</message>
@ -983,102 +984,102 @@ in %1</source>
<translation>Писать логи в файл (отладка)</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="345"/>
<location filename="../../src/settingseditor.ui" line="342"/>
<source>Default language:</source>
<translation>Язык по умолчанию:</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="303"/>
<location filename="../../src/settingseditor.ui" line="329"/>
<source>Tessdata path:</source>
<translation>Путь к языкам (tessdata):</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="369"/>
<location filename="../../src/settingseditor.ui" line="379"/>
<source>\\ for \ symbol, \n for newline</source>
<translation>\\ для символа \ , \n для символа новой строки</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="417"/>
<location filename="../../src/settingseditor.ui" line="427"/>
<source>Translators path:</source>
<translation>Путь к переводчикам:</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="424"/>
<location filename="../../src/settingseditor.ui" line="434"/>
<source>Translators</source>
<translation>Переводчики</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="559"/>
<location filename="../../src/settingseditor.ui" line="569"/>
<source>Result window</source>
<translation>Окно результата</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="565"/>
<location filename="../../src/settingseditor.ui" line="575"/>
<source>Font:</source>
<translation>Шрифт:</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="575"/>
<location filename="../../src/settingseditor.ui" line="585"/>
<source>Font size:</source>
<translation>Размер шрифта:</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="592"/>
<location filename="../../src/settingseditor.ui" line="602"/>
<source>Font color:</source>
<translation>Цвет шрифта:</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="606"/>
<location filename="../../src/settingseditor.ui" line="616"/>
<source>Background:</source>
<translation>Фон:</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="620"/>
<location filename="../../src/settingseditor.ui" line="630"/>
<source>Show image</source>
<translation>Показывать изображение</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="627"/>
<location filename="../../src/settingseditor.ui" line="637"/>
<source>Show recognized</source>
<translation>Показывать распознанное</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="677"/>
<location filename="../../src/settingseditor.ui" line="687"/>
<source>Update check interval (days):</source>
<translation>Интервал проверки обновления (дней):</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="684"/>
<location filename="../../src/settingseditor.ui" line="694"/>
<source>0 - disabled</source>
<translation>- отключено</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="444"/>
<location filename="../../src/settingseditor.ui" line="454"/>
<source>Translate text</source>
<translation>Переводить текст</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="451"/>
<location filename="../../src/settingseditor.ui" line="461"/>
<source>Single translator timeout:</source>
<translation>Переходить к следующему переводчику после:</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="521"/>
<location filename="../../src/settingseditor.ui" line="531"/>
<source>Result type</source>
<translation>Тип результата</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="533"/>
<location filename="../../src/settingseditor.ui" line="543"/>
<source>Tray</source>
<translation>Трей</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="546"/>
<location filename="../../src/settingseditor.ui" line="556"/>
<source>Window</source>
<translation>Окно</translation>
</message>
<message>
<location filename="../../src/settingseditor.ui" line="700"/>
<location filename="../../src/settingseditor.ui" line="710"/>
<source>Check now</source>
<translation>Проверить сейчас</translation>
</message>
@ -1174,29 +1175,32 @@ Hunspell ищет в своем словаре слова, похожие на
<translation>HTTP</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="126"/>
<source>Optimized</source>
<translation type="vanished">Оптимизированная</translation>
<translation>Оптимизированная</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="127"/>
<source>Compatible</source>
<translation type="vanished">Совместимая</translation>
<translation>Совместимая</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="131"/>
<source>Use compatible version if you are experiencing crashes during recognition</source>
<translation type="vanished">Используйте совместимую версию если программа неожиданно завершается во время распознавания</translation>
<translation>Используйте совместимую версию если программа неожиданно завершается во время распознавания</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="135"/>
<location filename="../../src/settingseditor.cpp" line="143"/>
<source>&lt;b&gt;NOTE! Some translators might require the translation window to be visible. You can make it using the &quot;Show translator&quot; entry in the tray icon&apos;s context menu&lt;/b&gt;</source>
<translation>&lt;b&gt;ПРИМЕЧАНИЕ! Для работы некоторых переводчиков может потребоваться активное окно перевода. Его можно отобразить при помощи пункта &quot;Показать окно перевода&quot; контекстного меню иконки в трее&lt;/b&gt;</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="143"/>
<location filename="../../src/settingseditor.cpp" line="151"/>
<source>Sample text</source>
<translation>Текст для проверки</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="208"/>
<location filename="../../src/settingseditor.cpp" line="215"/>
<source>The program workflow consists of the following steps:
1. Selection on the screen area
2. Recognition of the selected area
@ -1219,7 +1223,7 @@ Then set default recognition and translation languages, enable some (or all) tra
Далее установите языки распознавания и перевода по умолчанию, активируйте некоторые (или все) переводчики и настройку &quot;переводить текст&quot;, если нужно.</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="371"/>
<location filename="../../src/settingseditor.cpp" line="380"/>
<source>Portable changed. Apply settings first</source>
<translation>Portable режим изменен. Сначала примените настройки</translation>
</message>

View File

@ -51,7 +51,7 @@ void Corrector::correct(const TaskPtr &task)
task->corrected = task->recognized;
if (settings_.useUserSubstitutions && !settings_.userSubstitutions.empty()) {
if (!settings_.userSubstitutions.empty()) {
task->corrected = substituteUser(task->recognized, task->sourceLanguage);
LTRACE() << "Corrected with user data";
}

View File

@ -4,7 +4,6 @@
#include <optional>
#include <unordered_map>
#include <vector>
using LanguageId = QString;

View File

@ -79,5 +79,9 @@ void Recognizer::updateSettings()
SOFT_ASSERT(!settings_.tessdataPath.isEmpty(), return );
queue_.clear();
emit reset(settings_.tessdataPath);
const auto libName =
(settings_.tesseractVersion == TesseractVersion::Optimized
? "tesseract-optimized"
: "tesseract-compatible");
emit reset(settings_.tessdataPath, libName);
}

View File

@ -18,7 +18,7 @@ public:
signals:
void recognizeImpl(const TaskPtr &task);
void reset(const QString &tessdataPath);
void reset(const QString &tessdataPath, const QString &tesseractLibrary);
private:
void recognized(const TaskPtr &task);

View File

@ -17,8 +17,8 @@ void RecognizeWorker::handle(const TaskPtr &task)
if (!engines_.count(task->sourceLanguage)) {
LTRACE() << "Create OCR engine" << task->sourceLanguage;
auto engine =
std::make_unique<Tesseract>(task->sourceLanguage, tessdataPath_);
auto engine = std::make_unique<Tesseract>(task->sourceLanguage,
tessdataPath_, tesseractLibrary_);
if (!engine->isValid()) {
result->error = tr("Failed to init OCR engine: %1").arg(engine->error());
@ -43,12 +43,14 @@ void RecognizeWorker::handle(const TaskPtr &task)
emit finished(result);
}
void RecognizeWorker::reset(const QString &tessdataPath)
void RecognizeWorker::reset(const QString &tessdataPath,
const QString &tesseractLibrary)
{
if (tessdataPath_ == tessdataPath)
if (tessdataPath_ == tessdataPath && tesseractLibrary_ == tesseractLibrary)
return;
tessdataPath_ = tessdataPath;
tesseractLibrary_ = tesseractLibrary;
engines_.clear();
LTRACE() << "Cleared OCR engines";
}

View File

@ -13,7 +13,7 @@ public:
~RecognizeWorker();
void handle(const TaskPtr &task);
void reset(const QString &tessdataPath);
void reset(const QString &tessdataPath, const QString &tesseractLibrary);
signals:
void finished(const TaskPtr &task);
@ -24,4 +24,5 @@ private:
std::map<QString, std::unique_ptr<Tesseract>> engines_;
std::map<QString, Generation> lastGenerations_;
QString tessdataPath_;
QString tesseractLibrary_;
};

View File

@ -4,7 +4,6 @@
#include "task.h"
#include <leptonica/allheaders.h>
#include <tesseract/baseapi.h>
#include <QBuffer>
#include <QDir>
@ -91,121 +90,145 @@ static double getScale(Pix *source)
return scale;
}
// Smart pointer for Pix
class PixGuard
static Pix *prepareImage(const QImage &image)
{
auto pix = convertImage(image);
SOFT_ASSERT(pix, return nullptr);
LTRACE() << "Converted Pix" << pix;
auto gray = pixConvertRGBToGray(pix, 0.0, 0.0, 0.0);
LTRACE() << "Created gray Pix" << gray;
SOFT_ASSERT(gray, return nullptr);
pixDestroy(&pix);
LTRACE() << "Removed converted Pix";
auto scaleSource = gray;
auto scaled = scaleSource;
if (const auto scale = getScale(scaleSource); scale > 1.0) {
scaled = pixScale(scaleSource, scale, scale);
LTRACE() << "Scaled Pix for OCR" << LARG(scale) << LARG(scaled);
if (!scaled)
scaled = scaleSource;
}
if (scaled != scaleSource) {
pixDestroy(&scaleSource);
LTRACE() << "Removed unscaled Pix";
}
return scaled;
}
static void cleanupImage(Pix **image)
{
pixDestroy(image);
}
// do not include capi.h from tesseract because it defined BOOL that breaks msvc
struct TessBaseAPI;
class Tesseract::Wrapper
{
using CreateApi = TessBaseAPI *(*)();
using DeleteApi = void (*)(TessBaseAPI *);
using InitApi = int (*)(TessBaseAPI *, const char *, const char *, int);
using SetImage = void (*)(TessBaseAPI *, struct Pix *);
using GetUtf8 = char *(*)(TessBaseAPI *);
using ClearApi = void (*)(TessBaseAPI *);
using DeleteUtf8 = void (*)(const char *);
using SetPageMode = void (*)(TessBaseAPI *, int);
public:
explicit PixGuard(Pix *pix = nullptr)
: pix_(pix)
explicit Wrapper(const QString &libraryName)
: lib(libraryName)
{
}
~PixGuard()
{
if (pix_)
pixDestroy(&pix_);
}
void operator=(Pix *pix)
{
if (!pix)
if (!lib.load()) {
LERROR() << "Failed to load tesseract library" << libraryName;
return;
if (pix_)
pixDestroy(&pix_);
pix_ = pix;
}
operator Pix *() { return pix_; }
Pix *operator->() { return pix_; }
Pix *&get() { return pix_; }
Pix *take()
{
auto ret = pix_;
pix_ = nullptr;
return ret;
}
void trace(const QString &name) const
{
LTRACE() << qPrintable(name) << pix_;
#if 0
if (!pix_)
}
LTRACE() << "Loaded tesseract library" << lib.fileName();
auto ok = true;
ok &= bool(createApi_ = (CreateApi)lib.resolve("TessBaseAPICreate"));
ok &= bool(deleteApi_ = (DeleteApi)lib.resolve("TessBaseAPIDelete"));
ok &= bool(initApi_ = (InitApi)lib.resolve("TessBaseAPIInit2"));
ok &= bool(setImage_ = (SetImage)lib.resolve("TessBaseAPISetImage2"));
ok &= bool(getUtf8_ = (GetUtf8)lib.resolve("TessBaseAPIGetUTF8Text"));
ok &= bool(clearApi_ = (ClearApi)lib.resolve("TessBaseAPIClear"));
ok &= bool(deleteUtf8_ = (DeleteUtf8)lib.resolve("TessDeleteText"));
ok &= bool(setPageMode_ =
(SetPageMode)lib.resolve("TessBaseAPISetPageSegMode"));
if (!ok) {
LERROR() << "Failed to resolve tesseract functions from" << libraryName;
return;
auto fileName = name + ".png";
fileName.replace(' ', "_");
convertImage(*pix_).save(fileName);
#endif
}
handle_ = createApi_();
}
~Wrapper()
{
if (handle_ && deleteApi_) {
deleteApi_(handle_);
}
lib.unload();
}
int Init(const char *datapath, const char *language)
{
SOFT_ASSERT(handle_, return -1);
SOFT_ASSERT(initApi_, return -1);
const auto mode = 3; // TessOcrEngineMode::OEM_DEFAULT
return initApi_(handle_, datapath, language, mode);
}
QString GetText(Pix *pix)
{
SOFT_ASSERT(handle_, return {});
SOFT_ASSERT(setPageMode_, return {});
setPageMode_(handle_, 3); // PSM_AUTO
SOFT_ASSERT(setImage_, return {});
setImage_(handle_, pix);
LTRACE() << "Set Pix to engine";
char *outText = nullptr;
SOFT_ASSERT(getUtf8_, return {});
outText = getUtf8_(handle_);
LTRACE() << "Received recognized text";
SOFT_ASSERT(clearApi_, return {});
clearApi_(handle_);
LTRACE() << "Cleared engine";
const auto result = QString(outText).trimmed();
SOFT_ASSERT(deleteUtf8_, return {});
deleteUtf8_(outText);
LTRACE() << "Cleared recognized text buffer";
return result;
}
private:
Pix *pix_;
Q_DISABLE_COPY(PixGuard);
QLibrary lib;
CreateApi createApi_{nullptr};
DeleteApi deleteApi_{nullptr};
InitApi initApi_{nullptr};
SetImage setImage_{nullptr};
GetUtf8 getUtf8_{nullptr};
ClearApi clearApi_{nullptr};
DeleteUtf8 deleteUtf8_{nullptr};
SetPageMode setPageMode_{nullptr};
TessBaseAPI *handle_{nullptr};
};
static Pix *prepareImage(const QImage &image)
{
auto pix = PixGuard(convertImage(image));
SOFT_ASSERT(pix, return nullptr);
pix.trace("Pix 1 Converted");
{
pix = pixConvertRGBToGray(pix, 0.0, 0.0, 0.0);
pix.trace("Pix 2 Gray");
}
if (const auto scale = getScale(pix); scale > 1.0) {
pix = pixScaleGrayLI(pix, scale, scale);
pix.trace("Pix 3 Scaled");
}
l_int32 otsuSx = 5000;
l_int32 otsuSy = 5000;
l_int32 otsuSmoothx = 0;
l_int32 otsuSmoothy = 0;
l_float32 otsuScorefract = 0.1f;
{
PixGuard otsu;
pixOtsuAdaptiveThreshold(pix, otsuSx, otsuSy, otsuSmoothx, otsuSmoothy,
otsuScorefract, nullptr, &otsu.get());
pix.trace("Pix 4 Test Color Otsu");
// Get the average intensity of the border pixels,
// with average of 0.0 being completely white and 1.0 being completely black
// Top
auto avg = pixAverageOnLine(otsu, 0, 0, otsu->w - 1, 0, 1);
// Bottom
avg += pixAverageOnLine(otsu, 0, otsu->h - 1, otsu->w - 1, otsu->h - 1, 1);
// Left
avg += pixAverageOnLine(otsu, 0, 0, 0, otsu->h - 1, 1);
// Right
avg += pixAverageOnLine(otsu, otsu->w - 1, 0, otsu->w - 1, otsu->h - 1, 1);
avg /= 4.0f;
// If background is dark
l_float32 threshold = 0.5f;
if (avg > threshold) {
pix = pixInvert(nullptr, pix);
pix.trace("Pix 5 Inverted");
}
}
{
l_int32 usm_halfwidth = 5;
l_float32 usm_fract = 2.5f;
pix = pixUnsharpMaskingGray(pix, usm_halfwidth, usm_fract);
pix.trace("Pix 6 Unshapred");
}
{
pixOtsuAdaptiveThreshold(pix, otsuSx, otsuSy, otsuSmoothx, otsuSmoothy, 0.0,
nullptr, &pix.get());
pix.trace("Pix 7 Binarized");
}
pix.trace("Pix 8 Result");
return pix.take();
}
Tesseract::Tesseract(const LanguageId &language, const QString &tessdataPath)
Tesseract::Tesseract(const LanguageId &language, const QString &tessdataPath,
const QString &tesseractLibrary)
: tesseractLibrary_(tesseractLibrary)
{
SOFT_ASSERT(!tessdataPath.isEmpty(), return );
SOFT_ASSERT(!language.isEmpty(), return );
@ -217,22 +240,20 @@ Tesseract::~Tesseract() = default;
void Tesseract::init(const LanguageId &language, const QString &tessdataPath)
{
SOFT_ASSERT(!api_, return );
SOFT_ASSERT(!engine_, return );
api_ = std::make_unique<tesseract::TessBaseAPI>();
LTRACE() << "Created Tesseract api" << api_.get();
engine_ = std::make_unique<Wrapper>(tesseractLibrary_);
LTRACE() << "Created Tesseract api" << engine_.get();
const auto tesseractName = LanguageCodes::tesseract(language);
auto result = api_->Init(qPrintable(tessdataPath), qPrintable(tesseractName),
tesseract::OcrEngineMode::OEM_DEFAULT);
auto result =
engine_->Init(qPrintable(tessdataPath), qPrintable(tesseractName));
LTRACE() << "Inited Tesseract api" << result;
if (result == 0)
return;
api_->SetPageSegMode(tesseract::PageSegMode::PSM_AUTO);
error_ = QObject::tr("init failed");
api_.reset();
engine_.reset();
LTRACE() << "Cleared Tesseract api";
}
@ -267,28 +288,19 @@ QStringList Tesseract::availableLanguageNames(const QString &path)
QString Tesseract::recognize(const QPixmap &source)
{
SOFT_ASSERT(api_, return {});
SOFT_ASSERT(engine_, return {});
SOFT_ASSERT(!source.isNull(), return {});
error_.clear();
PixGuard image(prepareImage(source.toImage()));
Pix *image = prepareImage(source.toImage());
SOFT_ASSERT(image, return {});
LTRACE() << "Preprocessed Pix for OCR" << image;
api_->SetImage(image);
LTRACE() << "Set Pix to engine";
auto result = engine_->GetText(image);
const auto outText = api_->GetUTF8Text();
LTRACE() << "Received recognized text";
api_->Clear();
LTRACE() << "Cleared engine";
const auto result = QString(outText).trimmed();
delete[] outText;
LTRACE() << "Cleared recognized text buffer";
cleanupImage(&image);
LTRACE() << "Cleared preprocessed Pix";
if (result.isEmpty())
error_ = QObject::tr("Failed to recognize text or no text selected");
@ -297,5 +309,5 @@ QString Tesseract::recognize(const QPixmap &source)
bool Tesseract::isValid() const
{
return api_.get();
return engine_.get();
}

View File

@ -8,15 +8,12 @@
class QPixmap;
class Task;
namespace tesseract
{
class TessBaseAPI;
}
class Tesseract
{
public:
Tesseract(const LanguageId& language, const QString& tessdataPath);
Tesseract(const LanguageId& language, const QString& tessdataPath,
const QString& tesseractLibrary);
~Tesseract();
QString recognize(const QPixmap& source);
@ -26,8 +23,10 @@ public:
static QStringList availableLanguageNames(const QString& path);
private:
class Wrapper;
void init(const LanguageId& language, const QString& tessdataPath);
std::unique_ptr<tesseract::TessBaseAPI> api_;
const QString tesseractLibrary_;
std::unique_ptr<Wrapper> engine_;
QString error_;
};

View File

@ -896,6 +896,11 @@ QDateTime Updater::lastUpdateCheck() const
void Updater::setAutoUpdate(int intervalDays, const QDateTime &lastCheck)
{
if (intervalDays < 1) {
autoChecker_.reset();
return;
}
autoChecker_ = std::make_unique<AutoChecker>(*this, intervalDays, lastCheck);
}

View File

@ -35,6 +35,7 @@ const QString qs_showMessageOnStart = "showMessageOnStart";
const QString qs_recogntionGroup = "Recognition";
const QString qs_ocrLanguage = "language";
const QString qs_tesseractVersion = "tesseractVersion";
const QString qs_correctionGroup = "Correction";
const QString qs_userSubstitutions = "userSubstitutions";
@ -132,6 +133,36 @@ void cleanupOutdated(QSettings& settings)
settings.endGroup();
}
#ifdef _MSC_VER
#include <intrin.h>
void cpuid(int leaf, int subleaf, std::array<uint, 4>& cpuinfo)
{
__cpuidex(reinterpret_cast<int*>(cpuinfo.data()), leaf, subleaf);
}
#else
#include <cpuid.h>
void cpuid(int leaf, int subleaf, std::array<uint, 4>& cpuinfo)
{
__get_cpuid_count(leaf, subleaf, &cpuinfo[0], &cpuinfo[1], &cpuinfo[2],
&cpuinfo[3]);
}
#endif
bool checkOptimizedTesseractSupport()
{
std::array<uint, 4> cpuinfo{0};
cpuid(1, 0, cpuinfo);
const bool sse4_1 = cpuinfo[2] & (1 << 19);
const bool sse4_2 = cpuinfo[2] & (1 << 20);
const bool avx = cpuinfo[2] & (1 << 28);
cpuid(7, 0, cpuinfo);
const bool avx2 = cpuinfo[1] & (1 << 5);
return sse4_1 && sse4_2 && avx && avx2;
}
} // namespace
void Settings::save() const
@ -176,6 +207,7 @@ void Settings::save() const
settings.beginGroup(qs_recogntionGroup);
settings.setValue(qs_ocrLanguage, sourceLanguage);
settings.setValue(qs_tesseractVersion, int(tesseractVersion));
settings.endGroup();
settings.beginGroup(qs_correctionGroup);
@ -263,6 +295,15 @@ void Settings::load()
settings.beginGroup(qs_recogntionGroup);
sourceLanguage = settings.value(qs_ocrLanguage, sourceLanguage).toString();
if (!settings.contains(qs_tesseractVersion)) {
tesseractVersion = checkOptimizedTesseractSupport()
? TesseractVersion::Optimized
: TesseractVersion::Compatible;
} else {
tesseractVersion = TesseractVersion(std::clamp(
settings.value(qs_tesseractVersion, int(tesseractVersion)).toInt(),
int(TesseractVersion::Optimized), int(TesseractVersion::Compatible)));
}
settings.endGroup();
settings.beginGroup(qs_correctionGroup);

View File

@ -19,6 +19,8 @@ using Substitutions = std::multimap<LanguageId, Substitution>;
enum class ProxyType { Disabled, System, Socks5, Http };
enum class TesseractVersion { Optimized, Compatible };
class Settings
{
public:
@ -58,6 +60,7 @@ public:
QString tessdataPath;
QString sourceLanguage{"eng"};
TesseractVersion tesseractVersion{TesseractVersion::Optimized};
bool doTranslation{true};
bool ignoreSslErrors{false};

View File

@ -122,6 +122,14 @@ SettingsEditor::SettingsEditor(Manager &manager, update::Updater &updater)
// recognition
ui->tesseractLangCombo->setModel(models_.sourceLanguageModel());
const QMap<TesseractVersion, QString> tesseractVersions{
{TesseractVersion::Optimized, tr("Optimized")},
{TesseractVersion::Compatible, tr("Compatible")},
};
ui->tesseractVersion->addItems(tesseractVersions.values());
ui->tesseractVersion->setToolTip(
tr("Use compatible version if you are experiencing crashes during "
"recognition"));
// correction
ui->userSubstitutionsTable->setEnabled(ui->useUserSubstitutions->isChecked());
@ -183,15 +191,14 @@ SettingsEditor::SettingsEditor(Manager &manager, update::Updater &updater)
(locale.language() == QLocale::Russian ? "ru" : "en") + ".md";
const auto license = baseUrl + "/blob/master/LICENSE.md";
const auto help = locale.language() == QLocale::Russian
? "https://translator.gres.biz/page/download/"
: baseUrl + "/blob/master/README.md";
? "https://translator.gres.biz/page/download/"
: baseUrl + "/blob/master/README.md";
const auto aboutLines = QStringList{
QObject::tr(
R"(<p>Optical character recognition (OCR) and translation tool</p>)"),
QObject::tr(R"(<p>Version: %1</p>)")
.arg(QApplication::applicationVersion()),
QObject::tr(R"(<p>Setup instructions: <a href="%1">%1</a></p>)")
.arg(help),
QObject::tr(R"(<p>Setup instructions: <a href="%1">%1</a></p>)").arg(help),
QObject::tr(R"(<p>Changelog: <a href="%1">%2</a></p>)")
.arg(changelog, QUrl(changelog).fileName()),
QObject::tr(R"(<p>License: <a href="%3">MIT</a></p>)").arg(license),
@ -260,6 +267,8 @@ Settings SettingsEditor::settings() const
settings.sourceLanguage =
LanguageCodes::idForName(ui->tesseractLangCombo->currentText());
settings.tesseractVersion =
TesseractVersion(ui->tesseractVersion->currentIndex());
settings.useHunspell = ui->useHunspell->isChecked();
settings.useUserSubstitutions = ui->useUserSubstitutions->isChecked();
@ -319,6 +328,7 @@ void SettingsEditor::setSettings(const Settings &settings)
ui->tesseractLangCombo->setCurrentText(
LanguageCodes::name(settings.sourceLanguage));
ui->tesseractVersion->setCurrentIndex(int(settings.tesseractVersion));
ui->useHunspell->setChecked(settings.useHunspell);
ui->hunspellDir->setText(settings.hunspellPath);

View File

@ -221,7 +221,7 @@
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="4" column="1">
<widget class="service::KeySequenceEdit" name="clipboardEdit" native="true"/>
<widget class="service::KeySequenceEdit" name="clipboardEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
@ -231,7 +231,7 @@
</widget>
</item>
<item row="2" column="1">
<widget class="service::KeySequenceEdit" name="repeatCaptureEdit" native="true"/>
<widget class="service::KeySequenceEdit" name="repeatCaptureEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_3">
@ -241,7 +241,7 @@
</widget>
</item>
<item row="0" column="1">
<widget class="service::KeySequenceEdit" name="captureEdit" native="true"/>
<widget class="service::KeySequenceEdit" name="captureEdit"/>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_7">
@ -251,7 +251,7 @@
</widget>
</item>
<item row="3" column="1">
<widget class="service::KeySequenceEdit" name="repeatEdit" native="true"/>
<widget class="service::KeySequenceEdit" name="repeatEdit"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
@ -268,7 +268,7 @@
</widget>
</item>
<item row="1" column="1">
<widget class="service::KeySequenceEdit" name="captureLockedEdit" native="true"/>
<widget class="service::KeySequenceEdit" name="captureLockedEdit"/>
</item>
</layout>
</widget>
@ -291,23 +291,7 @@
</widget>
<widget class="QWidget" name="pageRecognize">
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Tessdata path:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="tesseractLangCombo"/>
</item>
<item row="2" column="2">
<item row="3" column="2">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -333,6 +317,19 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Tessdata path:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
@ -349,6 +346,19 @@
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="tesseractLangCombo"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_24">
<property name="text">
<string>Library version</string>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QComboBox" name="tesseractVersion"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="pageCorrect">

View File

@ -4,16 +4,8 @@ var active = window.location.href !== "about:blank";
function checkFinished() {
if (!active) return;
let area = document.querySelector('div#target-dummydiv');
let text = area ? area.innerHTML.trim() : '';
if (area == null) {
area = document.querySelector('d-textarea.lmt__target_textarea p');
text = area ? area.innerText.trim() : '';
}
if (area == null) {
area = document.querySelector('d-textarea[data-testid=translator-target-input] p');
text = area ? area.innerText.trim() : '';
}
let area = document.querySelector('textarea[dl-test=translator-target-input]');
let text = area ? area.value : '';
if (text === lastText || text === '')
return;
@ -28,16 +20,14 @@ function translate(text, from, to) {
console.log('start translate', text, from, to)
if (text.trim().length == 0) {
proxy.setTranslated('');
return;
proxy.setTranslated('');
return;
}
from = from == 'zh-CN' ? 'zh' : from;
to = to == 'zh-CN' ? 'zh' : to;
let supported = ['ru', 'en', 'de', 'fr', 'es', 'pt', 'it', 'nl', 'pl', 'ja', 'zh',
'uk', 'bg', 'hu', 'el', 'da', 'id', 'lt', 'pt', 'ro', 'sk', 'sk', 'tr', 'fi', 'cs',
'sv', 'et']
let supported = ['ru', 'en', 'de', 'fr', 'es', 'pt', 'it', 'nl', 'pl', 'ja', 'zh']
if (supported.indexOf(from) == -1) {
proxy.setFailed('Source language not supported');
return;
@ -49,32 +39,21 @@ function translate(text, from, to) {
active = true;
var singleLineText = text.replace(/(?:\r\n|\r|\n)/g, ' ');
let langs = from + '/' + to + '/';
if (window.location.href.indexOf('www.deepl.com/translator') !== -1
&& window.location.href.indexOf(langs) !== -1) {
var input = document.querySelector('d-textarea[dl-test=translator-source-input] p');
if (input == null)
input = document.querySelector('d-textarea.lmt__source_textarea p');
if (input == null)
input = document.querySelector('d-textarea[data-testid=translator-source-input] p');
if (input.innerText == singleLineText) {
console.log('using cached result');
lastText = '';
return;
var input = document.querySelector('textarea[dl-test=translator-source-input]');
if (input.value == text) {
console.log('using cached result');
lastText = '';
return;
}
input.innerText = singleLineText;
if (areaCopy = document.querySelector('div#source-dummydiv'))
areaCopy.innerHTML = singleLineText;
setTimeout(function () {
input.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
}, 300);
input.value = text;
input.dispatchEvent(new Event("input", { bubbles: true, cancelable: true }));
return;
}
let url = 'https://www.deepl.com/translator#' + langs + encodeURIComponent(singleLineText);
let url = 'https://www.deepl.com/translator#' + langs + encodeURIComponent(text);
console.log("setting url", url);
window.location = url;
}

View File

@ -4,7 +4,7 @@ var active = window.location.href !== "about:blank";
function checkFinished() {
if (!active) return;
let spans = [].slice.call(document.querySelectorAll('span.HwtZe > span > span'));
let spans = [].slice.call(document.querySelectorAll('span.VIiyi > span > span'));
let text = spans.reduce(function (res, i) {
return res + ' ' + i.innerText;
}, '');

View File

@ -4,9 +4,9 @@ var active = window.location.href !== "about:blank";
function checkFinished() {
if (!active) return;
let spans = [].slice.call(document.querySelectorAll('span.translation-word'));
let spans = [].slice.call(document.querySelectorAll('span.translation-chunk'));
let text = spans.reduce(function (res, i) {
return res + i.innerText;
return res + ' ' + i.innerText;
}, '').trim();
if (text === lastText || text === '')

View File

@ -2,9 +2,9 @@
"version":1
,"app":{
"win32":{"version":"3.3.0", "host":"win32", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"414c74c4594e0b90aff3cd86a73f96dd"}]}
,"win64":{"version":"3.3.0", "host":"win64", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"3f2c3c27364f25c239ea63243a8910a3"}]}
,"linux":{"version":"3.3.0", "host":"linux", "files":[{"path":"$appdir$/screen-translator", "md5":"a091be0443fd128a02b01b313e0270bc"}]}
"win32":{"version":"3.2.2", "host":"win32", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"e7113757a8e5fe68ba87d0d7c5069450"}]}
,"win64":{"version":"3.2.2", "host":"win64", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"4187fc91d7a5d26c916692d890ad171b"}]}
,"linux":{"version":"3.2.2", "host":"linux", "files":[{"path":"$appdir$/screen-translator", "md5":"ceb69232a200ac28d4535ae5a15706a7"}]}
}
@ -387,200 +387,188 @@
,"correction": {
"Afrikaans":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/af_ZA/af_ZA.aff","https://translator.gres.biz/resources/dictionaries/af_ZA/af_ZA.aff.zip"], "path":"$hunspell$/af/af_ZA.aff", "date":"2020-02-16T20:22:16+01:00", "size":5027}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/af_ZA/af_ZA.dic","https://translator.gres.biz/resources/dictionaries/af_ZA/af_ZA.dic.zip"], "path":"$hunspell$/af/af_ZA.dic", "date":"2020-02-16T20:22:16+01:00", "size":1262203}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/af_ZA/af_ZA.aff","https://translator.gres.biz/resources/dictionaries/af_ZA/af_ZA.aff.zip"], "path":"$hunspell$/af/af_ZA.aff", "date":"2020-03-17T12:21:16+01:00", "size":5027}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/af_ZA/af_ZA.dic","https://translator.gres.biz/resources/dictionaries/af_ZA/af_ZA.dic.zip"], "path":"$hunspell$/af/af_ZA.dic", "date":"2020-03-17T12:21:16+01:00", "size":1262203}
]}
, "Arabic":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ar/ar.aff","https://translator.gres.biz/resources/dictionaries/ar/ar.aff.zip"], "path":"$hunspell$/ar/ar.aff", "date":"2018-02-04T21:34:12+01:00", "size":86949}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ar/ar.dic","https://translator.gres.biz/resources/dictionaries/ar/ar.dic.zip"], "path":"$hunspell$/ar/ar.dic", "date":"2019-03-07T11:32:58+01:00", "size":7217161}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ar/ar.aff","https://translator.gres.biz/resources/dictionaries/ar/ar.aff.zip"], "path":"$hunspell$/ar/ar.aff", "date":"2020-03-17T12:21:16+01:00", "size":86949}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ar/ar.dic","https://translator.gres.biz/resources/dictionaries/ar/ar.dic.zip"], "path":"$hunspell$/ar/ar.dic", "date":"2020-03-17T12:21:16+01:00", "size":7217161}
]}
, "Belarusian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/be_BY/be-official.aff","https://translator.gres.biz/resources/dictionaries/be_BY/be-official.aff.zip"], "path":"$hunspell$/be/be-official.aff", "date":"2021-09-27T10:14:30+02:00", "size":183480}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/be_BY/be-official.dic","https://translator.gres.biz/resources/dictionaries/be_BY/be-official.dic.zip"], "path":"$hunspell$/be/be-official.dic", "date":"2021-09-27T10:14:30+02:00", "size":9355556}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/be_BY/be_BY.aff","https://translator.gres.biz/resources/dictionaries/be_BY/be_BY.aff.zip"], "path":"$hunspell$/be/be_BY.aff", "date":"2020-03-17T12:21:16+01:00", "size":23968}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/be_BY/be_BY.dic","https://translator.gres.biz/resources/dictionaries/be_BY/be_BY.dic.zip"], "path":"$hunspell$/be/be_BY.dic", "date":"2020-03-17T12:21:16+01:00", "size":1707840}
]}
, "Bulgarian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bg_BG/bg_BG.aff","https://translator.gres.biz/resources/dictionaries/bg_BG/bg_BG.aff.zip"], "path":"$hunspell$/bg/bg_BG.aff", "date":"2018-06-29T12:25:29+02:00", "size":58189}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bg_BG/bg_BG.dic","https://translator.gres.biz/resources/dictionaries/bg_BG/bg_BG.dic.zip"], "path":"$hunspell$/bg/bg_BG.dic", "date":"2018-06-29T12:25:29+02:00", "size":1566331}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bg_BG/bg_BG.aff","https://translator.gres.biz/resources/dictionaries/bg_BG/bg_BG.aff.zip"], "path":"$hunspell$/bg/bg_BG.aff", "date":"2020-03-17T12:21:16+01:00", "size":58189}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bg_BG/bg_BG.dic","https://translator.gres.biz/resources/dictionaries/bg_BG/bg_BG.dic.zip"], "path":"$hunspell$/bg/bg_BG.dic", "date":"2020-03-17T12:21:16+01:00", "size":1566331}
]}
, "Bengali":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bn_BD/bn_BD.aff","https://translator.gres.biz/resources/dictionaries/bn_BD/bn_BD.aff.zip"], "path":"$hunspell$/bn/bn_BD.aff", "date":"2012-10-16T11:09:27-05:00", "size":195}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bn_BD/bn_BD.dic","https://translator.gres.biz/resources/dictionaries/bn_BD/bn_BD.dic.zip"], "path":"$hunspell$/bn/bn_BD.dic", "date":"2012-10-16T11:09:27-05:00", "size":2596038}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bn_BD/bn_BD.aff","https://translator.gres.biz/resources/dictionaries/bn_BD/bn_BD.aff.zip"], "path":"$hunspell$/bn/bn_BD.aff", "date":"2020-03-17T12:21:16+01:00", "size":195}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bn_BD/bn_BD.dic","https://translator.gres.biz/resources/dictionaries/bn_BD/bn_BD.dic.zip"], "path":"$hunspell$/bn/bn_BD.dic", "date":"2020-03-17T12:21:16+01:00", "size":2596038}
]}
, "Tibetan":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bo/bo.aff","https://translator.gres.biz/resources/dictionaries/bo/bo.aff.zip"], "path":"$hunspell$/bo/bo.aff", "date":"2016-11-22T22:23:34+00:00", "size":1706}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bo/bo.dic","https://translator.gres.biz/resources/dictionaries/bo/bo.dic.zip"], "path":"$hunspell$/bo/bo.dic", "date":"2017-10-23T18:37:13+02:00", "size":4637}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bo/bo.aff","https://translator.gres.biz/resources/dictionaries/bo/bo.aff.zip"], "path":"$hunspell$/bo/bo.aff", "date":"2020-03-17T12:21:16+01:00", "size":1706}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bo/bo.dic","https://translator.gres.biz/resources/dictionaries/bo/bo.dic.zip"], "path":"$hunspell$/bo/bo.dic", "date":"2020-03-17T12:21:16+01:00", "size":4637}
]}
, "Bosnian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bs_BA/bs_BA.aff","https://translator.gres.biz/resources/dictionaries/bs_BA/bs_BA.aff.zip"], "path":"$hunspell$/bs/bs_BA.aff", "date":"2013-01-22T17:32:09+01:00", "size":17468}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bs_BA/bs_BA.dic","https://translator.gres.biz/resources/dictionaries/bs_BA/bs_BA.dic.zip"], "path":"$hunspell$/bs/bs_BA.dic", "date":"2013-01-22T17:32:09+01:00", "size":339863}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bs_BA/bs_BA.aff","https://translator.gres.biz/resources/dictionaries/bs_BA/bs_BA.aff.zip"], "path":"$hunspell$/bs/bs_BA.aff", "date":"2020-03-17T12:21:16+01:00", "size":17468}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/bs_BA/bs_BA.dic","https://translator.gres.biz/resources/dictionaries/bs_BA/bs_BA.dic.zip"], "path":"$hunspell$/bs/bs_BA.dic", "date":"2020-03-17T12:21:16+01:00", "size":339863}
]}
, "Czech":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/cs_CZ/cs_CZ.aff","https://translator.gres.biz/resources/dictionaries/cs_CZ/cs_CZ.aff.zip"], "path":"$hunspell$/cs/cs_CZ.aff", "date":"2021-07-01T19:25:44+02:00", "size":111575}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/cs_CZ/cs_CZ.dic","https://translator.gres.biz/resources/dictionaries/cs_CZ/cs_CZ.dic.zip"], "path":"$hunspell$/cs/cs_CZ.dic", "date":"2021-07-28T19:02:59+02:00", "size":3656362}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/cs_CZ/cs_CZ.aff","https://translator.gres.biz/resources/dictionaries/cs_CZ/cs_CZ.aff.zip"], "path":"$hunspell$/cs/cs_CZ.aff", "date":"2020-03-17T12:21:16+01:00", "size":97286}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/cs_CZ/cs_CZ.dic","https://translator.gres.biz/resources/dictionaries/cs_CZ/cs_CZ.dic.zip"], "path":"$hunspell$/cs/cs_CZ.dic", "date":"2020-03-17T12:21:16+01:00", "size":2209232}
]}
, "Danish":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/da_DK/da_DK.aff","https://translator.gres.biz/resources/dictionaries/da_DK/da_DK.aff.zip"], "path":"$hunspell$/da/da_DK.aff", "date":"2022-06-09T11:42:30+02:00", "size":79054}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/da_DK/da_DK.dic","https://translator.gres.biz/resources/dictionaries/da_DK/da_DK.dic.zip"], "path":"$hunspell$/da/da_DK.dic", "date":"2022-06-09T11:42:30+02:00", "size":3514463}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/da_DK/da_DK.aff","https://translator.gres.biz/resources/dictionaries/da_DK/da_DK.aff.zip"], "path":"$hunspell$/da/da_DK.aff", "date":"2020-03-17T12:21:16+01:00", "size":55779}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/da_DK/da_DK.dic","https://translator.gres.biz/resources/dictionaries/da_DK/da_DK.dic.zip"], "path":"$hunspell$/da/da_DK.dic", "date":"2020-03-17T12:21:16+01:00", "size":2915525}
]}
, "German":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/de/de_DE_frami.aff","https://translator.gres.biz/resources/dictionaries/de/de_DE_frami.aff.zip"], "path":"$hunspell$/de/de_DE_frami.aff", "date":"2022-09-23T10:52:56+02:00", "size":19067}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/de/de_DE_frami.dic","https://translator.gres.biz/resources/dictionaries/de/de_DE_frami.dic.zip"], "path":"$hunspell$/de/de_DE_frami.dic", "date":"2017-01-22T19:03:05+00:00", "size":4356858}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/de/de_DE_frami.aff","https://translator.gres.biz/resources/dictionaries/de/de_DE_frami.aff.zip"], "path":"$hunspell$/de/de_DE_frami.aff", "date":"2020-03-17T12:21:16+01:00", "size":18991}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/de/de_DE_frami.dic","https://translator.gres.biz/resources/dictionaries/de/de_DE_frami.dic.zip"], "path":"$hunspell$/de/de_DE_frami.dic", "date":"2020-03-17T12:21:16+01:00", "size":4356858}
]}
, "Greek":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/el_GR/el_GR.aff","https://translator.gres.biz/resources/dictionaries/el_GR/el_GR.aff.zip"], "path":"$hunspell$/el/el_GR.aff", "date":"2015-09-21T17:56:43+02:00", "size":15647}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/el_GR/el_GR.dic","https://translator.gres.biz/resources/dictionaries/el_GR/el_GR.dic.zip"], "path":"$hunspell$/el/el_GR.dic", "date":"2015-09-21T17:56:43+02:00", "size":10125390}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/el_GR/el_GR.aff","https://translator.gres.biz/resources/dictionaries/el_GR/el_GR.aff.zip"], "path":"$hunspell$/el/el_GR.aff", "date":"2020-03-17T12:21:16+01:00", "size":15647}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/el_GR/el_GR.dic","https://translator.gres.biz/resources/dictionaries/el_GR/el_GR.dic.zip"], "path":"$hunspell$/el/el_GR.dic", "date":"2020-03-17T12:21:16+01:00", "size":10125390}
]}
, "English":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/en/en_US.aff","https://translator.gres.biz/resources/dictionaries/en/en_US.aff.zip"], "path":"$hunspell$/en/en_US.aff", "date":"2018-05-15T00:49:14+02:00", "size":3090}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/en/en_US.dic","https://translator.gres.biz/resources/dictionaries/en/en_US.dic.zip"], "path":"$hunspell$/en/en_US.dic", "date":"2021-05-12T15:36:00+02:00", "size":551762}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/en/en_US.aff","https://translator.gres.biz/resources/dictionaries/en/en_US.aff.zip"], "path":"$hunspell$/en/en_US.aff", "date":"2020-03-17T12:21:16+01:00", "size":3090}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/en/en_US.dic","https://translator.gres.biz/resources/dictionaries/en/en_US.dic.zip"], "path":"$hunspell$/en/en_US.dic", "date":"2020-03-17T12:21:16+01:00", "size":551260}
]}
, "Esperanto":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/eo/eo.aff","https://translator.gres.biz/resources/dictionaries/eo/eo.aff.zip"], "path":"$hunspell$/eo/eo.aff", "date":"2021-04-11T10:01:47+02:00", "size":19129}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/eo/eo.dic","https://translator.gres.biz/resources/dictionaries/eo/eo.dic.zip"], "path":"$hunspell$/eo/eo.dic", "date":"2021-04-11T10:01:47+02:00", "size":377989}
, "Spanish":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/es/es_ANY.aff","https://translator.gres.biz/resources/dictionaries/es/es_ANY.aff.zip"], "path":"$hunspell$/es/es_ANY.aff", "date":"2020-03-17T12:21:16+01:00", "size":169377}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/es/es_ANY.dic","https://translator.gres.biz/resources/dictionaries/es/es_ANY.dic.zip"], "path":"$hunspell$/es/es_ANY.dic", "date":"2020-03-17T12:21:16+01:00", "size":804058}
]}
, "Estonian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/et_EE/et_EE.aff","https://translator.gres.biz/resources/dictionaries/et_EE/et_EE.aff.zip"], "path":"$hunspell$/et/et_EE.aff", "date":"2012-10-16T11:09:27-05:00", "size":236336}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/et_EE/et_EE.dic","https://translator.gres.biz/resources/dictionaries/et_EE/et_EE.dic.zip"], "path":"$hunspell$/et/et_EE.dic", "date":"2012-10-16T11:09:27-05:00", "size":4383841}
]}
, "Persian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/fa_IR/fa-IR.aff","https://translator.gres.biz/resources/dictionaries/fa_IR/fa-IR.aff.zip"], "path":"$hunspell$/fa/fa-IR.aff", "date":"2022-08-27T17:55:37+02:00", "size":5439}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/fa_IR/fa-IR.dic","https://translator.gres.biz/resources/dictionaries/fa_IR/fa-IR.dic.zip"], "path":"$hunspell$/fa/fa-IR.dic", "date":"2022-08-27T17:55:37+02:00", "size":2575990}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/et_EE/et_EE.aff","https://translator.gres.biz/resources/dictionaries/et_EE/et_EE.aff.zip"], "path":"$hunspell$/et/et_EE.aff", "date":"2020-03-17T12:21:16+01:00", "size":236336}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/et_EE/et_EE.dic","https://translator.gres.biz/resources/dictionaries/et_EE/et_EE.dic.zip"], "path":"$hunspell$/et/et_EE.dic", "date":"2020-03-17T12:21:16+01:00", "size":4383841}
]}
, "French":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/fr_FR/fr.aff","https://translator.gres.biz/resources/dictionaries/fr_FR/fr.aff.zip"], "path":"$hunspell$/fr/fr.aff", "date":"2020-12-22T09:23:57+01:00", "size":201591}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/fr_FR/fr.dic","https://translator.gres.biz/resources/dictionaries/fr_FR/fr.dic.zip"], "path":"$hunspell$/fr/fr.dic", "date":"2020-12-22T09:23:57+01:00", "size":1227095}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/fr_FR/fr.aff","https://translator.gres.biz/resources/dictionaries/fr_FR/fr.aff.zip"], "path":"$hunspell$/fr/fr.aff", "date":"2020-03-17T12:21:16+01:00", "size":256857}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/fr_FR/fr.dic","https://translator.gres.biz/resources/dictionaries/fr_FR/fr.dic.zip"], "path":"$hunspell$/fr/fr.dic", "date":"2020-03-17T12:21:16+01:00", "size":1100397}
]}
, "Gaelic":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gd_GB/gd_GB.aff","https://translator.gres.biz/resources/dictionaries/gd_GB/gd_GB.aff.zip"], "path":"$hunspell$/gd/gd_GB.aff", "date":"2017-06-22T00:27:25+02:00", "size":8228}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gd_GB/gd_GB.dic","https://translator.gres.biz/resources/dictionaries/gd_GB/gd_GB.dic.zip"], "path":"$hunspell$/gd/gd_GB.dic", "date":"2017-06-22T00:27:25+02:00", "size":4806682}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gd_GB/gd_GB.aff","https://translator.gres.biz/resources/dictionaries/gd_GB/gd_GB.aff.zip"], "path":"$hunspell$/gd/gd_GB.aff", "date":"2020-03-17T12:21:16+01:00", "size":8228}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gd_GB/gd_GB.dic","https://translator.gres.biz/resources/dictionaries/gd_GB/gd_GB.dic.zip"], "path":"$hunspell$/gd/gd_GB.dic", "date":"2020-03-17T12:21:16+01:00", "size":4806682}
]}
, "Galician":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gl/gl_ES.aff","https://translator.gres.biz/resources/dictionaries/gl/gl_ES.aff.zip"], "path":"$hunspell$/gl/gl_ES.aff", "date":"2021-07-26T16:31:04+02:00", "size":1163541}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gl/gl_ES.dic","https://translator.gres.biz/resources/dictionaries/gl/gl_ES.dic.zip"], "path":"$hunspell$/gl/gl_ES.dic", "date":"2021-07-26T16:31:04+02:00", "size":8325262}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gl/gl_ES.aff","https://translator.gres.biz/resources/dictionaries/gl/gl_ES.aff.zip"], "path":"$hunspell$/gl/gl_ES.aff", "date":"2020-03-17T12:21:16+01:00", "size":1159910}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gl/gl_ES.dic","https://translator.gres.biz/resources/dictionaries/gl/gl_ES.dic.zip"], "path":"$hunspell$/gl/gl_ES.dic", "date":"2020-03-17T12:21:16+01:00", "size":8636406}
]}
, "Gujarati":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gu_IN/gu_IN.aff","https://translator.gres.biz/resources/dictionaries/gu_IN/gu_IN.aff.zip"], "path":"$hunspell$/gu/gu_IN.aff", "date":"2012-10-16T11:09:27-05:00", "size":174}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gu_IN/gu_IN.dic","https://translator.gres.biz/resources/dictionaries/gu_IN/gu_IN.dic.zip"], "path":"$hunspell$/gu/gu_IN.dic", "date":"2012-10-16T11:09:27-05:00", "size":3792870}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gu_IN/gu_IN.aff","https://translator.gres.biz/resources/dictionaries/gu_IN/gu_IN.aff.zip"], "path":"$hunspell$/gu/gu_IN.aff", "date":"2020-03-17T12:21:16+01:00", "size":174}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/gu_IN/gu_IN.dic","https://translator.gres.biz/resources/dictionaries/gu_IN/gu_IN.dic.zip"], "path":"$hunspell$/gu/gu_IN.dic", "date":"2020-03-17T12:21:16+01:00", "size":3792870}
]}
, "Hebrew":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/he_IL/he_IL.aff","https://translator.gres.biz/resources/dictionaries/he_IL/he_IL.aff.zip"], "path":"$hunspell$/he/he_IL.aff", "date":"2017-09-05T18:11:31+02:00", "size":78883}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/he_IL/he_IL.dic","https://translator.gres.biz/resources/dictionaries/he_IL/he_IL.dic.zip"], "path":"$hunspell$/he/he_IL.dic", "date":"2017-09-05T18:11:31+02:00", "size":7796259}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/he_IL/he_IL.aff","https://translator.gres.biz/resources/dictionaries/he_IL/he_IL.aff.zip"], "path":"$hunspell$/he/he_IL.aff", "date":"2020-03-17T12:21:16+01:00", "size":78883}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/he_IL/he_IL.dic","https://translator.gres.biz/resources/dictionaries/he_IL/he_IL.dic.zip"], "path":"$hunspell$/he/he_IL.dic", "date":"2020-03-17T12:21:16+01:00", "size":7796259}
]}
, "Hindi":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hi_IN/hi_IN.aff","https://translator.gres.biz/resources/dictionaries/hi_IN/hi_IN.aff.zip"], "path":"$hunspell$/hi/hi_IN.aff", "date":"2012-10-16T11:09:27-05:00", "size":210}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hi_IN/hi_IN.dic","https://translator.gres.biz/resources/dictionaries/hi_IN/hi_IN.dic.zip"], "path":"$hunspell$/hi/hi_IN.dic", "date":"2012-10-16T11:09:27-05:00", "size":303963}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hi_IN/hi_IN.aff","https://translator.gres.biz/resources/dictionaries/hi_IN/hi_IN.aff.zip"], "path":"$hunspell$/hi/hi_IN.aff", "date":"2020-03-17T12:21:16+01:00", "size":210}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hi_IN/hi_IN.dic","https://translator.gres.biz/resources/dictionaries/hi_IN/hi_IN.dic.zip"], "path":"$hunspell$/hi/hi_IN.dic", "date":"2020-03-17T12:21:16+01:00", "size":303963}
]}
, "Croatian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hr_HR/hr_HR.aff","https://translator.gres.biz/resources/dictionaries/hr_HR/hr_HR.aff.zip"], "path":"$hunspell$/hr/hr_HR.aff", "date":"2018-05-29T22:11:06+02:00", "size":95802}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hr_HR/hr_HR.dic","https://translator.gres.biz/resources/dictionaries/hr_HR/hr_HR.dic.zip"], "path":"$hunspell$/hr/hr_HR.dic", "date":"2018-05-29T22:11:06+02:00", "size":731819}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hr_HR/hr_HR.aff","https://translator.gres.biz/resources/dictionaries/hr_HR/hr_HR.aff.zip"], "path":"$hunspell$/hr/hr_HR.aff", "date":"2020-03-17T12:21:16+01:00", "size":95802}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hr_HR/hr_HR.dic","https://translator.gres.biz/resources/dictionaries/hr_HR/hr_HR.dic.zip"], "path":"$hunspell$/hr/hr_HR.dic", "date":"2020-03-17T12:21:16+01:00", "size":731819}
]}
, "Hungarian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hu_HU/hu_HU.aff","https://translator.gres.biz/resources/dictionaries/hu_HU/hu_HU.aff.zip"], "path":"$hunspell$/hu/hu_HU.aff", "date":"2018-05-22T22:26:58+02:00", "size":2106214}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hu_HU/hu_HU.dic","https://translator.gres.biz/resources/dictionaries/hu_HU/hu_HU.dic.zip"], "path":"$hunspell$/hu/hu_HU.dic", "date":"2018-05-22T22:26:58+02:00", "size":1653155}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hu_HU/hu_HU.aff","https://translator.gres.biz/resources/dictionaries/hu_HU/hu_HU.aff.zip"], "path":"$hunspell$/hu/hu_HU.aff", "date":"2020-03-17T12:21:16+01:00", "size":2106214}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/hu_HU/hu_HU.dic","https://translator.gres.biz/resources/dictionaries/hu_HU/hu_HU.dic.zip"], "path":"$hunspell$/hu/hu_HU.dic", "date":"2020-03-17T12:21:16+01:00", "size":1653155}
]}
, "Indonesian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/id/id_ID.aff","https://translator.gres.biz/resources/dictionaries/id/id_ID.aff.zip"], "path":"$hunspell$/id/id_ID.aff", "date":"2018-02-28T01:40:08+01:00", "size":14957}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/id/id_ID.dic","https://translator.gres.biz/resources/dictionaries/id/id_ID.dic.zip"], "path":"$hunspell$/id/id_ID.dic", "date":"2018-02-28T01:40:08+01:00", "size":315384}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/id/id_ID.aff","https://translator.gres.biz/resources/dictionaries/id/id_ID.aff.zip"], "path":"$hunspell$/id/id_ID.aff", "date":"2020-03-17T12:21:16+01:00", "size":14957}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/id/id_ID.dic","https://translator.gres.biz/resources/dictionaries/id/id_ID.dic.zip"], "path":"$hunspell$/id/id_ID.dic", "date":"2020-03-17T12:21:16+01:00", "size":315384}
]}
, "Icelandic":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/is/is.aff","https://translator.gres.biz/resources/dictionaries/is/is.aff.zip"], "path":"$hunspell$/is/is.aff", "date":"2016-03-14T09:05:09+00:00", "size":309734}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/is/is.dic","https://translator.gres.biz/resources/dictionaries/is/is.dic.zip"], "path":"$hunspell$/is/is.dic", "date":"2016-03-14T09:05:09+00:00", "size":2454138}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/is/is.aff","https://translator.gres.biz/resources/dictionaries/is/is.aff.zip"], "path":"$hunspell$/is/is.aff", "date":"2020-03-17T12:21:16+01:00", "size":309734}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/is/is.dic","https://translator.gres.biz/resources/dictionaries/is/is.dic.zip"], "path":"$hunspell$/is/is.dic", "date":"2020-03-17T12:21:16+01:00", "size":2454138}
]}
, "Italian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/it_IT/it_IT.aff","https://translator.gres.biz/resources/dictionaries/it_IT/it_IT.aff.zip"], "path":"$hunspell$/it/it_IT.aff", "date":"2020-10-28T10:37:21+01:00", "size":70054}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/it_IT/it_IT.dic","https://translator.gres.biz/resources/dictionaries/it_IT/it_IT.dic.zip"], "path":"$hunspell$/it/it_IT.dic", "date":"2021-01-20T09:47:03+01:00", "size":1295078}
]}
, "Korean":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ko_KR/ko_KR.aff","https://translator.gres.biz/resources/dictionaries/ko_KR/ko_KR.aff.zip"], "path":"$hunspell$/ko/ko_KR.aff", "date":"2020-10-28T10:46:18+01:00", "size":11094418}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ko_KR/ko_KR.dic","https://translator.gres.biz/resources/dictionaries/ko_KR/ko_KR.dic.zip"], "path":"$hunspell$/ko/ko_KR.dic", "date":"2020-10-28T10:46:18+01:00", "size":2862610}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/it_IT/it_IT.aff","https://translator.gres.biz/resources/dictionaries/it_IT/it_IT.aff.zip"], "path":"$hunspell$/it/it_IT.aff", "date":"2020-03-17T12:21:16+01:00", "size":80216}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/it_IT/it_IT.dic","https://translator.gres.biz/resources/dictionaries/it_IT/it_IT.dic.zip"], "path":"$hunspell$/it/it_IT.dic", "date":"2020-03-17T12:21:16+01:00", "size":1290681}
]}
, "Lao":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lo_LA/lo_LA.aff","https://translator.gres.biz/resources/dictionaries/lo_LA/lo_LA.aff.zip"], "path":"$hunspell$/lo/lo_LA.aff", "date":"2013-11-24T19:21:08+01:00", "size":10}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lo_LA/lo_LA.dic","https://translator.gres.biz/resources/dictionaries/lo_LA/lo_LA.dic.zip"], "path":"$hunspell$/lo/lo_LA.dic", "date":"2021-05-11T15:56:42+02:00", "size":671495}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lo_LA/lo_LA.aff","https://translator.gres.biz/resources/dictionaries/lo_LA/lo_LA.aff.zip"], "path":"$hunspell$/lo/lo_LA.aff", "date":"2020-03-17T12:21:16+01:00", "size":10}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lo_LA/lo_LA.dic","https://translator.gres.biz/resources/dictionaries/lo_LA/lo_LA.dic.zip"], "path":"$hunspell$/lo/lo_LA.dic", "date":"2020-03-17T12:21:16+01:00", "size":203209}
]}
, "Lithuanian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lt_LT/lt.aff","https://translator.gres.biz/resources/dictionaries/lt_LT/lt.aff.zip"], "path":"$hunspell$/lt/lt.aff", "date":"2013-01-23T11:35:37+00:00", "size":92208}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lt_LT/lt.dic","https://translator.gres.biz/resources/dictionaries/lt_LT/lt.dic.zip"], "path":"$hunspell$/lt/lt.dic", "date":"2013-01-23T11:35:37+00:00", "size":1085291}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lt_LT/lt.aff","https://translator.gres.biz/resources/dictionaries/lt_LT/lt.aff.zip"], "path":"$hunspell$/lt/lt.aff", "date":"2020-03-17T12:21:16+01:00", "size":92208}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lt_LT/lt.dic","https://translator.gres.biz/resources/dictionaries/lt_LT/lt.dic.zip"], "path":"$hunspell$/lt/lt.dic", "date":"2020-03-17T12:21:16+01:00", "size":1085291}
]}
, "Latvian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lv_LV/lv_LV.aff","https://translator.gres.biz/resources/dictionaries/lv_LV/lv_LV.aff.zip"], "path":"$hunspell$/lv/lv_LV.aff", "date":"2020-05-24T12:13:08+02:00", "size":130475}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lv_LV/lv_LV.dic","https://translator.gres.biz/resources/dictionaries/lv_LV/lv_LV.dic.zip"], "path":"$hunspell$/lv/lv_LV.dic", "date":"2020-05-24T12:13:08+02:00", "size":1844831}
]}
, "Mongolian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/mn_MN/mn_MN.aff","https://translator.gres.biz/resources/dictionaries/mn_MN/mn_MN.aff.zip"], "path":"$hunspell$/mn/mn_MN.aff", "date":"2022-04-18T07:06:27+02:00", "size":398455}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/mn_MN/mn_MN.dic","https://translator.gres.biz/resources/dictionaries/mn_MN/mn_MN.dic.zip"], "path":"$hunspell$/mn/mn_MN.dic", "date":"2022-04-18T07:06:27+02:00", "size":16650918}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lv_LV/lv_LV.aff","https://translator.gres.biz/resources/dictionaries/lv_LV/lv_LV.aff.zip"], "path":"$hunspell$/lv/lv_LV.aff", "date":"2020-03-17T12:21:16+01:00", "size":69597}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/lv_LV/lv_LV.dic","https://translator.gres.biz/resources/dictionaries/lv_LV/lv_LV.dic.zip"], "path":"$hunspell$/lv/lv_LV.dic", "date":"2020-03-17T12:21:16+01:00", "size":2226834}
]}
, "Nepali":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ne_NP/ne_NP.aff","https://translator.gres.biz/resources/dictionaries/ne_NP/ne_NP.aff.zip"], "path":"$hunspell$/ne/ne_NP.aff", "date":"2012-10-16T11:09:27-05:00", "size":14162}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ne_NP/ne_NP.dic","https://translator.gres.biz/resources/dictionaries/ne_NP/ne_NP.dic.zip"], "path":"$hunspell$/ne/ne_NP.dic", "date":"2012-10-16T11:09:27-05:00", "size":874372}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ne_NP/ne_NP.aff","https://translator.gres.biz/resources/dictionaries/ne_NP/ne_NP.aff.zip"], "path":"$hunspell$/ne/ne_NP.aff", "date":"2020-03-17T12:21:16+01:00", "size":14162}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ne_NP/ne_NP.dic","https://translator.gres.biz/resources/dictionaries/ne_NP/ne_NP.dic.zip"], "path":"$hunspell$/ne/ne_NP.dic", "date":"2020-03-17T12:21:16+01:00", "size":874372}
]}
, "Dutch":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/nl_NL/nl_NL.aff","https://translator.gres.biz/resources/dictionaries/nl_NL/nl_NL.aff.zip"], "path":"$hunspell$/nl/nl_NL.aff", "date":"2013-07-22T17:41:01+00:00", "size":27835}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/nl_NL/nl_NL.dic","https://translator.gres.biz/resources/dictionaries/nl_NL/nl_NL.dic.zip"], "path":"$hunspell$/nl/nl_NL.dic", "date":"2013-07-22T17:41:01+00:00", "size":1881063}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/nl_NL/nl_NL.aff","https://translator.gres.biz/resources/dictionaries/nl_NL/nl_NL.aff.zip"], "path":"$hunspell$/nl/nl_NL.aff", "date":"2020-03-17T12:21:16+01:00", "size":27835}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/nl_NL/nl_NL.dic","https://translator.gres.biz/resources/dictionaries/nl_NL/nl_NL.dic.zip"], "path":"$hunspell$/nl/nl_NL.dic", "date":"2020-03-17T12:21:16+01:00", "size":1881063}
]}
, "Norwegian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/no/nb_NO.aff","https://translator.gres.biz/resources/dictionaries/no/nb_NO.aff.zip"], "path":"$hunspell$/no/nb_NO.aff", "date":"2013-05-23T11:54:36+01:00", "size":17259}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/no/nb_NO.dic","https://translator.gres.biz/resources/dictionaries/no/nb_NO.dic.zip"], "path":"$hunspell$/no/nb_NO.dic", "date":"2018-09-05T10:30:32+02:00", "size":5274030}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/no/nb_NO.aff","https://translator.gres.biz/resources/dictionaries/no/nb_NO.aff.zip"], "path":"$hunspell$/no/nb_NO.aff", "date":"2020-03-17T12:21:16+01:00", "size":17259}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/no/nb_NO.dic","https://translator.gres.biz/resources/dictionaries/no/nb_NO.dic.zip"], "path":"$hunspell$/no/nb_NO.dic", "date":"2020-03-17T12:21:16+01:00", "size":5274030}
]}
, "Polish":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/pl_PL/pl_PL.aff","https://translator.gres.biz/resources/dictionaries/pl_PL/pl_PL.aff.zip"], "path":"$hunspell$/pl/pl_PL.aff", "date":"2017-05-05T15:26:38+02:00", "size":246842}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/pl_PL/pl_PL.dic","https://translator.gres.biz/resources/dictionaries/pl_PL/pl_PL.dic.zip"], "path":"$hunspell$/pl/pl_PL.dic", "date":"2017-05-21T10:58:59+02:00", "size":4539105}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/pl_PL/pl_PL.aff","https://translator.gres.biz/resources/dictionaries/pl_PL/pl_PL.aff.zip"], "path":"$hunspell$/pl/pl_PL.aff", "date":"2020-03-17T12:21:16+01:00", "size":246842}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/pl_PL/pl_PL.dic","https://translator.gres.biz/resources/dictionaries/pl_PL/pl_PL.dic.zip"], "path":"$hunspell$/pl/pl_PL.dic", "date":"2020-03-17T12:21:16+01:00", "size":4539105}
]}
, "Portuguese":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/pt_BR/pt_BR.aff","https://translator.gres.biz/resources/dictionaries/pt_BR/pt_BR.aff.zip"], "path":"$hunspell$/pt/pt_BR.aff", "date":"2021-11-12T14:13:08+01:00", "size":979792}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/pt_BR/pt_BR.dic","https://translator.gres.biz/resources/dictionaries/pt_BR/pt_BR.dic.zip"], "path":"$hunspell$/pt/pt_BR.dic", "date":"2021-11-12T14:13:08+01:00", "size":4477695}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/pt_PT/pt_PT.aff","https://translator.gres.biz/resources/dictionaries/pt_PT/pt_PT.aff.zip"], "path":"$hunspell$/pt/pt_PT.aff", "date":"2020-03-17T12:21:16+01:00", "size":95089}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/pt_PT/pt_PT.dic","https://translator.gres.biz/resources/dictionaries/pt_PT/pt_PT.dic.zip"], "path":"$hunspell$/pt/pt_PT.dic", "date":"2020-03-17T12:21:16+01:00", "size":1473077}
]}
, "Romanian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ro/ro_RO.aff","https://translator.gres.biz/resources/dictionaries/ro/ro_RO.aff.zip"], "path":"$hunspell$/ro/ro_RO.aff", "date":"2013-03-28T11:26:45+01:00", "size":55181}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ro/ro_RO.dic","https://translator.gres.biz/resources/dictionaries/ro/ro_RO.dic.zip"], "path":"$hunspell$/ro/ro_RO.dic", "date":"2013-03-28T11:26:45+01:00", "size":2196348}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ro/ro_RO.aff","https://translator.gres.biz/resources/dictionaries/ro/ro_RO.aff.zip"], "path":"$hunspell$/ro/ro_RO.aff", "date":"2020-03-17T12:21:16+01:00", "size":55181}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ro/ro_RO.dic","https://translator.gres.biz/resources/dictionaries/ro/ro_RO.dic.zip"], "path":"$hunspell$/ro/ro_RO.dic", "date":"2020-03-17T12:21:16+01:00", "size":2196348}
]}
, "Russian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ru_RU/ru_RU.aff","https://translator.gres.biz/resources/dictionaries/ru_RU/ru_RU.aff.zip"], "path":"$hunspell$/ru/ru_RU.aff", "date":"2020-06-04T15:36:15+02:00", "size":71236}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ru_RU/ru_RU.dic","https://translator.gres.biz/resources/dictionaries/ru_RU/ru_RU.dic.zip"], "path":"$hunspell$/ru/ru_RU.dic", "date":"2021-07-27T15:41:55+02:00", "size":3473191}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ru_RU/ru_RU.aff","https://translator.gres.biz/resources/dictionaries/ru_RU/ru_RU.aff.zip"], "path":"$hunspell$/ru/ru_RU.aff", "date":"2020-03-17T12:21:16+01:00", "size":53019}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/ru_RU/ru_RU.dic","https://translator.gres.biz/resources/dictionaries/ru_RU/ru_RU.dic.zip"], "path":"$hunspell$/ru/ru_RU.dic", "date":"2020-03-17T12:21:16+01:00", "size":1969349}
]}
, "Slovak":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sk_SK/sk_SK.aff","https://translator.gres.biz/resources/dictionaries/sk_SK/sk_SK.aff.zip"], "path":"$hunspell$/sk/sk_SK.aff", "date":"2020-06-10T20:31:32+02:00", "size":195963}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sk_SK/sk_SK.dic","https://translator.gres.biz/resources/dictionaries/sk_SK/sk_SK.dic.zip"], "path":"$hunspell$/sk/sk_SK.dic", "date":"2020-06-10T20:31:32+02:00", "size":4308934}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sk_SK/sk_SK.aff","https://translator.gres.biz/resources/dictionaries/sk_SK/sk_SK.aff.zip"], "path":"$hunspell$/sk/sk_SK.aff", "date":"2020-03-17T12:21:16+01:00", "size":99414}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sk_SK/sk_SK.dic","https://translator.gres.biz/resources/dictionaries/sk_SK/sk_SK.dic.zip"], "path":"$hunspell$/sk/sk_SK.dic", "date":"2020-03-17T12:21:16+01:00", "size":3289769}
]}
, "Slovenian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sl_SI/sl_SI.aff","https://translator.gres.biz/resources/dictionaries/sl_SI/sl_SI.aff.zip"], "path":"$hunspell$/sl/sl_SI.aff", "date":"2012-10-16T11:09:27-05:00", "size":14730}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sl_SI/sl_SI.dic","https://translator.gres.biz/resources/dictionaries/sl_SI/sl_SI.dic.zip"], "path":"$hunspell$/sl/sl_SI.dic", "date":"2012-10-16T11:09:27-05:00", "size":2967766}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sl_SI/sl_SI.aff","https://translator.gres.biz/resources/dictionaries/sl_SI/sl_SI.aff.zip"], "path":"$hunspell$/sl/sl_SI.aff", "date":"2020-03-17T12:21:16+01:00", "size":14730}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sl_SI/sl_SI.dic","https://translator.gres.biz/resources/dictionaries/sl_SI/sl_SI.dic.zip"], "path":"$hunspell$/sl/sl_SI.dic", "date":"2020-03-17T12:21:16+01:00", "size":2967766}
]}
, "Albanian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sq_AL/sq_AL.aff","https://translator.gres.biz/resources/dictionaries/sq_AL/sq_AL.aff.zip"], "path":"$hunspell$/sq/sq_AL.aff", "date":"2021-01-08T00:11:15+01:00", "size":7764}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sq_AL/sq_AL.dic","https://translator.gres.biz/resources/dictionaries/sq_AL/sq_AL.dic.zip"], "path":"$hunspell$/sq/sq_AL.dic", "date":"2021-01-08T00:11:15+01:00", "size":2726785}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sq_AL/sq_AL.aff","https://translator.gres.biz/resources/dictionaries/sq_AL/sq_AL.aff.zip"], "path":"$hunspell$/sq/sq_AL.aff", "date":"2020-03-17T12:21:16+01:00", "size":7555}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sq_AL/sq_AL.dic","https://translator.gres.biz/resources/dictionaries/sq_AL/sq_AL.dic.zip"], "path":"$hunspell$/sq/sq_AL.dic", "date":"2020-03-17T12:21:16+01:00", "size":2605147}
]}
, "Serbian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sr/sr.aff","https://translator.gres.biz/resources/dictionaries/sr/sr.aff.zip"], "path":"$hunspell$/sr/sr.aff", "date":"2019-04-20T11:24:57+02:00", "size":901060}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sr/sr.dic","https://translator.gres.biz/resources/dictionaries/sr/sr.dic.zip"], "path":"$hunspell$/sr/sr.dic", "date":"2019-04-20T11:24:57+02:00", "size":5878745}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sr/sr.aff","https://translator.gres.biz/resources/dictionaries/sr/sr.aff.zip"], "path":"$hunspell$/sr/sr.aff", "date":"2020-03-17T12:21:16+01:00", "size":901060}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sr/sr.dic","https://translator.gres.biz/resources/dictionaries/sr/sr.dic.zip"], "path":"$hunspell$/sr/sr.dic", "date":"2020-03-17T12:21:16+01:00", "size":5878745}
]}
, "Swedish":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sv_SE/sv_FI.aff","https://translator.gres.biz/resources/dictionaries/sv_SE/sv_FI.aff.zip"], "path":"$hunspell$/sv/sv_FI.aff", "date":"2015-09-08T21:02:20+00:00", "size":18583}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sv_SE/sv_FI.dic","https://translator.gres.biz/resources/dictionaries/sv_SE/sv_FI.dic.zip"], "path":"$hunspell$/sv/sv_FI.dic", "date":"2016-08-16T20:00:33+00:00", "size":2317112}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sv_SE/sv_FI.aff","https://translator.gres.biz/resources/dictionaries/sv_SE/sv_FI.aff.zip"], "path":"$hunspell$/sv/sv_FI.aff", "date":"2020-03-17T12:21:16+01:00", "size":18583}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sv_SE/sv_FI.dic","https://translator.gres.biz/resources/dictionaries/sv_SE/sv_FI.dic.zip"], "path":"$hunspell$/sv/sv_FI.dic", "date":"2020-03-17T12:21:16+01:00", "size":2317112}
]}
, "Swahili":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sw_TZ/sw_TZ.aff","https://translator.gres.biz/resources/dictionaries/sw_TZ/sw_TZ.aff.zip"], "path":"$hunspell$/sw/sw_TZ.aff", "date":"2012-10-16T11:09:27-05:00", "size":974}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sw_TZ/sw_TZ.dic","https://translator.gres.biz/resources/dictionaries/sw_TZ/sw_TZ.dic.zip"], "path":"$hunspell$/sw/sw_TZ.dic", "date":"2012-10-16T11:09:27-05:00", "size":630844}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sw_TZ/sw_TZ.aff","https://translator.gres.biz/resources/dictionaries/sw_TZ/sw_TZ.aff.zip"], "path":"$hunspell$/sw/sw_TZ.aff", "date":"2020-03-17T12:21:16+01:00", "size":974}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/sw_TZ/sw_TZ.dic","https://translator.gres.biz/resources/dictionaries/sw_TZ/sw_TZ.dic.zip"], "path":"$hunspell$/sw/sw_TZ.dic", "date":"2020-03-17T12:21:16+01:00", "size":630844}
]}
, "Telugu":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/te_IN/te_IN.aff","https://translator.gres.biz/resources/dictionaries/te_IN/te_IN.aff.zip"], "path":"$hunspell$/te/te_IN.aff", "date":"2012-10-16T11:09:27-05:00", "size":160}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/te_IN/te_IN.dic","https://translator.gres.biz/resources/dictionaries/te_IN/te_IN.dic.zip"], "path":"$hunspell$/te/te_IN.dic", "date":"2012-10-16T11:09:27-05:00", "size":3402272}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/te_IN/te_IN.aff","https://translator.gres.biz/resources/dictionaries/te_IN/te_IN.aff.zip"], "path":"$hunspell$/te/te_IN.aff", "date":"2020-03-17T12:21:16+01:00", "size":160}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/te_IN/te_IN.dic","https://translator.gres.biz/resources/dictionaries/te_IN/te_IN.dic.zip"], "path":"$hunspell$/te/te_IN.dic", "date":"2020-03-17T12:21:16+01:00", "size":3402272}
]}
, "Thai":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/th_TH/th_TH.aff","https://translator.gres.biz/resources/dictionaries/th_TH/th_TH.aff.zip"], "path":"$hunspell$/th/th_TH.aff", "date":"2019-04-30T09:35:45+02:00", "size":156}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/th_TH/th_TH.dic","https://translator.gres.biz/resources/dictionaries/th_TH/th_TH.dic.zip"], "path":"$hunspell$/th/th_TH.dic", "date":"2019-06-04T14:18:16+02:00", "size":1251425}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/th_TH/th_TH.aff","https://translator.gres.biz/resources/dictionaries/th_TH/th_TH.aff.zip"], "path":"$hunspell$/th/th_TH.aff", "date":"2020-03-17T12:21:16+01:00", "size":156}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/th_TH/th_TH.dic","https://translator.gres.biz/resources/dictionaries/th_TH/th_TH.dic.zip"], "path":"$hunspell$/th/th_TH.dic", "date":"2020-03-17T12:21:16+01:00", "size":1251425}
]}
, "Turkish":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/tr_TR/tr_TR.aff","https://translator.gres.biz/resources/dictionaries/tr_TR/tr_TR.aff.zip"], "path":"$hunspell$/tr/tr_TR.aff", "date":"2018-08-27T16:55:14+02:00", "size":235315}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/tr_TR/tr_TR.dic","https://translator.gres.biz/resources/dictionaries/tr_TR/tr_TR.dic.zip"], "path":"$hunspell$/tr/tr_TR.dic", "date":"2018-08-27T16:55:14+02:00", "size":9061155}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/tr_TR/tr_TR.aff","https://translator.gres.biz/resources/dictionaries/tr_TR/tr_TR.aff.zip"], "path":"$hunspell$/tr/tr_TR.aff", "date":"2020-03-17T12:21:16+01:00", "size":235315}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/tr_TR/tr_TR.dic","https://translator.gres.biz/resources/dictionaries/tr_TR/tr_TR.dic.zip"], "path":"$hunspell$/tr/tr_TR.dic", "date":"2020-03-17T12:21:16+01:00", "size":9061155}
]}
, "Ukrainian":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/uk_UA/uk_UA.aff","https://translator.gres.biz/resources/dictionaries/uk_UA/uk_UA.aff.zip"], "path":"$hunspell$/uk/uk_UA.aff", "date":"2022-08-28T03:23:22+02:00", "size":203463}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/uk_UA/uk_UA.dic","https://translator.gres.biz/resources/dictionaries/uk_UA/uk_UA.dic.zip"], "path":"$hunspell$/uk/uk_UA.dic", "date":"2022-08-28T03:23:22+02:00", "size":8355640}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/uk_UA/uk_UA.aff","https://translator.gres.biz/resources/dictionaries/uk_UA/uk_UA.aff.zip"], "path":"$hunspell$/uk/uk_UA.aff", "date":"2020-03-17T12:21:16+01:00", "size":159599}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/uk_UA/uk_UA.dic","https://translator.gres.biz/resources/dictionaries/uk_UA/uk_UA.dic.zip"], "path":"$hunspell$/uk/uk_UA.dic", "date":"2020-03-17T12:21:16+01:00", "size":2584267}
]}
, "Vietnamese":{"files":[
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/vi/vi_VN.aff","https://translator.gres.biz/resources/dictionaries/vi/vi_VN.aff.zip"], "path":"$hunspell$/vi/vi_VN.aff", "date":"2012-10-16T11:09:27-05:00", "size":788}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/vi/vi_VN.dic","https://translator.gres.biz/resources/dictionaries/vi/vi_VN.dic.zip"], "path":"$hunspell$/vi/vi_VN.dic", "date":"2012-10-16T11:09:27-05:00", "size":39852}
{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/vi/vi_VN.aff","https://translator.gres.biz/resources/dictionaries/vi/vi_VN.aff.zip"], "path":"$hunspell$/vi/vi_VN.aff", "date":"2020-03-17T12:21:16+01:00", "size":788}
,{"url":["https://cgit.freedesktop.org/libreoffice/dictionaries/plain/vi/vi_VN.dic","https://translator.gres.biz/resources/dictionaries/vi/vi_VN.dic.zip"], "path":"$hunspell$/vi/vi_VN.dic", "date":"2020-03-17T12:21:16+01:00", "size":39852}
]}
}
@ -594,10 +582,10 @@
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/bing.js", "path":"$translators$/bing.js", "md5":"a982e9aa6cac598f4c9bf4a56386d13e", "size":1481}
]}
,"deepl": {"files":[
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/deepl.js", "path":"$translators$/deepl.js", "md5":"76856af9b80c3d0e852ca73f8f1ebbdb", "size":2611}
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/deepl.js", "path":"$translators$/deepl.js", "md5":"fff5dba9840208cbb98fc85079014b0d", "size":1754}
]}
,"google": {"files":[
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/google.js", "path":"$translators$/google.js", "md5":"793d6628ac9e26a1f3cc00fa9c863495", "size":1508}
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/google.js", "path":"$translators$/google.js", "md5":"1ceba6431d757fc2ae028a4ec177542c", "size":1508}
]}
,"google_api": {"files":[
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/google_api.js", "path":"$translators$/google_api.js", "md5":"90b9b1a5c8dc52fd4a3f28be93442a56", "size":1030}
@ -606,7 +594,7 @@
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/papago.js", "path":"$translators$/papago.js", "md5":"603a56fc23990453942064ec53d1eaa3", "size":2164}
]}
,"yandex": {"files":[
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/yandex.js", "path":"$translators$/yandex.js", "md5":"82c10bddde30f3a1dc6675f7eea71986", "size":1170}
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/yandex.js", "path":"$translators$/yandex.js", "md5":"6bc71c24270ca418b193f073e6155d5f", "size":1177}
]}
}