Compare commits

...

23 Commits

Author SHA1 Message Date
dependabot[bot]
6efc473859
Bump actions/download-artifact from 1 to 4.1.7 in /.github/workflows (#191)
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 1 to 4.1.7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v1...v4.1.7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-06 10:51:26 +03:00
Gres
e1ec86f298 Update deepl translation 2023-09-02 21:09:27 +03:00
Gres
29ee5dda90 Update deepl translation 2023-05-19 23:30:44 +03:00
Gres
b8cd2dff54 Update project state 2023-05-05 21:50:57 +03:00
Gres
fb3f32f050 Update deepl translation 2023-04-08 22:09:35 +03:00
Gres
41f1f56fe5 Update deepl translation 2023-02-12 14:17:17 +03:00
Gres
5be5def820 Update deepl translation 2023-02-06 23:40:07 +03:00
Gres
12997389ff Add Hebrew translation 2023-01-28 12:29:12 +03:00
Gres
ab15cc8c79 Update Yandex translator 2023-01-28 12:29:12 +03:00
Gres
6cb9199a6c Fix repeated 'check for updates warning' 2023-01-28 12:29:12 +03:00
Gres
57b1cf8865 Add note about the app translaion 2023-01-03 21:51:56 +03:00
Gres
d328026356 Update correction resource names 2022-10-24 13:07:58 +03:00
Gres
8d4bcb8605 Update translation script 2022-10-14 21:20:42 +03:00
Gres
5a2c52e4c5 Update deepl supported languages 2022-10-07 21:09:43 +03:00
Gres
8c918e14a4 Update readme 2022-08-14 12:29:45 +03:00
Gres
936aaa90ff Update version file 2022-08-14 12:07:35 +03:00
Gres
efa9fab49f Update version file 2022-07-30 13:27:46 +03:00
Gres
cad1e83d44 Bump version 2022-07-30 13:10:43 +03:00
Gres
7be070744b Use single tesseract library
Link with it during compilation.
Bump to 5.2.0.
2022-07-29 23:09:56 +03:00
Gres
cb203b912e Improve image preprocessing 2022-07-29 23:05:49 +03:00
Gres
5f53aaec23 Rescent gcc fix 2022-07-03 22:34:16 +03:00
Gres
b71c67dd1b Respect "use user substitutions" option 2022-07-03 22:34:02 +03:00
Gres
5df1f52a68 Update version file 2022-05-22 15:06:14 +03:00
28 changed files with 1671 additions and 523 deletions

View File

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

View File

@ -1,5 +1,7 @@
# Screen Translator # Screen Translator
**The project is almost abandoned. I don't have time for it and I can only fix minor issues**
## Introduction ## Introduction
This software allows you to translate any text on screen. This software allows you to translate any text on screen.
@ -16,6 +18,12 @@ If the app fails to start complaining about missing dlls or there are any update
**OS X**: currently not supported. **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 ## Setup
The app doesn't have a main window. The app doesn't have a main window.
@ -53,9 +61,6 @@ Then click `Ok` to close settings.
By default resources are downloaded to the one of the user's folders. 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 `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. 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 Answers to some frequently asked questions can be found in issues or

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -6,27 +6,12 @@ import platform
c.print('>> Installing tesseract') c.print('>> Installing tesseract')
install_dir = dependencies_dir install_dir = dependencies_dir
url = 'https://github.com/tesseract-ocr/tesseract/archive/5.1.0.tar.gz' required_version = '5.2.0'
required_version = '5.1.0' url = 'https://github.com/tesseract-ocr/tesseract/archive/{}.tar.gz'.format(required_version)
build_type_flag = 'Debug' if build_type == 'debug' else 'Release' build_type_flag = 'Debug' if build_type == 'debug' else 'Release'
# compatibility flags cache_file = install_dir + '/tesseract.cache'
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 cache_file_data = required_version + build_type_flag
def check_existing(): def check_existing():
@ -42,22 +27,25 @@ def check_existing():
return False return False
if platform.system() == "Windows": if platform.system() == "Windows":
lib = install_dir + '/bin/tesseract{}.dll'.format(lib_suffix) file_name_ver = required_version[0] + required_version[2]
orig_lib = install_dir + '/bin/tesseract51.dll' 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')
elif platform.system() == "Darwin": elif platform.system() == "Darwin":
lib = install_dir + '/lib/libtesseract{}.dylib'.format(lib_suffix) lib = install_dir + '/lib/libtesseract.{}.dylib'.format(required_version)
orig_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')
else: else:
lib = install_dir + '/lib/libtesseract{}.so'.format(lib_suffix) lib = install_dir + '/lib/libtesseract.so.{}'.format(required_version)
orig_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')
if os.path.exists(lib): return True
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: if check_existing() and not 'FORCE' in os.environ:
@ -71,60 +59,24 @@ src_dir = os.path.abspath('tesseract_src')
c.extract(archive, '.') c.extract(archive, '.')
c.symlink(c.get_archive_top_dir(archive), src_dir) 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.ensure_got_path(install_dir)
c.recreate_dir(build_dir) c.recreate_dir(build_dir)
os.chdir(build_dir) os.chdir(build_dir)
cmake_args = '"{0}" -DCMAKE_INSTALL_PREFIX="{1}" -DLeptonica_DIR="{1}/cmake" \ cmake_args = '"{0}" \
-DBUILD_TRAINING_TOOLS=OFF -DBUILD_TESTS=OFF -DBUILD_SHARED_LIBS=ON -DSW_BUILD=OFF \ -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 \
'.format(src_dir, install_dir) '.format(src_dir, install_dir)
if platform.system() == "Windows": if platform.system() == "Windows":
@ -135,10 +87,6 @@ if platform.system() == "Windows":
c.set_make_threaded() c.set_make_threaded()
c.run('cmake {}'.format(cmake_args)) 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 . --config {}'.format(build_type_flag))
c.run('cmake --build . --target install --config {}'.format(build_type_flag)) c.run('cmake --build . --target install --config {}'.format(build_type_flag))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -4,6 +4,7 @@
#include "task.h" #include "task.h"
#include <leptonica/allheaders.h> #include <leptonica/allheaders.h>
#include <tesseract/baseapi.h>
#include <QBuffer> #include <QBuffer>
#include <QDir> #include <QDir>
@ -90,145 +91,121 @@ static double getScale(Pix *source)
return scale; return scale;
} }
static Pix *prepareImage(const QImage &image) // Smart pointer for Pix
class PixGuard
{ {
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: public:
explicit Wrapper(const QString &libraryName) explicit PixGuard(Pix *pix = nullptr)
: lib(libraryName) : pix_(pix)
{ {
if (!lib.load()) { }
LERROR() << "Failed to load tesseract library" << libraryName; ~PixGuard()
{
if (pix_)
pixDestroy(&pix_);
}
void operator=(Pix *pix)
{
if (!pix)
return; return;
} if (pix_)
pixDestroy(&pix_);
LTRACE() << "Loaded tesseract library" << lib.fileName(); pix_ = pix;
auto ok = true; }
ok &= bool(createApi_ = (CreateApi)lib.resolve("TessBaseAPICreate")); operator Pix *() { return pix_; }
ok &= bool(deleteApi_ = (DeleteApi)lib.resolve("TessBaseAPIDelete")); Pix *operator->() { return pix_; }
ok &= bool(initApi_ = (InitApi)lib.resolve("TessBaseAPIInit2")); Pix *&get() { return pix_; }
ok &= bool(setImage_ = (SetImage)lib.resolve("TessBaseAPISetImage2")); Pix *take()
ok &= bool(getUtf8_ = (GetUtf8)lib.resolve("TessBaseAPIGetUTF8Text")); {
ok &= bool(clearApi_ = (ClearApi)lib.resolve("TessBaseAPIClear")); auto ret = pix_;
ok &= bool(deleteUtf8_ = (DeleteUtf8)lib.resolve("TessDeleteText")); pix_ = nullptr;
ok &= bool(setPageMode_ = return ret;
(SetPageMode)lib.resolve("TessBaseAPISetPageSegMode")); }
if (!ok) { void trace(const QString &name) const
LERROR() << "Failed to resolve tesseract functions from" << libraryName; {
LTRACE() << qPrintable(name) << pix_;
#if 0
if (!pix_)
return; return;
} auto fileName = name + ".png";
handle_ = createApi_(); fileName.replace(' ', "_");
} convertImage(*pix_).save(fileName);
#endif
~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: private:
QLibrary lib; Pix *pix_;
CreateApi createApi_{nullptr};
DeleteApi deleteApi_{nullptr}; Q_DISABLE_COPY(PixGuard);
InitApi initApi_{nullptr};
SetImage setImage_{nullptr};
GetUtf8 getUtf8_{nullptr};
ClearApi clearApi_{nullptr};
DeleteUtf8 deleteUtf8_{nullptr};
SetPageMode setPageMode_{nullptr};
TessBaseAPI *handle_{nullptr};
}; };
Tesseract::Tesseract(const LanguageId &language, const QString &tessdataPath, static Pix *prepareImage(const QImage &image)
const QString &tesseractLibrary) {
: tesseractLibrary_(tesseractLibrary) 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)
{ {
SOFT_ASSERT(!tessdataPath.isEmpty(), return ); SOFT_ASSERT(!tessdataPath.isEmpty(), return );
SOFT_ASSERT(!language.isEmpty(), return ); SOFT_ASSERT(!language.isEmpty(), return );
@ -240,20 +217,22 @@ Tesseract::~Tesseract() = default;
void Tesseract::init(const LanguageId &language, const QString &tessdataPath) void Tesseract::init(const LanguageId &language, const QString &tessdataPath)
{ {
SOFT_ASSERT(!engine_, return ); SOFT_ASSERT(!api_, return );
engine_ = std::make_unique<Wrapper>(tesseractLibrary_); api_ = std::make_unique<tesseract::TessBaseAPI>();
LTRACE() << "Created Tesseract api" << engine_.get(); LTRACE() << "Created Tesseract api" << api_.get();
const auto tesseractName = LanguageCodes::tesseract(language); const auto tesseractName = LanguageCodes::tesseract(language);
auto result = auto result = api_->Init(qPrintable(tessdataPath), qPrintable(tesseractName),
engine_->Init(qPrintable(tessdataPath), qPrintable(tesseractName)); tesseract::OcrEngineMode::OEM_DEFAULT);
LTRACE() << "Inited Tesseract api" << result; LTRACE() << "Inited Tesseract api" << result;
if (result == 0) if (result == 0)
return; return;
api_->SetPageSegMode(tesseract::PageSegMode::PSM_AUTO);
error_ = QObject::tr("init failed"); error_ = QObject::tr("init failed");
engine_.reset(); api_.reset();
LTRACE() << "Cleared Tesseract api"; LTRACE() << "Cleared Tesseract api";
} }
@ -288,19 +267,28 @@ QStringList Tesseract::availableLanguageNames(const QString &path)
QString Tesseract::recognize(const QPixmap &source) QString Tesseract::recognize(const QPixmap &source)
{ {
SOFT_ASSERT(engine_, return {}); SOFT_ASSERT(api_, return {});
SOFT_ASSERT(!source.isNull(), return {}); SOFT_ASSERT(!source.isNull(), return {});
error_.clear(); error_.clear();
Pix *image = prepareImage(source.toImage()); PixGuard image(prepareImage(source.toImage()));
SOFT_ASSERT(image, return {}); SOFT_ASSERT(image, return {});
LTRACE() << "Preprocessed Pix for OCR" << image; LTRACE() << "Preprocessed Pix for OCR" << image;
auto result = engine_->GetText(image); api_->SetImage(image);
LTRACE() << "Set Pix to engine";
cleanupImage(&image); const auto outText = api_->GetUTF8Text();
LTRACE() << "Cleared preprocessed Pix"; LTRACE() << "Received recognized text";
api_->Clear();
LTRACE() << "Cleared engine";
const auto result = QString(outText).trimmed();
delete[] outText;
LTRACE() << "Cleared recognized text buffer";
if (result.isEmpty()) if (result.isEmpty())
error_ = QObject::tr("Failed to recognize text or no text selected"); error_ = QObject::tr("Failed to recognize text or no text selected");
@ -309,5 +297,5 @@ QString Tesseract::recognize(const QPixmap &source)
bool Tesseract::isValid() const bool Tesseract::isValid() const
{ {
return engine_.get(); return api_.get();
} }

View File

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

View File

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

View File

@ -35,7 +35,6 @@ const QString qs_showMessageOnStart = "showMessageOnStart";
const QString qs_recogntionGroup = "Recognition"; const QString qs_recogntionGroup = "Recognition";
const QString qs_ocrLanguage = "language"; const QString qs_ocrLanguage = "language";
const QString qs_tesseractVersion = "tesseractVersion";
const QString qs_correctionGroup = "Correction"; const QString qs_correctionGroup = "Correction";
const QString qs_userSubstitutions = "userSubstitutions"; const QString qs_userSubstitutions = "userSubstitutions";
@ -133,36 +132,6 @@ void cleanupOutdated(QSettings& settings)
settings.endGroup(); 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 } // namespace
void Settings::save() const void Settings::save() const
@ -207,7 +176,6 @@ void Settings::save() const
settings.beginGroup(qs_recogntionGroup); settings.beginGroup(qs_recogntionGroup);
settings.setValue(qs_ocrLanguage, sourceLanguage); settings.setValue(qs_ocrLanguage, sourceLanguage);
settings.setValue(qs_tesseractVersion, int(tesseractVersion));
settings.endGroup(); settings.endGroup();
settings.beginGroup(qs_correctionGroup); settings.beginGroup(qs_correctionGroup);
@ -295,15 +263,6 @@ void Settings::load()
settings.beginGroup(qs_recogntionGroup); settings.beginGroup(qs_recogntionGroup);
sourceLanguage = settings.value(qs_ocrLanguage, sourceLanguage).toString(); 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.endGroup();
settings.beginGroup(qs_correctionGroup); settings.beginGroup(qs_correctionGroup);

View File

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

View File

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

View File

@ -221,7 +221,7 @@
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="4" column="1"> <item row="4" column="1">
<widget class="service::KeySequenceEdit" name="clipboardEdit"/> <widget class="service::KeySequenceEdit" name="clipboardEdit" native="true"/>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QLabel" name="label_8"> <widget class="QLabel" name="label_8">
@ -231,7 +231,7 @@
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="service::KeySequenceEdit" name="repeatCaptureEdit"/> <widget class="service::KeySequenceEdit" name="repeatCaptureEdit" native="true"/>
</item> </item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="label_3">
@ -241,7 +241,7 @@
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="service::KeySequenceEdit" name="captureEdit"/> <widget class="service::KeySequenceEdit" name="captureEdit" native="true"/>
</item> </item>
<item row="4" column="0"> <item row="4" column="0">
<widget class="QLabel" name="label_7"> <widget class="QLabel" name="label_7">
@ -251,7 +251,7 @@
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="3" column="1">
<widget class="service::KeySequenceEdit" name="repeatEdit"/> <widget class="service::KeySequenceEdit" name="repeatEdit" native="true"/>
</item> </item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
@ -268,7 +268,7 @@
</widget> </widget>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="service::KeySequenceEdit" name="captureLockedEdit"/> <widget class="service::KeySequenceEdit" name="captureLockedEdit" native="true"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -291,7 +291,23 @@
</widget> </widget>
<widget class="QWidget" name="pageRecognize"> <widget class="QWidget" name="pageRecognize">
<layout class="QGridLayout" name="gridLayout_2"> <layout class="QGridLayout" name="gridLayout_2">
<item row="3" column="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">
<spacer name="verticalSpacer_2"> <spacer name="verticalSpacer_2">
<property name="orientation"> <property name="orientation">
<enum>Qt::Vertical</enum> <enum>Qt::Vertical</enum>
@ -317,19 +333,6 @@
</property> </property>
</widget> </widget>
</item> </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"> <item row="1" column="0">
<widget class="QLabel" name="label_4"> <widget class="QLabel" name="label_4">
<property name="sizePolicy"> <property name="sizePolicy">
@ -346,19 +349,6 @@
</property> </property>
</widget> </widget>
</item> </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> </layout>
</widget> </widget>
<widget class="QWidget" name="pageCorrect"> <widget class="QWidget" name="pageCorrect">

View File

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

View File

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

View File

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

View File

@ -2,9 +2,9 @@
"version":1 "version":1
,"app":{ ,"app":{
"win32":{"version":"3.2.2", "host":"win32", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"e7113757a8e5fe68ba87d0d7c5069450"}]} "win32":{"version":"3.3.0", "host":"win32", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"414c74c4594e0b90aff3cd86a73f96dd"}]}
,"win64":{"version":"3.2.2", "host":"win64", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"4187fc91d7a5d26c916692d890ad171b"}]} ,"win64":{"version":"3.3.0", "host":"win64", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"3f2c3c27364f25c239ea63243a8910a3"}]}
,"linux":{"version":"3.2.2", "host":"linux", "files":[{"path":"$appdir$/screen-translator", "md5":"ceb69232a200ac28d4535ae5a15706a7"}]} ,"linux":{"version":"3.3.0", "host":"linux", "files":[{"path":"$appdir$/screen-translator", "md5":"a091be0443fd128a02b01b313e0270bc"}]}
} }
@ -387,188 +387,200 @@
,"correction": { ,"correction": {
"Afrikaans":{"files":[ "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-03-17T12:21:16+01:00", "size":5027} {"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-03-17T12:21:16+01:00", "size":1262203} ,{"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}
]} ]}
, "Arabic":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":86949} {"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":"2020-03-17T12:21:16+01:00", "size":7217161} ,{"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}
]} ]}
, "Belarusian":{"files":[ , "Belarusian":{"files":[
{"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-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_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} ,{"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}
]} ]}
, "Bulgarian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":58189} {"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":"2020-03-17T12:21:16+01:00", "size":1566331} ,{"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}
]} ]}
, "Bengali":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":195} {"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":"2020-03-17T12:21:16+01:00", "size":2596038} ,{"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}
]} ]}
, "Tibetan":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":1706} {"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":"2020-03-17T12:21:16+01:00", "size":4637} ,{"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}
]} ]}
, "Bosnian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":17468} {"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":"2020-03-17T12:21:16+01:00", "size":339863} ,{"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}
]} ]}
, "Czech":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":97286} {"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":"2020-03-17T12:21:16+01:00", "size":2209232} ,{"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}
]} ]}
, "Danish":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":55779} {"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":"2020-03-17T12:21:16+01:00", "size":2915525} ,{"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}
]} ]}
, "German":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":18991} {"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":"2020-03-17T12:21:16+01:00", "size":4356858} ,{"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}
]} ]}
, "Greek":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":15647} {"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":"2020-03-17T12:21:16+01:00", "size":10125390} ,{"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}
]} ]}
, "English":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":3090} {"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":"2020-03-17T12:21:16+01:00", "size":551260} ,{"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}
]} ]}
, "Spanish":{"files":[ , "Esperanto":{"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/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/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} ,{"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}
]} ]}
, "Estonian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":236336} {"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":"2020-03-17T12:21:16+01:00", "size":4383841} ,{"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}
]} ]}
, "French":{"files":[ , "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-03-17T12:21:16+01:00", "size":256857} {"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-03-17T12:21:16+01:00", "size":1100397} ,{"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}
]} ]}
, "Gaelic":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":8228} {"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":"2020-03-17T12:21:16+01:00", "size":4806682} ,{"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}
]} ]}
, "Galician":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":1159910} {"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":"2020-03-17T12:21:16+01:00", "size":8636406} ,{"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}
]} ]}
, "Gujarati":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":174} {"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":"2020-03-17T12:21:16+01:00", "size":3792870} ,{"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}
]} ]}
, "Hebrew":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":78883} {"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":"2020-03-17T12:21:16+01:00", "size":7796259} ,{"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}
]} ]}
, "Hindi":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":210} {"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":"2020-03-17T12:21:16+01:00", "size":303963} ,{"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}
]} ]}
, "Croatian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":95802} {"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":"2020-03-17T12:21:16+01:00", "size":731819} ,{"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}
]} ]}
, "Hungarian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":2106214} {"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":"2020-03-17T12:21:16+01:00", "size":1653155} ,{"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}
]} ]}
, "Indonesian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":14957} {"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":"2020-03-17T12:21:16+01:00", "size":315384} ,{"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}
]} ]}
, "Icelandic":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":309734} {"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":"2020-03-17T12:21:16+01:00", "size":2454138} ,{"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}
]} ]}
, "Italian":{"files":[ , "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-03-17T12:21:16+01:00", "size":80216} {"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":"2020-03-17T12:21:16+01:00", "size":1290681} ,{"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}
]} ]}
, "Lao":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":10} {"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":"2020-03-17T12:21:16+01:00", "size":203209} ,{"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}
]} ]}
, "Lithuanian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":92208} {"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":"2020-03-17T12:21:16+01:00", "size":1085291} ,{"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}
]} ]}
, "Latvian":{"files":[ , "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-03-17T12:21:16+01:00", "size":69597} {"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-03-17T12:21:16+01:00", "size":2226834} ,{"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}
]} ]}
, "Nepali":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":14162} {"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":"2020-03-17T12:21:16+01:00", "size":874372} ,{"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}
]} ]}
, "Dutch":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":27835} {"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":"2020-03-17T12:21:16+01:00", "size":1881063} ,{"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}
]} ]}
, "Norwegian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":17259} {"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":"2020-03-17T12:21:16+01:00", "size":5274030} ,{"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}
]} ]}
, "Polish":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":246842} {"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":"2020-03-17T12:21:16+01:00", "size":4539105} ,{"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}
]} ]}
, "Portuguese":{"files":[ , "Portuguese":{"files":[
{"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_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_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} ,{"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}
]} ]}
, "Romanian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":55181} {"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":"2020-03-17T12:21:16+01:00", "size":2196348} ,{"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}
]} ]}
, "Russian":{"files":[ , "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-03-17T12:21:16+01:00", "size":53019} {"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":"2020-03-17T12:21:16+01:00", "size":1969349} ,{"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}
]} ]}
, "Slovak":{"files":[ , "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-03-17T12:21:16+01:00", "size":99414} {"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-03-17T12:21:16+01:00", "size":3289769} ,{"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}
]} ]}
, "Slovenian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":14730} {"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":"2020-03-17T12:21:16+01:00", "size":2967766} ,{"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}
]} ]}
, "Albanian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":7555} {"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":"2020-03-17T12:21:16+01:00", "size":2605147} ,{"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}
]} ]}
, "Serbian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":901060} {"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":"2020-03-17T12:21:16+01:00", "size":5878745} ,{"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}
]} ]}
, "Swedish":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":18583} {"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":"2020-03-17T12:21:16+01:00", "size":2317112} ,{"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}
]} ]}
, "Swahili":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":974} {"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":"2020-03-17T12:21:16+01:00", "size":630844} ,{"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}
]} ]}
, "Telugu":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":160} {"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":"2020-03-17T12:21:16+01:00", "size":3402272} ,{"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}
]} ]}
, "Thai":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":156} {"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":"2020-03-17T12:21:16+01:00", "size":1251425} ,{"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}
]} ]}
, "Turkish":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":235315} {"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":"2020-03-17T12:21:16+01:00", "size":9061155} ,{"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}
]} ]}
, "Ukrainian":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":159599} {"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":"2020-03-17T12:21:16+01:00", "size":2584267} ,{"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}
]} ]}
, "Vietnamese":{"files":[ , "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":"2020-03-17T12:21:16+01:00", "size":788} {"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":"2020-03-17T12:21:16+01:00", "size":39852} ,{"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}
]} ]}
} }
@ -582,10 +594,10 @@
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/bing.js", "path":"$translators$/bing.js", "md5":"a982e9aa6cac598f4c9bf4a56386d13e", "size":1481} {"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/bing.js", "path":"$translators$/bing.js", "md5":"a982e9aa6cac598f4c9bf4a56386d13e", "size":1481}
]} ]}
,"deepl": {"files":[ ,"deepl": {"files":[
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/deepl.js", "path":"$translators$/deepl.js", "md5":"fff5dba9840208cbb98fc85079014b0d", "size":1754} {"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/deepl.js", "path":"$translators$/deepl.js", "md5":"76856af9b80c3d0e852ca73f8f1ebbdb", "size":2611}
]} ]}
,"google": {"files":[ ,"google": {"files":[
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/google.js", "path":"$translators$/google.js", "md5":"1ceba6431d757fc2ae028a4ec177542c", "size":1508} {"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/google.js", "path":"$translators$/google.js", "md5":"793d6628ac9e26a1f3cc00fa9c863495", "size":1508}
]} ]}
,"google_api": {"files":[ ,"google_api": {"files":[
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/google_api.js", "path":"$translators$/google_api.js", "md5":"90b9b1a5c8dc52fd4a3f28be93442a56", "size":1030} {"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/google_api.js", "path":"$translators$/google_api.js", "md5":"90b9b1a5c8dc52fd4a3f28be93442a56", "size":1030}
@ -594,7 +606,7 @@
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/papago.js", "path":"$translators$/papago.js", "md5":"603a56fc23990453942064ec53d1eaa3", "size":2164} {"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/papago.js", "path":"$translators$/papago.js", "md5":"603a56fc23990453942064ec53d1eaa3", "size":2164}
]} ]}
,"yandex": {"files":[ ,"yandex": {"files":[
{"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/yandex.js", "path":"$translators$/yandex.js", "md5":"6bc71c24270ca418b193f073e6155d5f", "size":1177} {"url":"https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/translators/yandex.js", "path":"$translators$/yandex.js", "md5":"82c10bddde30f3a1dc6675f7eea71986", "size":1170}
]} ]}
} }