Compare commits

..

58 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
Gres
59d7f1d4f5 Update changelog 2022-05-22 14:53:33 +03:00
Gres
bf5d4efc6b Bump version 2022-05-22 14:37:50 +03:00
Gres
6cb853d804 Yet another typo 2022-05-18 23:13:51 +03:00
Gres
ac24d909d1 Typo in gcc version 2022-05-18 23:00:58 +03:00
Gres
9b6657318b Bump gcc version 2022-05-18 22:44:53 +03:00
Gres
ccfbf843dc Add info about Linux crash workaround 2022-05-18 22:44:21 +03:00
Gres
00e3f90430 Add workaround for tesseract crash on Linux 2022-05-18 22:44:21 +03:00
Gres
60f115acd1 Set proper flags for tesseract builds 2022-05-18 22:43:20 +03:00
Gres
1f6fff0050 Improve result window placement on screen borders
See #74
2022-05-04 19:36:56 +03:00
Gres
030c99d0fe Typo 2022-04-07 23:18:38 +03:00
Gres
a4a3f44806 Fixed avx support detection 2022-04-07 22:56:22 +03:00
Gres
ce9c47c3ea Update tesseract version 2022-04-03 12:19:50 +03:00
Gres
07b520d10b Change msvc version 2022-03-27 22:04:59 +03:00
Gres
260a10bea3 Close result widgets with escape button
For #86
2022-03-27 11:37:32 +03:00
Gres
4f195f5629 Fix multi-monitor result and editor positions
Fixes #90
2022-03-26 16:19:33 +03:00
Gres
7d84bd2f7b Fixed translators order persistence
fixes #91
2022-03-24 20:39:39 +03:00
Gres
a4e09d88c6 Update version file 2022-02-05 22:18:19 +03:00
Gres
ad39d98858 Disable sourceforge upload 2022-02-05 22:14:56 +03:00
Gres
2369015824 Bump version 2022-02-05 21:49:32 +03:00
Gres
156cd7c926 Make cache dependant on script changes 2022-02-05 21:49:32 +03:00
Gres
ff041facd8 Add file to store cached tesseract version in ci 2022-02-05 21:49:32 +03:00
Gres
5581f385ae Added joint script to make a release 2022-02-05 21:49:32 +03:00
Gres
958b86044e Use rescent linuxdeployqt for appimage 2022-02-05 21:49:32 +03:00
Gres
032a14380f Remove outdated file 2022-02-05 21:49:32 +03:00
Gres
c03a3d2fc2 Update translations 2022-02-05 21:49:32 +03:00
Gres
d5eb9f1855 Add some info to readme.
Add link to readme to the app.
2022-02-05 21:49:32 +03:00
Gres
7a8e8e510c Use more rescent library versions
Tesseract 5.0.1 causes "free: invalid pointer" error
2022-02-05 21:48:23 +03:00
Gres
45a36f3222 Change CI ubuntu version 2022-01-30 13:34:48 +03:00
Gres
155c3577c3 Auto select all translators if translation is enabled and no one is selected 2022-01-30 13:34:48 +03:00
Gres
0e72af3770 Auto select tesseract versions depending on cpu info 2022-01-30 13:34:48 +03:00
Gres
fdfa43c093 Fix multi-monitor configurations with primary not right/bottom 2022-01-30 13:34:48 +03:00
Gres
af15301bf1 Fix some special key mappings for global shortcuts 2022-01-12 19:06:51 +03:00
Gres
26c034e75a Change shortcut editor
Remove global shortcuts when blocking actions to not trigger it when editing
2022-01-12 19:06:51 +03:00
Gres
75bfd798c8 Add ISO code for Filipino language. Required for translation 2022-01-12 19:00:28 +03:00
Gres
59a10af57e Change tesseract github url 2021-11-22 11:37:51 +03:00
54 changed files with 2249 additions and 1023 deletions

View File

@ -6,7 +6,7 @@ jobs:
release: release:
name: Create release name: Create release
if: contains(github.ref, '/tags/') if: contains(github.ref, '/tags/')
runs-on: ubuntu-16.04 runs-on: ubuntu-18.04
steps: steps:
- name: Create release - name: Create release
id: create_release id: create_release
@ -33,13 +33,13 @@ jobs:
runs-on: ${{ matrix.config.os }} runs-on: ${{ matrix.config.os }}
env: env:
OS: ${{ matrix.config.name }} OS: ${{ matrix.config.name }}
MSVC_VERSION: 2019/Enterprise MSVC_VERSION: C:/Program Files/Microsoft Visual Studio/2022/Enterprise
strategy: strategy:
matrix: matrix:
config: config:
- { name: "win64", os: windows-latest } - { name: "win64", os: windows-latest }
- { name: "win32", os: windows-latest } - { name: "win32", os: windows-latest }
- { name: "linux", os: ubuntu-16.04 } - { name: "linux", os: ubuntu-18.04 }
# - { name: "macos", os: macos-latest } # - { name: "macos", os: macos-latest }
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
@ -55,64 +55,19 @@ jobs:
if: runner.os == 'Linux' if: runner.os == 'Linux'
run: | run: |
sudo apt-get install libgl1-mesa-dev libxkbcommon-x11-0 libxcb-* sudo apt-get install libgl1-mesa-dev libxkbcommon-x11-0 libxcb-*
echo "QMAKE_FLAGS=QMAKE_CXX=g++-9 QMAKE_CC=gcc-9" >> $GITHUB_ENV echo "QMAKE_FLAGS=QMAKE_CXX=g++-10 QMAKE_CC=gcc-10 QMAKE_LINK=g++-10" >> $GITHUB_ENV
- name: Cache dependencies - name: Cache dependencies
uses: actions/cache@v1 uses: actions/cache@v2
with: with:
path: deps path: deps
key: ${{ env.OS }}-deps key: ${{ env.OS }}-${{ hashFiles('./share/ci/*.py') }}
- name: Get Qt - name: Make a release
run: python ./share/ci/get_qt.py
- name: Get ssl
run: python ./share/ci/get_qt_ssl.py
- name: Get leptonica
run: python ./share/ci/get_leptonica.py
- name: Get tesseract optimized
env:
MARCH: sandy-bridge
TAG: optimized
run: python ./share/ci/get_tesseract.py
- name: Get tesseract compatible
env:
MARCH: nehalem
TAG: compatible
run: python ./share/ci/get_tesseract.py
- name: Get hunspell
run: python ./share/ci/get_hunspell.py
- name: Test
run: python ./share/ci/test.py
- name: Build
run: python ./share/ci/build.py
- name: Create AppImage
if: runner.os == 'Linux'
shell: bash shell: bash
run: | run: |
python ./share/ci/appimage.py python ./share/ci/release.py
echo "artifact=`python ./share/ci/appimage.py artifact_name`" >> $GITHUB_ENV echo "artifact=`python ./share/ci/release.py artifact_name`" >> $GITHUB_ENV
- name: Create win deploy
if: runner.os == 'Windows'
shell: bash
run: |
python ./share/ci/windeploy.py
echo "artifact=`python ./share/ci/windeploy.py artifact_name`" >> $GITHUB_ENV
- name: Create mac deploy
if: runner.os == 'macOS'
shell: bash
run: |
python ./share/ci/macdeploy.py
echo "artifact=`python ./share/ci/macdeploy.py artifact_name`" >> $GITHUB_ENV
- name: Upload build artifact - name: Upload build artifact
if: env.artifact != '' if: env.artifact != ''
@ -123,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: ./
@ -143,13 +98,3 @@ jobs:
asset_path: ./${{ env.artifact }} asset_path: ./${{ env.artifact }}
asset_name: ${{ env.artifact }} asset_name: ${{ env.artifact }}
asset_content_type: application/zip asset_content_type: application/zip
- name: Upload sourceforge
if: contains(github.ref, '/tags/')
env:
SF_PKEY: ${{ secrets.SF_PKEY }}
SF_API: ${{ secrets.SF_API }}
run: |
python -m pip install --upgrade pip
pip install paramiko
python ./share/ci/sourceforge.py ./${{ env.artifact }}

View File

@ -1,30 +1,52 @@
# 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.
Basically it is a combination of screen capture, OCR and translation tools. Basically it is a combination of screen capture, OCR and translation tools.
Translation is currently done via online services.
## Installation ## Installation
**Windows**: download archive from [github releases](https://github.com/OneMoreGres/ScreenTranslator/releases) page, extract it and run `.exe` file. **Windows**: download archive from [github releases](https://github.com/OneMoreGres/ScreenTranslator/releases) page, extract it and run `.exe` file.
If the app fails to start with missing dll's error then install `vs_redist*.exe` from the release archive. If the app fails to start complaining about missing dlls or there are any update errors related to SSL/TLS then install or repair `vs_redist*.exe` from the release archive.
If you have any update errors related to SSL/TLS you should also install or repair `vcredist 2010` (from the Microsoft website).
**Linux**: download `.AppImage` file from [github releases](https://github.com/OneMoreGres/ScreenTranslator/releases), make executable (`chmod +x <file>`) and run it. **Linux**: download `.AppImage` file from [github releases](https://github.com/OneMoreGres/ScreenTranslator/releases), make executable (`chmod +x <file>`) and run it.
**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
Start the app, open the updates page of the settings window The app doesn't have a main window.
and install required recognition languages, translators and, optionally, After start it shows only the tray icon.
hunspell dictionaries.
After languages/translators installation set default recognition and If the app detects invalid settings, it will show the error message via system tray.
translation languages, enable some (or all) translators It will also highlight the section name in red on the left panel of the settings window.
and the `translate text` setting if needed. Clicking on that section name will show a more detailed error message in the right panel (also in red).
The packages downloaded from this site do not include resources, such as recognition language packs or scripts to interact with online translation services.
To download them, open the settings window and go to the `Update` section.
In the right panel, expand the `recognizers` and `translators` sections.
Select preferred items, then right click and choose `Install/Update`.
After the progress bar reaches `100%`, the resource's state will change to `Up to Date`.
You must download at least one `recognizers` resource and one `translators` resource.
After finishing downloads, go to the `Recognition` section and update the default recognition language setting (the source to be translated).
Then go to the `Translation` section, update the default translation language setting (the language to be translated into) and enable some or all translation sevices (you may also change their order by dragging).
After that all sections in the left panel should be black.
Then click `Ok` to close settings.
## Usage ## Usage
@ -36,6 +58,11 @@ and the `translate text` setting if needed.
## FAQ ## FAQ
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.
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
[wiki](https://github.com/OneMoreGres/ScreenTranslator/wiki/FAQ) [wiki](https://github.com/OneMoreGres/ScreenTranslator/wiki/FAQ)

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,20 +8,20 @@ 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
} }
linux{ linux{
QT += x11extras dbus QT += x11extras
LIBS += -lX11 LIBS += -lX11
} }
SOURCES += $$PWD/external/miniz/miniz.c SOURCES += $$PWD/external/miniz/miniz.c
INCLUDEPATH += $$PWD/external INCLUDEPATH += $$PWD/external
VER=3.2.1 VER=3.3.0
DEFINES += VERSION="$$VER" DEFINES += VERSION="$$VER"
VERSION = $$VER.0 VERSION = $$VER.0
QMAKE_TARGET_COMPANY = Gres QMAKE_TARGET_COMPANY = Gres
@ -37,7 +37,6 @@ HEADERS += \
src/capture/captureareaeditor.h \ src/capture/captureareaeditor.h \
src/capture/captureareaselector.h \ src/capture/captureareaselector.h \
src/capture/capturer.h \ src/capture/capturer.h \
src/capture/waylandcapturer.h \
src/commonmodels.h \ src/commonmodels.h \
src/correct/corrector.h \ src/correct/corrector.h \
src/correct/correctorworker.h \ src/correct/correctorworker.h \
@ -54,6 +53,7 @@ HEADERS += \
src/service/debug.h \ src/service/debug.h \
src/service/geometryutils.h \ src/service/geometryutils.h \
src/service/globalaction.h \ src/service/globalaction.h \
src/service/keysequenceedit.h \
src/service/runatsystemstart.h \ src/service/runatsystemstart.h \
src/service/singleapplication.h \ src/service/singleapplication.h \
src/service/updates.h \ src/service/updates.h \
@ -74,7 +74,6 @@ SOURCES += \
src/capture/captureareaeditor.cpp \ src/capture/captureareaeditor.cpp \
src/capture/captureareaselector.cpp \ src/capture/captureareaselector.cpp \
src/capture/capturer.cpp \ src/capture/capturer.cpp \
src/capture/waylandcapturer.cpp \
src/commonmodels.cpp \ src/commonmodels.cpp \
src/correct/corrector.cpp \ src/correct/corrector.cpp \
src/correct/correctorworker.cpp \ src/correct/correctorworker.cpp \
@ -92,6 +91,7 @@ SOURCES += \
src/service/debug.cpp \ src/service/debug.cpp \
src/service/geometryutils.cpp \ src/service/geometryutils.cpp \
src/service/globalaction.cpp \ src/service/globalaction.cpp \
src/service/keysequenceedit.cpp \
src/service/runatsystemstart.cpp \ src/service/runatsystemstart.cpp \
src/service/singleapplication.cpp \ src/service/singleapplication.cpp \
src/service/updates.cpp \ src/service/updates.cpp \
@ -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,24 @@
# Changes # Changes
## 3.3.0
* Use single tesseract library (not optimized and compatible versions)
* Improved recognition
## 3.2.3
* Fixed translators order persistance
* Fixed multi-monitor support
* Improves result representation near monitor borders
* Updated recognition library
## 3.2.2
* Disabled hotkeys with several consecutive combinations
* Added the ability to use some service buttons for hotkeys
* Fixed multiple monitors support if the main one is not at the top left
* Automatic selection of the supported version of tesseract
## 3.2.1 ## 3.2.1
* Fixed incorrect update install * Fixed incorrect update install

View File

@ -1,5 +1,24 @@
# Изменения # Изменения
## 3.3.0
* Использование единой библиотеки распознавания (без оптимизированной и совместимой версий)
* Улучшено распознавание
## 3.2.3
* Исправлено сохранение порядка переводчиков в настройках
* Исправлена работа с несколькими мониторами
* Улучшено отображение результата на границе монитора
* Обновлена версия библиотеки распознавания
## 3.2.2
* Исключено задание горячих клавиш из нескольких последовательных комбинаций
* Добавлена возможность использования некоторых служебных кнопок для горячих клавиш
* Исправлена работа с несколькими мониторами, если главный находится не слева-вверху
* Автоматический выбор поддерживаемой версии tesseract
## 3.2.1 ## 3.2.1
* Исправлена некорректная установка обновления * Исправлена некорректная установка обновления

View File

@ -22,7 +22,7 @@ c.print('>> Making appimage')
base_url = 'https://github.com/probonopd/linuxdeployqt/releases/download' base_url = 'https://github.com/probonopd/linuxdeployqt/releases/download'
continuous_url = base_url + '/continuous/linuxdeployqt-continuous-x86_64.AppImage' continuous_url = base_url + '/continuous/linuxdeployqt-continuous-x86_64.AppImage'
tagged_url = base_url + '/6/linuxdeployqt-6-x86_64.AppImage' tagged_url = base_url + '/6/linuxdeployqt-6-x86_64.AppImage'
linuxdeployqt_url = tagged_url linuxdeployqt_url = continuous_url
linuxdeployqt_original = os.path.basename(linuxdeployqt_url) linuxdeployqt_original = os.path.basename(linuxdeployqt_url)
c.download(linuxdeployqt_url, linuxdeployqt_original) c.download(linuxdeployqt_url, linuxdeployqt_original)
@ -47,14 +47,15 @@ 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:
c.print('>> Copying {} to {}'.format(f, out_lib_dir)) c.print('>> Copying {} to {}'.format(f, out_lib_dir))
shutil.copy(f, out_lib_dir) shutil.copy(f, out_lib_dir)
c.ensure_got_path('{}/usr/share/doc/libc6/copyright'.format(install_dir))
c.run('{} {}/usr/share/applications/*.desktop {} -appimage -qmake={}/bin/qmake'.format( c.run('{} {}/usr/share/applications/*.desktop {} -appimage -qmake={}/bin/qmake'.format(
linuxdeployqt_bin, install_dir, flags, qt_dir)) linuxdeployqt_bin, install_dir, flags, qt_dir))

View File

@ -150,15 +150,7 @@ def get_msvc_env_cmd(bitness='64', msvc_version=''):
if platform.system() != "Windows": if platform.system() != "Windows":
return None return None
msvc_path = 'C:/Program Files (x86)/Microsoft Visual Studio' env_script = msvc_version + '/VC/Auxiliary/Build/vcvars{}.bat'.format(bitness)
if len(msvc_version) == 0:
with os.scandir(msvc_path) as ver_it:
version = next(ver_it, '')
with os.scandir(msvc_path + '/' + version) as ed_it:
msvc_version = version + '/' + next(ed_it, '')
env_script = msvc_path + '/{}/VC/Auxiliary/Build/vcvars{}.bat'.format(
msvc_version, bitness)
return '"' + env_script + '"' return '"' + env_script + '"'

View File

@ -30,6 +30,6 @@ os_name = getenv('OS', 'linux')
app_version += {'linux': '', 'macos': '-experimental', app_version += {'linux': '', 'macos': '-experimental',
'win32': '', 'win64': ''}[os_name] 'win32': '', 'win64': ''}[os_name]
bitness = '32' if os_name == 'win32' else '64' bitness = '32' if os_name == 'win32' else '64'
msvc_version = getenv('MSVC_VERSION', '2019/Community') msvc_version = getenv('MSVC_VERSION', 'C:/Program Files (x86)/Microsoft Visual Studio/2019/Community')
build_type = 'release' # 'debug' build_type = 'release' # 'debug'

View File

@ -6,8 +6,8 @@ import platform
c.print('>> Installing leptonica') c.print('>> Installing leptonica')
install_dir = dependencies_dir install_dir = dependencies_dir
url = 'https://github.com/DanBloomberg/leptonica/releases/download/1.80.0/leptonica-1.80.0.tar.gz' url = 'https://github.com/DanBloomberg/leptonica/releases/download/1.82.0/leptonica-1.82.0.tar.gz'
required_version = '1.80.0' required_version = '1.82.0'
build_type_flag = 'Debug' if build_type == 'debug' else 'Release' build_type_flag = 'Debug' if build_type == 'debug' else 'Release'
@ -25,14 +25,14 @@ def check_existing():
return False return False
if platform.system() == "Windows": if platform.system() == "Windows":
dll = install_dir + '/bin/leptonica-1.80.0.dll' dll = install_dir + '/bin/leptonica-1.82.0.dll'
lib = install_dir + '/lib/leptonica-1.80.0.lib' lib = install_dir + '/lib/leptonica-1.82.0.lib'
if not os.path.exists(dll) or not os.path.exists(lib): if not os.path.exists(dll) or not os.path.exists(lib):
return False return False
c.symlink(dll, install_dir + '/bin/leptonica.dll') c.symlink(dll, install_dir + '/bin/leptonica.dll')
c.symlink(lib, install_dir + '/lib/leptonica.lib') c.symlink(lib, install_dir + '/lib/leptonica.lib')
elif platform.system() == "Darwin": elif platform.system() == "Darwin":
lib = install_dir + '/lib/libleptonica.1.80.0.dylib' lib = install_dir + '/lib/libleptonica.1.82.0.dylib'
if not os.path.exists(lib): if not os.path.exists(lib):
return False return False
c.symlink(lib, install_dir + '/lib/libleptonica.dylib') c.symlink(lib, install_dir + '/lib/libleptonica.dylib')
@ -44,12 +44,12 @@ def check_existing():
if len(c.get_folder_files(includes_path)) == 0: if len(c.get_folder_files(includes_path)) == 0:
return False return False
version_file = install_dir + '/cmake/LeptonicaConfig-version.cmake' version_file = install_dir + '/lib/cmake/leptonica/LeptonicaConfig-version.cmake'
if not os.path.exists(version_file): if not os.path.exists(version_file):
return False return False
with open(version_file, 'rt') as f: with open(version_file, 'rt') as f:
existing_version = f.readline()[22:28] # set(Leptonica_VERSION 1.80.0) existing_version = f.readline()[22:28] # set(Leptonica_VERSION 1.82.0)
if existing_version != required_version: if existing_version != required_version:
return False return False
return True return True

View File

@ -6,60 +6,46 @@ 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/4.1.1.tar.gz' required_version = '5.2.0'
required_version = '4.1.1' 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 = '' cache_file_data = required_version + build_type_flag
if os.environ.get('NO_AVX2', '0') == '1':
compat_flags += ' -D USE_AVX2=OFF '
if os.environ.get('NO_AVX512', '0') == '1':
compat_flags += ' -D USE_AVX512BW=OFF -D USE_AVX512CD=OFF \
-D USE_AVX512DQ=OFF -D USE_AVX512ER=OFF -D USE_AVX512F=OFF -D USE_AVX512IFMA=OFF \
-D USE_AVX512PF=OFF -D USE_AVX512VBMI=OFF -D USE_AVX512VL=OFF '
if os.environ.get('NO_AVX', '0') == '1':
compat_flags += ' -D USE_AVX=OFF '
if os.environ.get('NO_FMA', '0') == '1':
compat_flags += ' -D USE_FMA=OFF '
if os.environ.get('NO_BMI2', '0') == '1':
compat_flags += ' -D USE_BMI2=OFF '
if os.environ.get('NO_SSE4', '0') == '1':
compat_flags += ' -D USE_SSE4_1=OFF -D USE_SSE4_2=OFF '
if os.environ.get('NO_OPT', '0') == '1':
compat_flags += ' -D CMAKE_CXX_FLAGS_RELEASE="/MD /Od /Od0 /DNDEBUG" '
compat_flags += ' -D CMAKE_C_FLAGS_RELEASE="/MD /Od /Od0 /DNDEBUG" '
if len(os.environ.get('MARCH', '')) > 0:
compat_flags += ' -D TARGET_ARCHITECTURE={} '.format(os.environ['MARCH'])
lib_suffix = os.environ.get('TAG', '')
if len(lib_suffix) > 0:
lib_suffix = '-' + lib_suffix
def check_existing(): def check_existing():
if not os.path.exists(cache_file):
return False
with open(cache_file, 'r') as f:
cached = f.read()
if cached != cache_file_data:
return False
includes_path = install_dir + '/include/tesseract' includes_path = install_dir + '/include/tesseract'
if len(c.get_folder_files(includes_path)) == 0: if len(c.get_folder_files(includes_path)) == 0:
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/tesseract41.dll' dll = install_dir + '/bin/tesseract{}.dll'.format(file_name_ver)
elif platform.system() == "Darwin": lib = install_dir + '/lib/tesseract{}.lib'.format(file_name_ver)
lib = install_dir + '/lib/libtesseract{}.dylib'.format(lib_suffix) if not os.path.exists(dll) or not os.path.exists(lib):
orig_lib = install_dir + '/lib/libtesseract.4.1.1.dylib'
else:
lib = install_dir + '/lib/libtesseract{}.so'.format(lib_suffix)
orig_lib = install_dir + '/lib/libtesseract.so.4.1.1'
if os.path.exists(lib):
return True
if os.path.exists(orig_lib):
os.rename(orig_lib, lib)
return True
return False return False
c.symlink(dll, install_dir + '/bin/tesseract.dll')
c.symlink(lib, install_dir + '/lib/tesseract.lib')
elif platform.system() == "Darwin":
lib = install_dir + '/lib/libtesseract.{}.dylib'.format(required_version)
if not os.path.exists(lib):
return False
c.symlink(lib, install_dir + '/lib/libtesseract.dylib')
else:
lib = install_dir + '/lib/libtesseract.so.{}'.format(required_version)
if not os.path.exists(lib):
return False
c.symlink(lib, install_dir + '/lib/libtesseract.so')
return True
if check_existing() and not 'FORCE' in os.environ: if check_existing() and not 'FORCE' in os.environ:
@ -78,8 +64,20 @@ 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'.format(src_dir, install_dir) -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)
if platform.system() == "Windows": if platform.system() == "Windows":
env_cmd = c.get_msvc_env_cmd(bitness=bitness, msvc_version=msvc_version) env_cmd = c.get_msvc_env_cmd(bitness=bitness, msvc_version=msvc_version)
@ -89,13 +87,12 @@ 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))
with open(cache_file, 'w') as f:
f.write(cache_file_data)
if not check_existing(): # add suffix if not check_existing(): # add suffix
c.print('>> Build failed') c.print('>> Build failed')
exit(1) exit(1)

43
share/ci/release.py Normal file
View File

@ -0,0 +1,43 @@
import os
import platform
import sys
import subprocess
here = os.path.dirname(__file__)
def r_out(script, args):
return subprocess.run([sys.executable, os.path.join(here, script)] + args, check=True, stdout=subprocess.PIPE).stdout.decode('utf-8').strip()
if len(sys.argv) > 1 and sys.argv[1] == 'artifact_name':
artifact_name = ''
if platform.system() == "Linux":
artifact_name = r_out('appimage.py', ['artifact_name'])
if platform.system() == "Windows":
artifact_name = r_out('windeploy.py', ['artifact_name'])
if platform.system() == "Darwin":
artifact_name = r_out('macdeploy.py', ['artifact_name'])
print(artifact_name)
exit(0)
def r(script):
return subprocess.run([sys.executable, os.path.join(here, script)], check=True)
r('get_qt.py')
r('get_qt_ssl.py')
r('get_leptonica.py')
r('get_tesseract.py')
r('get_hunspell.py')
r('test.py')
r('build.py')
if platform.system() == "Linux":
r('appimage.py')
if platform.system() == "Windows":
r('windeploy.py')
if platform.system() == "Darwin":
r('macdeploy.py')

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,7 @@
<context> <context>
<name>CaptureAreaSelector</name> <name>CaptureAreaSelector</name>
<message> <message>
<location filename="../../src/capture/captureareaselector.cpp" line="37"/> <location filename="../../src/capture/captureareaselector.cpp" line="39"/>
<source>Right click on selection - customize <source>Right click on selection - customize
Left click on selection - process Left click on selection - process
Enter - process all selections Enter - process all selections
@ -45,12 +45,12 @@ Esc - отмена
Ctrl - продолжить выделять</translation> Ctrl - продолжить выделять</translation>
</message> </message>
<message> <message>
<location filename="../../src/capture/captureareaselector.cpp" line="44"/> <location filename="../../src/capture/captureareaselector.cpp" line="46"/>
<source>Capture all</source> <source>Capture all</source>
<translation>Обработать все</translation> <translation>Обработать все</translation>
</message> </message>
<message> <message>
<location filename="../../src/capture/captureareaselector.cpp" line="49"/> <location filename="../../src/capture/captureareaselector.cpp" line="51"/>
<source>Cancel</source> <source>Cancel</source>
<translation>Отменить</translation> <translation>Отменить</translation>
</message> </message>
@ -653,17 +653,17 @@ Check for updates to silence this warning</source>
Проверьте обновления, чтобы отключить это сообщение</translation> Проверьте обновления, чтобы отключить это сообщение</translation>
</message> </message>
<message> <message>
<location filename="../../src/manager.cpp" line="127"/> <location filename="../../src/manager.cpp" line="129"/>
<source>Incorrect settings found. Go to Settings</source> <source>Incorrect settings found. Go to Settings</source>
<translation>Обнвружены некорректные настройки. Перейдите в Настройки</translation> <translation>Обнаружены некорректные настройки. Перейдите в Настройки</translation>
</message> </message>
<message> <message>
<location filename="../../src/manager.cpp" line="192"/> <location filename="../../src/manager.cpp" line="194"/>
<source>Failed to set log file: %1</source> <source>Failed to set log file: %1</source>
<translation>Ошибка установки лог-файла: %1</translation> <translation>Ошибка установки лог-файла: %1</translation>
</message> </message>
<message> <message>
<location filename="../../src/manager.cpp" line="198"/> <location filename="../../src/manager.cpp" line="200"/>
<source>Started logging to file: %1</source> <source>Started logging to file: %1</source>
<translation>Начата запись в лог-файл: %1</translation> <translation>Начата запись в лог-файл: %1</translation>
</message> </message>
@ -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,57 +712,62 @@ in %1</source>
<translation>Не восстанавливать интерфейс пользователя (размер и положения окна и т.д.)</translation> <translation>Не восстанавливать интерфейс пользователя (размер и положения окна и т.д.)</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="183"/> <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="185"/> <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="187"/> <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>
<translation>&lt;p&gt;Инструкции по установке: &lt;a href=&quot;%1&quot;&gt;%1&lt;/a&gt;&lt;/p&gt;</translation>
</message>
<message>
<location filename="../../src/settingseditor.cpp" line="195"/>
<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="189"/> <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="190"/> <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="192"/> <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>
<message> <message>
<location filename="../../src/settingsvalidator.cpp" line="33"/> <location filename="../../src/settingsvalidator.cpp" line="45"/>
<source>No recognizers installed</source> <source>No recognizers installed</source>
<translation>Нет установленных языков распознавания</translation> <translation>Нет установленных языков распознавания</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingsvalidator.cpp" line="35"/> <location filename="../../src/settingsvalidator.cpp" line="47"/>
<source>Recognition language not set</source> <source>Recognition language not set</source>
<translation>Не задан язык распознавания по умолчанию</translation> <translation>Не задан язык распознавания по умолчанию</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingsvalidator.cpp" line="38"/> <location filename="../../src/settingsvalidator.cpp" line="50"/>
<source>No translators installed</source> <source>No translators installed</source>
<translation>Нет установленных переводчиков</translation> <translation>Нет установленных переводчиков</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingsvalidator.cpp" line="41"/> <location filename="../../src/settingsvalidator.cpp" line="53"/>
<source>No translators enabled (selected)</source> <source>No translators enabled (selected)</source>
<translation>Нет активированных (выделенных) переводчиков</translation> <translation>Нет активированных (выделенных) переводчиков</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingsvalidator.cpp" line="43"/> <location filename="../../src/settingsvalidator.cpp" line="55"/>
<source>Translation language not set</source> <source>Translation language not set</source>
<translation>Не задан язык перевода</translation> <translation>Не задан язык перевода</translation>
</message> </message>
@ -839,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>Без коррекции:
@ -914,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>
@ -979,132 +983,132 @@ 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="619"/> <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="636"/> <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="643"/> <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="693"/> <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="700"/> <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="716"/> <location filename="../../src/settingseditor.ui" line="700"/>
<source>Check now</source> <source>Check now</source>
<translation>Проверить сейчас</translation> <translation>Проверить сейчас</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="54"/> <location filename="../../src/settingseditor.cpp" line="53"/>
<source>General</source> <source>General</source>
<translation>Основное</translation> <translation>Основное</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="54"/> <location filename="../../src/settingseditor.cpp" line="53"/>
<source>This page contains general program settings</source> <source>This page contains general program settings</source>
<translation>Эта страница содержит общие настройки программы</translation> <translation>Эта страница содержит общие настройки программы</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="57"/> <location filename="../../src/settingseditor.cpp" line="56"/>
<source>Recognition</source> <source>Recognition</source>
<translation>Распознавание</translation> <translation>Распознавание</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="58"/> <location filename="../../src/settingseditor.cpp" line="57"/>
<source>This page contains text recognition settings. It shows the available languages that program can convert from image to text</source> <source>This page contains text recognition settings. It shows the available languages that program can convert from image to text</source>
<translation>Эта страница содержит настройки распознавания текста. На ней представлены языки, которые программа может преобразовать из изображения в текст</translation> <translation>Эта страница содержит настройки распознавания текста. На ней представлены языки, которые программа может преобразовать из изображения в текст</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="63"/> <location filename="../../src/settingseditor.cpp" line="62"/>
<source>Correction</source> <source>Correction</source>
<translation>Коррекция</translation> <translation>Коррекция</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="64"/> <location filename="../../src/settingseditor.cpp" line="63"/>
<source>This page contains recognized text correction settings. It allows to fix some errors after recognition. <source>This page contains recognized text correction settings. It allows to fix some errors after recognition.
Hunspell searches for words that are similar to recognized ones in its dictionary. Hunspell searches for words that are similar to recognized ones in its dictionary.
User correction allows to manually fix some frequently happening mistakes. User correction allows to manually fix some frequently happening mistakes.
@ -1115,87 +1119,84 @@ Hunspell ищет в своем словаре слова, похожие на
Пользовательская коррекция выполняется до коррекции hunspell, если они обе активированы</translation> Пользовательская коррекция выполняется до коррекции hunspell, если они обе активированы</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="74"/> <location filename="../../src/settingseditor.cpp" line="73"/>
<source>Translation</source> <source>Translation</source>
<translation>Перевод</translation> <translation>Перевод</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="75"/> <location filename="../../src/settingseditor.cpp" line="74"/>
<source>This page contains settings, related to translation of the recognized text. Translation is done via enabled (checked) translation services. If one fails, then second one will be used and so on. If translator hangs it will be treated as failed after given timeout</source> <source>This page contains settings, related to translation of the recognized text. Translation is done via enabled (checked) translation services. If one fails, then second one will be used and so on. If translator hangs it will be treated as failed after given timeout</source>
<translation>Эта страница содержит настройки перевода распознанного текста. Перевод выполняется через активированные (выделенные) сервисы перевода. Если один переводчик не может перевести тест, то используется следующие и т.д. Если переводчик не отвечает в течение заданного времени, то также выполняется переход к следующему</translation> <translation>Эта страница содержит настройки перевода распознанного текста. Перевод выполняется через активированные (выделенные) сервисы перевода. Если один переводчик не может перевести тест, то используется следующие и т.д. Если переводчик не отвечает в течение заданного времени, то также выполняется переход к следующему</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="83"/> <location filename="../../src/settingseditor.cpp" line="82"/>
<source>Representation</source> <source>Representation</source>
<translation>Отображение</translation> <translation>Отображение</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="84"/> <location filename="../../src/settingseditor.cpp" line="83"/>
<source>This page contains result representation settings</source> <source>This page contains result representation settings</source>
<translation>Эта страница содержит настройки отображения результатов</translation> <translation>Эта страница содержит настройки отображения результатов</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="87"/> <location filename="../../src/settingseditor.cpp" line="86"/>
<source>Update</source> <source>Update</source>
<translation>Обновление</translation> <translation>Обновление</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="88"/> <location filename="../../src/settingseditor.cpp" line="87"/>
<source>This page allow to install/update/remove program resources</source> <source>This page allow to install/update/remove program resources</source>
<translation>Эта страница позволяет устанавливать,обновлять и удалять ресурсы, используемые программой</translation> <translation>Эта страница позволяет устанавливать,обновлять и удалять ресурсы, используемые программой</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="90"/> <location filename="../../src/settingseditor.cpp" line="89"/>
<source>Help</source> <source>Help</source>
<translation>Помощь</translation> <translation>Помощь</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="110"/> <location filename="../../src/settingseditor.cpp" line="109"/>
<source>Disabled</source> <source>Disabled</source>
<translation>Отключен</translation> <translation>Отключен</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="111"/> <location filename="../../src/settingseditor.cpp" line="110"/>
<source>System</source> <source>System</source>
<translation>Системный</translation> <translation>Системный</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="112"/> <location filename="../../src/settingseditor.cpp" line="111"/>
<source>SOCKS 5</source> <source>SOCKS 5</source>
<translation>SOCKS 5</translation> <translation>SOCKS 5</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="113"/> <location filename="../../src/settingseditor.cpp" line="112"/>
<source>HTTP</source> <source>HTTP</source>
<translation>HTTP</translation> <translation>HTTP</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="127"/>
<source>Optimized</source> <source>Optimized</source>
<translation>Оптимизированная</translation> <translation type="vanished">Оптимизированная</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="128"/>
<source>Compatible</source> <source>Compatible</source>
<translation>Совместимая</translation> <translation type="vanished">Совместимая</translation>
</message> </message>
<message> <message>
<location filename="../../src/settingseditor.cpp" line="132"/>
<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="144"/> <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="152"/> <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="200"/> <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
@ -1218,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="365"/> <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>
@ -1292,53 +1293,53 @@ Most likely they are already in use by another program</source>
Скорее всего они уже используются какой-то программой</translation> Скорее всего они уже используются какой-то программой</translation>
</message> </message>
<message> <message>
<location filename="../../src/trayicon.cpp" line="156"/> <location filename="../../src/trayicon.cpp" line="166"/>
<location filename="../../src/trayicon.cpp" line="163"/> <location filename="../../src/trayicon.cpp" line="173"/>
<source>Error</source> <source>Error</source>
<translation>Ошибка</translation> <translation>Ошибка</translation>
</message> </message>
<message> <message>
<location filename="../../src/trayicon.cpp" line="194"/> <location filename="../../src/trayicon.cpp" line="204"/>
<source>Capture</source> <source>Capture</source>
<translation>Захват</translation> <translation>Захват</translation>
</message> </message>
<message> <message>
<location filename="../../src/trayicon.cpp" line="199"/> <location filename="../../src/trayicon.cpp" line="209"/>
<source>Repeat capture</source> <source>Repeat capture</source>
<translation>Повторить захват</translation> <translation>Повторить захват</translation>
</message> </message>
<message> <message>
<location filename="../../src/trayicon.cpp" line="204"/> <location filename="../../src/trayicon.cpp" line="214"/>
<source>Capture saved areas</source> <source>Capture saved areas</source>
<translation>Захват сохраненных зон</translation> <translation>Захват сохраненных зон</translation>
</message> </message>
<message> <message>
<location filename="../../src/trayicon.cpp" line="210"/> <location filename="../../src/trayicon.cpp" line="220"/>
<source>Result</source> <source>Result</source>
<translation>Результат</translation> <translation>Результат</translation>
</message> </message>
<message> <message>
<location filename="../../src/trayicon.cpp" line="212"/> <location filename="../../src/trayicon.cpp" line="222"/>
<source>Show</source> <source>Show</source>
<translation>Показать</translation> <translation>Показать</translation>
</message> </message>
<message> <message>
<location filename="../../src/trayicon.cpp" line="217"/> <location filename="../../src/trayicon.cpp" line="227"/>
<source>To clipboard</source> <source>To clipboard</source>
<translation>В буфер обмена</translation> <translation>В буфер обмена</translation>
</message> </message>
<message> <message>
<location filename="../../src/trayicon.cpp" line="224"/> <location filename="../../src/trayicon.cpp" line="234"/>
<source>Show translator</source> <source>Show translator</source>
<translation>Показать переводчик</translation> <translation>Показать переводчик</translation>
</message> </message>
<message> <message>
<location filename="../../src/trayicon.cpp" line="230"/> <location filename="../../src/trayicon.cpp" line="240"/>
<source>Settings</source> <source>Settings</source>
<translation>Настройки</translation> <translation>Настройки</translation>
</message> </message>
<message> <message>
<location filename="../../src/trayicon.cpp" line="236"/> <location filename="../../src/trayicon.cpp" line="246"/>
<source>Quit</source> <source>Quit</source>
<translation>Выход</translation> <translation>Выход</translation>
</message> </message>
@ -1457,6 +1458,14 @@ Error %2</source>
<translation>таймаут</translation> <translation>таймаут</translation>
</message> </message>
</context> </context>
<context>
<name>service::KeySequenceEdit</name>
<message>
<location filename="../../src/service/keysequenceedit.cpp" line="10"/>
<source>Press shortcut</source>
<translation>Нажмите на клавиши</translation>
</message>
</context>
<context> <context>
<name>update::Loader</name> <name>update::Loader</name>
<message> <message>

View File

@ -12,7 +12,8 @@ CaptureArea::CaptureArea(const QRect &rect, const Settings &settings)
{ {
} }
TaskPtr CaptureArea::task(const QPixmap &pixmap) const TaskPtr CaptureArea::task(const QPixmap &pixmap,
const QPoint &pixmapOffset) const
{ {
if (pixmap.isNull() || !isValid()) if (pixmap.isNull() || !isValid())
return {}; return {};
@ -21,7 +22,7 @@ TaskPtr CaptureArea::task(const QPixmap &pixmap) const
task->generation = generation_; task->generation = generation_;
task->useHunspell = useHunspell_; task->useHunspell = useHunspell_;
task->captured = pixmap.copy(rect_); task->captured = pixmap.copy(rect_);
task->capturePoint = rect_.topLeft(); task->capturePoint = pixmapOffset + rect_.topLeft();
task->sourceLanguage = sourceLanguage_; task->sourceLanguage = sourceLanguage_;
if (task->sourceLanguage.isEmpty()) if (task->sourceLanguage.isEmpty())
task->error += QObject::tr("No source language set"); task->error += QObject::tr("No source language set");

View File

@ -11,7 +11,7 @@ class CaptureArea
{ {
public: public:
CaptureArea(const QRect& rect, const Settings& settings); CaptureArea(const QRect& rect, const Settings& settings);
TaskPtr task(const QPixmap& pixmap) const; TaskPtr task(const QPixmap& pixmap, const QPoint& pixmapOffset) const;
void setGeneration(uint generation); void setGeneration(uint generation);
bool isValid() const; bool isValid() const;

View File

@ -22,10 +22,12 @@ static bool notLocked(const std::shared_ptr<CaptureArea> &area)
CaptureAreaSelector::CaptureAreaSelector(Capturer &capturer, CaptureAreaSelector::CaptureAreaSelector(Capturer &capturer,
const Settings &settings, const Settings &settings,
const CommonModels &models, const CommonModels &models,
const QPixmap &pixmap) const QPixmap &pixmap,
const QPoint &pixmapOffset)
: capturer_(capturer) : capturer_(capturer)
, settings_(settings) , settings_(settings)
, pixmap_(pixmap) , pixmap_(pixmap)
, pixmapOffset_(pixmapOffset)
, editor_(std::make_unique<CaptureAreaEditor>(models, this)) , editor_(std::make_unique<CaptureAreaEditor>(models, this))
, contextMenu_(new QMenu(this)) , contextMenu_(new QMenu(this))
{ {
@ -56,7 +58,7 @@ CaptureAreaSelector::~CaptureAreaSelector() = default;
void CaptureAreaSelector::activate() void CaptureAreaSelector::activate()
{ {
setGeometry(pixmap_.rect()); setGeometry(QRect(pixmapOffset_, pixmap_.size()));
show(); show();
activateWindow(); activateWindow();
} }
@ -337,7 +339,7 @@ void CaptureAreaSelector::customize(const std::shared_ptr<CaptureArea> &area)
edited_ = area; edited_ = area;
editor_->show(); editor_->show();
const auto topLeft = service::geometry::cornerAtPoint( const auto topLeft = service::geometry::cornerAtPoint(
area->rect().center(), editor_->size(), geometry()); area->rect().center(), editor_->size(), QRect({}, size()));
editor_->move(topLeft); editor_->move(topLeft);
update(); update();
} }

View File

@ -12,7 +12,8 @@ class CaptureAreaSelector : public QWidget
public: public:
CaptureAreaSelector(Capturer &capturer, const Settings &settings, CaptureAreaSelector(Capturer &capturer, const Settings &settings,
const CommonModels &models, const QPixmap &pixmap); const CommonModels &models, const QPixmap &pixmap,
const QPoint &pixmapOffset);
~CaptureAreaSelector(); ~CaptureAreaSelector();
void activate(); void activate();
@ -50,6 +51,7 @@ private:
Capturer &capturer_; Capturer &capturer_;
const Settings &settings_; const Settings &settings_;
const QPixmap &pixmap_; const QPixmap &pixmap_;
const QPoint &pixmapOffset_;
Generation generation_{}; Generation generation_{};
QPoint startSelectPos_; QPoint startSelectPos_;
QPoint currentSelectPos_; QPoint currentSelectPos_;

View File

@ -4,7 +4,7 @@
#include "debug.h" #include "debug.h"
#include "manager.h" #include "manager.h"
#include "settings.h" #include "settings.h"
#include "waylandcapturer.h" #include "task.h"
#include <QApplication> #include <QApplication>
#include <QPainter> #include <QPainter>
@ -15,8 +15,7 @@ Capturer::Capturer(Manager &manager, const Settings &settings,
: manager_(manager) : manager_(manager)
, settings_(settings) , settings_(settings)
, selector_(std::make_unique<CaptureAreaSelector>(*this, settings_, models, , selector_(std::make_unique<CaptureAreaSelector>(*this, settings_, models,
pixmap_)) pixmap_, pixmapOffset_))
, wayland_(WaylandCapturer::create())
{ {
} }
@ -57,25 +56,20 @@ void Capturer::updatePixmap()
QPixmap combined(rect.size()); QPixmap combined(rect.size());
QPainter p(&combined); QPainter p(&combined);
p.translate(-rect.topLeft());
if (!wayland_) {
for (const auto screen : screens) { for (const auto screen : screens) {
const auto geometry = screen->geometry(); const auto geometry = screen->geometry();
const auto pixmap = const auto pixmap =
screen->grabWindow(0, 0, 0, geometry.width(), geometry.height()); screen->grabWindow(0, 0, 0, geometry.width(), geometry.height());
p.drawPixmap(geometry, pixmap); p.drawPixmap(geometry, pixmap);
} }
} else {
auto pix = wayland_->grab();
if (!pix.isNull()) {
p.drawPixmap(0, 0, pix);
} else {
combined.fill(Qt::black);
}
}
SOFT_ASSERT(selector_, return ); SOFT_ASSERT(selector_, return );
pixmap_ = combined; pixmap_ = combined;
pixmapOffset_ = rect.topLeft();
for (auto &r : screenRects) r.translate(-rect.topLeft());
selector_->setScreenRects(screenRects); selector_->setScreenRects(screenRects);
} }
@ -97,7 +91,7 @@ void Capturer::selected(const CaptureArea &area)
selector_->hide(); selector_->hide();
SOFT_ASSERT(!pixmap_.isNull(), return manager_.captureCanceled()) SOFT_ASSERT(!pixmap_.isNull(), return manager_.captureCanceled())
auto task = area.task(pixmap_); auto task = area.task(pixmap_, pixmapOffset_);
if (task) if (task)
manager_.captured(task); manager_.captured(task);
else else

View File

@ -4,8 +4,6 @@
#include <QPixmap> #include <QPixmap>
class WaylandCapturer;
class Capturer class Capturer
{ {
public: public:
@ -28,6 +26,6 @@ private:
Manager &manager_; Manager &manager_;
const Settings &settings_; const Settings &settings_;
QPixmap pixmap_; QPixmap pixmap_;
QPoint pixmapOffset_;
std::unique_ptr<CaptureAreaSelector> selector_; std::unique_ptr<CaptureAreaSelector> selector_;
std::unique_ptr<WaylandCapturer> wayland_;
}; };

View File

@ -1,197 +0,0 @@
#include "waylandcapturer.h"
#include "debug.h"
#ifdef Q_OS_LINUX
#include <QCoreApplication>
#include <QDBusConnection>
#include <QDBusPendingReply>
#include <QDir>
#include <QTemporaryFile>
#include <QUrl>
namespace
{
QString desktopFile()
{
auto name = QCoreApplication::applicationName().toLower() +
QLatin1String("-screenshot-permission");
name.remove(QLatin1Char(' '));
const auto result = QDir::homePath() +
QLatin1String("/.local/share/applications/") + name +
QLatin1String(".desktop");
return result;
}
void removeDesktop()
{
QFile::remove(desktopFile());
}
void writeDesktop()
{
QFile f(desktopFile());
if (!f.open(QFile::WriteOnly))
return;
const auto contents = QString(R"([Desktop Entry]
Name=%1-screen-permission
Exec=%2
X-KDE-DBUS-Restricted-Interfaces=org.kde.kwin.Screenshot
)")
.arg(QCoreApplication::applicationName(),
QCoreApplication::applicationFilePath());
f.write(contents.toUtf8());
}
} // namespace
bool WaylandCapturerImpl::isWayland()
{
return qEnvironmentVariable("XDG_SESSION_TYPE").toLower() ==
QStringLiteral("wayland");
}
WaylandCapturerImpl::Method WaylandCapturerImpl::getMethod()
{
auto de = qEnvironmentVariable("XDG_CURRENT_DESKTOP").toLower();
if (de == QLatin1String("kde")) {
return Method::Kde;
} else if (de.endsWith(QLatin1String("gnome"))) {
return Method::Gnome;
}
return Method::Freedesktop;
}
WaylandCapturerImpl::WaylandCapturerImpl()
: method_(getMethod())
{
if (method_ == Method::Kde)
writeDesktop();
}
WaylandCapturerImpl::~WaylandCapturerImpl()
{
if (method_ == Method::Kde)
removeDesktop();
}
QPixmap WaylandCapturerImpl::grab()
{
switch (method_) {
case Method::Gnome: return grabGnome();
case Method::Kde: return grabKde();
case Method::Freedesktop: return grabFreedesktop();
}
return {};
}
QPixmap WaylandCapturerImpl::grabKde()
{
auto request = QDBusMessage::createMethodCall(
QStringLiteral("org.kde.KWin"), QStringLiteral("/Screenshot"),
QStringLiteral("org.kde.kwin.Screenshot"),
QStringLiteral("screenshotFullscreen"));
request << false;
auto reply = QDBusConnection::sessionBus().call(request);
const auto args = reply.arguments();
if (reply.type() == QDBusMessage::ErrorMessage || args.isEmpty()) {
LERROR() << "kde capture error" << reply;
return {};
}
const auto fileName = args.first().toString();
auto result = QPixmap(fileName);
QFile::remove(fileName);
return result;
}
QPixmap WaylandCapturerImpl::grabGnome()
{
auto request = QDBusMessage::createMethodCall(
QStringLiteral("org.gnome.Shell.Screenshot"),
QStringLiteral("/org/gnome/Shell/Screenshot"),
QStringLiteral("org.gnome.Shell.Screenshot"),
QStringLiteral("Screenshot"));
QTemporaryFile f;
if (!f.open()) {
LERROR() << "failed to create temp file" << f.errorString();
return {};
}
f.close();
request << false << false << f.fileName();
auto reply = QDBusConnection::sessionBus().call(request);
const auto args = reply.arguments();
if (reply.type() == QDBusMessage::ErrorMessage || args.isEmpty()) {
LERROR() << "gnome capture error" << reply;
return {};
}
if (!args.first().toBool()) {
LERROR() << "gnome capture error";
return {};
}
return QPixmap(f.fileName());
}
QPixmap WaylandCapturerImpl::grabFreedesktop()
{
auto request = QDBusMessage::createMethodCall(
QStringLiteral("org.freedesktop.portal.Desktop"),
QStringLiteral("/org/freedesktop/portal/desktop"),
QStringLiteral("org.freedesktop.portal.Screenshot"),
QStringLiteral("Screenshot"));
request << QStringLiteral("") << QVariantMap{};
auto reply = QDBusConnection::sessionBus().call(request);
const auto args = reply.arguments();
if (reply.type() == QDBusMessage::ErrorMessage || args.isEmpty()) {
LERROR() << "freedesktop capture error" << reply;
return {};
}
const auto handleArg = args.first();
if (!handleArg.canConvert<QDBusObjectPath>()) {
LERROR() << "wrong type in freedesktop ansert" << handleArg.userType();
return {};
}
const auto handle = handleArg.value<QDBusObjectPath>().path();
QDBusConnection::sessionBus().connect(
QStringLiteral("org.freedesktop.portal.Desktop"), handle,
QStringLiteral("org.freedesktop.portal.Request"),
QStringLiteral("Response"), this, SLOT(getScreen(uint, QVariantMap)));
loop_.exec();
return result_;
}
void WaylandCapturerImpl::parseFreedesktopResult(uint response,
const QVariantMap &results)
{
if (response == 0) {
const auto name = QUrl(results["uri"].toString()).toLocalFile();
result_.load(name);
QFile::remove(name);
}
loop_.exit();
}
#endif
std::unique_ptr<WaylandCapturer> WaylandCapturer::create()
{
#ifdef Q_OS_LINUX
if (WaylandCapturerImpl::isWayland())
return std::make_unique<WaylandCapturerImpl>();
#endif
return {};
}

View File

@ -1,46 +0,0 @@
#pragma once
#include <QEventLoop>
#include <QObject>
#include <QPixmap>
class WaylandCapturer
{
public:
virtual ~WaylandCapturer() = default;
virtual QPixmap grab() = 0;
static std::unique_ptr<WaylandCapturer> create();
};
#ifdef Q_OS_LINUX
class WaylandCapturerImpl : public QObject, public WaylandCapturer
{
Q_OBJECT
public:
WaylandCapturerImpl();
~WaylandCapturerImpl();
static bool isWayland();
QPixmap grab() override;
private slots:
void parseFreedesktopResult(uint response, const QVariantMap &results);
private:
enum class Method { Gnome, Kde, Freedesktop };
static Method getMethod();
QPixmap grabKde();
QPixmap grabGnome();
QPixmap grabFreedesktop();
Method method_;
QEventLoop loop_;
QPixmap result_;
};
#endif

View File

@ -11,7 +11,8 @@ CommonModels::CommonModels()
CommonModels::~CommonModels() = default; CommonModels::~CommonModels() = default;
void CommonModels::update(const QString &tessdataPath) void CommonModels::update(const QString &tessdataPath,
const QString &translatorPath)
{ {
{ {
auto names = Tesseract::availableLanguageNames(tessdataPath); auto names = Tesseract::availableLanguageNames(tessdataPath);
@ -19,6 +20,11 @@ void CommonModels::update(const QString &tessdataPath)
sourceLanguageModel_->setStringList(names); sourceLanguageModel_->setStringList(names);
} }
{
translators_ = Translator::availableTranslators(translatorPath);
std::sort(translators_.begin(), translators_.end());
}
if (targetLanguageModel_->rowCount() > 0) if (targetLanguageModel_->rowCount() > 0)
return; return;
@ -38,3 +44,8 @@ QStringListModel *CommonModels::targetLanguageModel() const
{ {
return targetLanguageModel_.get(); return targetLanguageModel_.get();
} }
const QStringList &CommonModels::translators() const
{
return translators_;
}

View File

@ -12,12 +12,14 @@ public:
CommonModels(); CommonModels();
~CommonModels(); ~CommonModels();
void update(const QString& tessdataPath); void update(const QString& tessdataPath, const QString& translatorPath);
QStringListModel* sourceLanguageModel() const; QStringListModel* sourceLanguageModel() const;
QStringListModel* targetLanguageModel() const; QStringListModel* targetLanguageModel() const;
const QStringList& translators() const;
private: private:
std::unique_ptr<QStringListModel> sourceLanguageModel_; std::unique_ptr<QStringListModel> sourceLanguageModel_;
std::unique_ptr<QStringListModel> targetLanguageModel_; std::unique_ptr<QStringListModel> targetLanguageModel_;
QStringList translators_;
}; };

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";
} }
@ -75,7 +75,7 @@ void Corrector::processQueue()
void Corrector::updateSettings() void Corrector::updateSettings()
{ {
queue_.clear(); queue_.clear();
emit resetAuto(settings_.hunspellDir); emit resetAuto(settings_.hunspellPath);
} }
void Corrector::finishCorrection(const TaskPtr &task) void Corrector::finishCorrection(const TaskPtr &task)

View File

@ -198,7 +198,7 @@ const std::unordered_map<LanguageId, LanguageCodes::Bundle>
{I("chi_sim_vert"), {I("chi_sim_vert"), S("zh-CN"), S("chi_sim_vert"), QT_TRANSLATE_NOOP("QObject", "Chinese (Simplified) vertical")}}, {I("chi_sim_vert"), {I("chi_sim_vert"), S("zh-CN"), S("chi_sim_vert"), QT_TRANSLATE_NOOP("QObject", "Chinese (Simplified) vertical")}},
{I("chi_tra"), {I("chi_tra"), S("zh-TW"), S("chi_tra"), QT_TRANSLATE_NOOP("QObject", "Chinese (Traditional)")}}, {I("chi_tra"), {I("chi_tra"), S("zh-TW"), S("chi_tra"), QT_TRANSLATE_NOOP("QObject", "Chinese (Traditional)")}},
{I("chi_tra_vert"), {I("chi_tra_vert"), S("zh-TW"), S("chi_tra_vert"), QT_TRANSLATE_NOOP("QObject", "Chinese (Traditional) vertical")}}, {I("chi_tra_vert"), {I("chi_tra_vert"), S("zh-TW"), S("chi_tra_vert"), QT_TRANSLATE_NOOP("QObject", "Chinese (Traditional) vertical")}},
{I("fil"), {I("fil"), S(""), S("fil"), QT_TRANSLATE_NOOP("QObject", "Filipino")}}, {I("fil"), {I("fil"), S("tl"), S("fil"), QT_TRANSLATE_NOOP("QObject", "Filipino")}},
{I("chr"), {I("chr"), S(""), S("chr"), QT_TRANSLATE_NOOP("QObject", "Cherokee")}}, {I("chr"), {I("chr"), S(""), S("chr"), QT_TRANSLATE_NOOP("QObject", "Cherokee")}},
{I("ceb"), {I("ceb"), S(""), S("ceb"), QT_TRANSLATE_NOOP("QObject", "Cebuano")}}, {I("ceb"), {I("ceb"), S(""), S("ceb"), QT_TRANSLATE_NOOP("QObject", "Cebuano")}},
{I("syr"), {I("syr"), S(""), S("syr"), QT_TRANSLATE_NOOP("QObject", "Syriac")}}, {I("syr"), {I("syr"), S(""), S("syr"), QT_TRANSLATE_NOOP("QObject", "Syriac")}},

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

@ -109,7 +109,7 @@ void Manager::updateSettings()
setupProxy(*settings_); setupProxy(*settings_);
setupUpdates(*settings_); setupUpdates(*settings_);
models_->update(settings_->tessdataPath); models_->update(settings_->tessdataPath, settings_->translatorsPath);
tray_->updateSettings(); tray_->updateSettings();
capturer_->updateSettings(); capturer_->updateSettings();
@ -120,7 +120,9 @@ void Manager::updateSettings()
tray_->setCaptureLockedEnabled(capturer_->canCaptureLocked()); tray_->setCaptureLockedEnabled(capturer_->canCaptureLocked());
const auto errors = SettingsValidator().check(*settings_, *models_); SettingsValidator validator;
validator.correct(*settings_, *models_);
const auto errors = validator.check(*settings_, *models_);
if (errors.isEmpty()) if (errors.isEmpty())
return; return;
@ -155,9 +157,9 @@ void Manager::setupProxy(const Settings &settings)
void Manager::setupUpdates(const Settings &settings) void Manager::setupUpdates(const Settings &settings)
{ {
updater_->setExpansions({ updater_->setExpansions({
{"$translators$", settings.translatorsDir}, {"$translators$", settings.translatorsPath},
{"$tessdata$", settings.tessdataPath}, {"$tessdata$", settings.tessdataPath},
{"$hunspell$", settings.hunspellDir}, {"$hunspell$", settings.hunspellPath},
{"$appdir$", QApplication::applicationDirPath()}, {"$appdir$", QApplication::applicationDirPath()},
}); });

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_);
pix_ = pix;
} }
operator Pix *() { return pix_; }
LTRACE() << "Loaded tesseract library" << lib.fileName(); Pix *operator->() { return pix_; }
auto ok = true; Pix *&get() { return pix_; }
ok &= bool(createApi_ = (CreateApi)lib.resolve("TessBaseAPICreate")); Pix *take()
ok &= bool(deleteApi_ = (DeleteApi)lib.resolve("TessBaseAPIDelete")); {
ok &= bool(initApi_ = (InitApi)lib.resolve("TessBaseAPIInit2")); auto ret = pix_;
ok &= bool(setImage_ = (SetImage)lib.resolve("TessBaseAPISetImage2")); pix_ = nullptr;
ok &= bool(getUtf8_ = (GetUtf8)lib.resolve("TessBaseAPIGetUTF8Text")); return ret;
ok &= bool(clearApi_ = (ClearApi)lib.resolve("TessBaseAPIClear")); }
ok &= bool(deleteUtf8_ = (DeleteUtf8)lib.resolve("TessDeleteText")); void trace(const QString &name) const
ok &= bool(setPageMode_ = {
(SetPageMode)lib.resolve("TessBaseAPISetPageSegMode")); LTRACE() << qPrintable(name) << pix_;
if (!ok) { #if 0
LERROR() << "Failed to resolve tesseract functions from" << libraryName; 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

@ -135,6 +135,10 @@ bool Representer::eventFilter(QObject * /*watched*/, QEvent *event)
const auto casted = static_cast<QMouseEvent *>(event); const auto casted = static_cast<QMouseEvent *>(event);
if (casted->button() == Qt::LeftButton) if (casted->button() == Qt::LeftButton)
hide(); hide();
} else if (event->type() == QEvent::KeyPress) {
const auto casted = static_cast<QKeyEvent *>(event);
if (casted->key() == Qt::Key_Escape)
hide();
} }
return false; return false;
} }

View File

@ -11,13 +11,15 @@
#include <QLabel> #include <QLabel>
#include <QMenu> #include <QMenu>
#include <QMouseEvent> #include <QMouseEvent>
#include <QScreen>
ResultWidget::ResultWidget(Manager &manager, Representer &representer, ResultWidget::ResultWidget(Manager &manager, Representer &representer,
const Settings &settings, QWidget *parent) const Settings &settings, QWidget *parent)
: QFrame(parent) : QFrame(parent)
, representer_(representer) , representer_(representer)
, settings_(settings) , settings_(settings)
, image_(new QLabel(this)) , imagePlaceholder_(new QWidget(this))
, image_(new QLabel(imagePlaceholder_))
, recognized_(new QLabel(this)) , recognized_(new QLabel(this))
, separator_(new QLabel(this)) , separator_(new QLabel(this))
, translated_(new QLabel(this)) , translated_(new QLabel(this))
@ -30,8 +32,6 @@ ResultWidget::ResultWidget(Manager &manager, Representer &representer,
setFrameShape(QFrame::StyledPanel); setFrameShape(QFrame::StyledPanel);
setFrameShadow(QFrame::Plain); setFrameShadow(QFrame::Plain);
image_->setAlignment(Qt::AlignCenter);
recognized_->setAlignment(Qt::AlignCenter); recognized_->setAlignment(Qt::AlignCenter);
recognized_->setWordWrap(true); recognized_->setWordWrap(true);
@ -65,7 +65,7 @@ ResultWidget::ResultWidget(Manager &manager, Representer &representer,
installEventFilter(this); installEventFilter(this);
auto layout = new QVBoxLayout(this); auto layout = new QVBoxLayout(this);
layout->addWidget(image_); layout->addWidget(imagePlaceholder_);
layout->addWidget(recognized_); layout->addWidget(recognized_);
layout->addWidget(separator_); layout->addWidget(separator_);
layout->addWidget(translated_); layout->addWidget(translated_);
@ -86,6 +86,8 @@ void ResultWidget::show(const TaskPtr &task)
task_ = task; task_ = task;
image_->setPixmap(task->captured); image_->setPixmap(task->captured);
image_->resize(task->captured.size());
imagePlaceholder_->setMinimumSize(image_->size());
recognized_->setText(task->corrected); recognized_->setText(task->corrected);
const auto tooltip = task->recognized == task->corrected const auto tooltip = task->recognized == task->corrected
@ -106,20 +108,37 @@ void ResultWidget::show(const TaskPtr &task)
show(); show();
adjustSize(); adjustSize();
if (!image_->isVisible()) // window should not be smaller than selected image
if (!imagePlaceholder_->isVisible())
resize(std::max(width(), task->captured.width()), resize(std::max(width(), task->captured.width()),
std::max(height(), task->captured.height())); std::max(height(), task->captured.height()));
QDesktopWidget *desktop = QApplication::desktop(); // if window is wider than image then image should be at horizontal center
Q_CHECK_PTR(desktop); const auto correctionToCenterImage =
const auto correction = QPoint((width() - task->captured.width()) / 2, 2 * lineWidth());
QPoint((width() - task->captured.width()) / 2, lineWidth()); auto rect = QRect(task->capturePoint - correctionToCenterImage, size());
auto rect = QRect(task->capturePoint - correction, size());
const auto screenRect = desktop->screenGeometry(this); auto screen = QApplication::screenAt(task->capturePoint);
SOFT_ASSERT(screen, return );
const auto screenRect = screen->geometry();
// window should not exceed horizontal borders
if (rect.right() > screenRect.right())
rect.moveRight(screenRect.right());
if (rect.left() < screenRect.left())
rect.moveLeft(screenRect.left());
// image should be where it was selected
if (imagePlaceholder_->isVisible()) {
const auto imageOffset =
task->capturePoint.x() - rect.left() - 2 * lineWidth();
image_->move(imageOffset, image_->y());
}
// window should not exceed vertical borders
const auto shouldTextOnTop = rect.bottom() > screenRect.bottom(); const auto shouldTextOnTop = rect.bottom() > screenRect.bottom();
if (shouldTextOnTop) if (shouldTextOnTop)
rect.moveBottom(rect.top() + task->captured.height() + lineWidth()); rect.moveBottom(rect.top() + task->captured.height() + 3 * lineWidth());
auto layout = static_cast<QBoxLayout *>(this->layout()); auto layout = static_cast<QBoxLayout *>(this->layout());
SOFT_ASSERT(layout, return ); SOFT_ASSERT(layout, return );
@ -156,7 +175,7 @@ void ResultWidget::updateSettings()
palette.setColor(QPalette::Window, separatorColor); palette.setColor(QPalette::Window, separatorColor);
separator_->setPalette(palette); separator_->setPalette(palette);
image_->setVisible(settings_.showCaptured); imagePlaceholder_->setVisible(settings_.showCaptured);
} }
void ResultWidget::mousePressEvent(QMouseEvent *event) void ResultWidget::mousePressEvent(QMouseEvent *event)

View File

@ -31,6 +31,7 @@ private:
Representer& representer_; Representer& representer_;
const Settings& settings_; const Settings& settings_;
TaskPtr task_; TaskPtr task_;
QWidget* imagePlaceholder_;
QLabel* image_; QLabel* image_;
QLabel* recognized_; QLabel* recognized_;
QLabel* separator_; QLabel* separator_;

View File

@ -153,6 +153,9 @@ quint32 GlobalAction::nativeKeycode(Qt::Key key)
{ {
Display *display = QX11Info::display(); Display *display = QX11Info::display();
KeySym keySym = XStringToKeysym(qPrintable(QKeySequence(key).toString())); KeySym keySym = XStringToKeysym(qPrintable(QKeySequence(key).toString()));
if (XKeysymToString(keySym) == nullptr) {
keySym = QChar(key).unicode();
}
return XKeysymToKeycode(display, keySym); return XKeysymToKeycode(display, keySym);
} }
@ -223,6 +226,9 @@ quint32 GlobalAction::nativeKeycode(Qt::Key key)
case Qt::Key_Down: return VK_DOWN; case Qt::Key_Down: return VK_DOWN;
case Qt::Key_PageUp: return VK_PRIOR; case Qt::Key_PageUp: return VK_PRIOR;
case Qt::Key_PageDown: return VK_NEXT; case Qt::Key_PageDown: return VK_NEXT;
case Qt::Key_CapsLock: return VK_CAPITAL;
case Qt::Key_NumLock: return VK_NUMLOCK;
case Qt::Key_ScrollLock: return VK_SCROLL;
case Qt::Key_F1: return VK_F1; case Qt::Key_F1: return VK_F1;
case Qt::Key_F2: return VK_F2; case Qt::Key_F2: return VK_F2;
case Qt::Key_F3: return VK_F3; case Qt::Key_F3: return VK_F3;
@ -248,11 +254,27 @@ quint32 GlobalAction::nativeKeycode(Qt::Key key)
case Qt::Key_F23: return VK_F23; case Qt::Key_F23: return VK_F23;
case Qt::Key_F24: return VK_F24; case Qt::Key_F24: return VK_F24;
case Qt::Key_Space: return VK_SPACE; case Qt::Key_Space: return VK_SPACE;
case Qt::Key_QuoteDbl: return VK_OEM_7;
case Qt::Key_Apostrophe: return VK_OEM_7;
case Qt::Key_Period: return VK_DECIMAL;
case Qt::Key_Colon: return VK_OEM_1;
case Qt::Key_Semicolon: return VK_OEM_1;
case Qt::Key_Less: return VK_OEM_COMMA;
case Qt::Key_Greater: return VK_OEM_PERIOD;
case Qt::Key_Question: return VK_OEM_2;
case Qt::Key_BracketLeft: return VK_OEM_4;
case Qt::Key_Backslash: return VK_OEM_5;
case Qt::Key_BracketRight: return VK_OEM_6;
case Qt::Key_QuoteLeft: return VK_OEM_3;
case Qt::Key_BraceLeft: return VK_OEM_4;
case Qt::Key_Bar: return VK_OEM_5;
case Qt::Key_BraceRight: return VK_OEM_6;
case Qt::Key_Asterisk: return VK_MULTIPLY; case Qt::Key_Asterisk: return VK_MULTIPLY;
case Qt::Key_Plus: return VK_ADD; case Qt::Key_Plus: return VK_OEM_PLUS;
case Qt::Key_Comma: return VK_SEPARATOR; case Qt::Key_Comma: return VK_OEM_COMMA;
case Qt::Key_Minus: return VK_SUBTRACT; case Qt::Key_Minus: return VK_OEM_MINUS;
case Qt::Key_Slash: return VK_DIVIDE; case Qt::Key_Slash: return VK_OEM_2;
case Qt::Key_MediaNext: return VK_MEDIA_NEXT_TRACK; case Qt::Key_MediaNext: return VK_MEDIA_NEXT_TRACK;
case Qt::Key_MediaPrevious: return VK_MEDIA_PREV_TRACK; case Qt::Key_MediaPrevious: return VK_MEDIA_PREV_TRACK;
case Qt::Key_MediaPlay: return VK_MEDIA_PLAY_PAUSE; case Qt::Key_MediaPlay: return VK_MEDIA_PLAY_PAUSE;

View File

@ -0,0 +1,71 @@
#include "keysequenceedit.h"
#include <QKeyEvent>
namespace service
{
KeySequenceEdit::KeySequenceEdit(QWidget *parent)
: QLineEdit(parent)
{
setPlaceholderText(tr("Press shortcut"));
setFocusPolicy(Qt::StrongFocus);
setAttribute(Qt::WA_MacShowFocusRect, true);
setAttribute(Qt::WA_InputMethodEnabled, false);
}
const QKeySequence &KeySequenceEdit::keySequence() const
{
return current_;
}
void KeySequenceEdit::setKeySequence(const QKeySequence &newKeySequence)
{
setKeySequence(newKeySequence, true);
}
void KeySequenceEdit::setKeySequence(const QKeySequence &current,
bool updateFallback)
{
current_ = current;
if (updateFallback)
fallback_ = current;
setText(current_.toString(QKeySequence::NativeText));
}
bool KeySequenceEdit::event(QEvent *e)
{
switch (e->type()) {
case QEvent::Shortcut: return true;
case QEvent::ShortcutOverride: e->accept(); return true;
default: break;
}
return QWidget::event(e);
}
void KeySequenceEdit::keyPressEvent(QKeyEvent *event)
{
const auto key = event->key();
if (key == Qt::Key_Control || key == Qt::Key_Meta || key == Qt::Key_Alt ||
key == Qt::Key_Shift || key == Qt::Key_unknown) {
return;
}
if (event->key() == Qt::Key_Escape) {
setKeySequence(fallback_, false);
event->accept();
return;
}
if (event->key() == Qt::Key_Backspace) {
setKeySequence({}, false);
event->accept();
return;
}
QKeySequence seq = event->modifiers() + event->key();
setKeySequence(seq, false);
event->accept();
}
} // namespace service

View File

@ -0,0 +1,25 @@
#pragma once
#include <QLineEdit>
namespace service
{
class KeySequenceEdit : public QLineEdit
{
public:
KeySequenceEdit(QWidget *parent = nullptr);
const QKeySequence &keySequence() const;
void setKeySequence(const QKeySequence &newKeySequence);
bool event(QEvent *event) override;
protected:
void keyPressEvent(QKeyEvent *event) override;
private:
void setKeySequence(const QKeySequence &current, bool updateFallback);
QKeySequence current_;
QKeySequence fallback_;
};
} // namespace service

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

@ -7,6 +7,8 @@
#include <QSettings> #include <QSettings>
#include <QStandardPaths> #include <QStandardPaths>
#include <array>
namespace namespace
{ {
const QString iniFileName() const QString iniFileName()
@ -33,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";
@ -175,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);
@ -263,9 +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();
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);
@ -341,6 +338,6 @@ void Settings::setPortable(bool isPortable)
QStandardPaths::AppDataLocation)) + QStandardPaths::AppDataLocation)) +
"/assets"; "/assets";
tessdataPath = baseDataPath + "/tessdata"; tessdataPath = baseDataPath + "/tessdata";
translatorsDir = baseDataPath + "/translators"; translatorsPath = baseDataPath + "/translators";
hunspellDir = baseDataPath + "/hunspell"; hunspellPath = baseDataPath + "/hunspell";
} }

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:
@ -52,7 +50,7 @@ public:
QDateTime lastUpdateCheck; QDateTime lastUpdateCheck;
bool useHunspell{false}; bool useHunspell{false};
QString hunspellDir; QString hunspellPath;
Substitutions userSubstitutions; Substitutions userSubstitutions;
bool useUserSubstitutions{true}; bool useUserSubstitutions{true};
@ -60,13 +58,12 @@ 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};
LanguageId targetLanguage{"rus"}; LanguageId targetLanguage{"rus"};
std::chrono::seconds translationTimeout{15}; std::chrono::seconds translationTimeout{15};
QString translatorsDir; QString translatorsPath;
QStringList translators{"google.js"}; QStringList translators{"google.js"};
ResultMode resultShowType{ResultMode::Widget}; // dialog ResultMode resultShowType{ResultMode::Widget}; // dialog

View File

@ -4,7 +4,6 @@
#include "manager.h" #include "manager.h"
#include "runatsystemstart.h" #include "runatsystemstart.h"
#include "settingsvalidator.h" #include "settingsvalidator.h"
#include "translator.h"
#include "ui_settingseditor.h" #include "ui_settingseditor.h"
#include "updates.h" #include "updates.h"
#include "widgetstate.h" #include "widgetstate.h"
@ -123,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,11 +182,16 @@ SettingsEditor::SettingsEditor(Manager &manager, update::Updater &updater)
baseUrl + "/blob/master/share/Changelog_" + baseUrl + "/blob/master/share/Changelog_" +
(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
? "https://translator.gres.biz/page/download/"
: 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>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),
@ -264,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();
@ -320,20 +314,20 @@ void SettingsEditor::setSettings(const Settings &settings)
ui->proxySaveCheck->setChecked(settings.proxySavePassword); ui->proxySaveCheck->setChecked(settings.proxySavePassword);
ui->tessdataPath->setText(settings.tessdataPath); ui->tessdataPath->setText(settings.tessdataPath);
ui->translatorsPath->setText(settings.translatorsPath);
updateModels(); updateModels();
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.hunspellDir); ui->hunspellDir->setText(settings.hunspellPath);
ui->useUserSubstitutions->setChecked(settings.useUserSubstitutions); ui->useUserSubstitutions->setChecked(settings.useUserSubstitutions);
ui->userSubstitutionsTable->setSubstitutions(settings.userSubstitutions); ui->userSubstitutionsTable->setSubstitutions(settings.userSubstitutions);
ui->doTranslationCheck->setChecked(settings.doTranslation); ui->doTranslationCheck->setChecked(settings.doTranslation);
ui->ignoreSslCheck->setChecked(settings.ignoreSslErrors); ui->ignoreSslCheck->setChecked(settings.ignoreSslErrors);
ui->translateTimeoutSpin->setValue(settings.translationTimeout.count()); ui->translateTimeoutSpin->setValue(settings.translationTimeout.count());
ui->translatorsPath->setText(settings.translatorsDir);
ui->translateLangCombo->setCurrentText( ui->translateLangCombo->setCurrentText(
LanguageCodes::name(settings.targetLanguage)); LanguageCodes::name(settings.targetLanguage));
updateTranslators(settings.translators); updateTranslators(settings.translators);
@ -363,8 +357,8 @@ void SettingsEditor::updateState()
Settings settings; Settings settings;
settings.setPortable(ui->portable->isChecked()); settings.setPortable(ui->portable->isChecked());
ui->tessdataPath->setText(settings.tessdataPath); ui->tessdataPath->setText(settings.tessdataPath);
ui->translatorsPath->setText(settings.translatorsDir); ui->translatorsPath->setText(settings.translatorsPath);
ui->hunspellDir->setText(settings.hunspellDir); ui->hunspellDir->setText(settings.hunspellPath);
updateModels(); updateModels();
updateTranslators(enabledTranslators()); updateTranslators(enabledTranslators());
@ -402,14 +396,17 @@ void SettingsEditor::updateCurrentPage()
void SettingsEditor::updateTranslators(const QStringList &translators) void SettingsEditor::updateTranslators(const QStringList &translators)
{ {
ui->translatorList->clear(); ui->translatorList->clear();
if (models_.translators().isEmpty())
auto names = Translator::availableTranslators(ui->translatorsPath->text());
if (names.isEmpty())
return; return;
std::sort(names.begin(), names.end()); QStringList all;
for (const auto &i : translators) {
ui->translatorList->addItems(names); if (models_.translators().contains(i))
all.append(i);
}
all += models_.translators();
all.removeDuplicates();
ui->translatorList->addItems(all);
for (auto i = 0, end = ui->translatorList->count(); i < end; ++i) { for (auto i = 0, end = ui->translatorList->count(); i < end; ++i) {
auto item = ui->translatorList->item(i); auto item = ui->translatorList->item(i);
@ -466,7 +463,7 @@ QStringList SettingsEditor::enabledTranslators() const
void SettingsEditor::updateModels() void SettingsEditor::updateModels()
{ {
const auto source = ui->tesseractLangCombo->currentText(); const auto source = ui->tesseractLangCombo->currentText();
models_.update(ui->tessdataPath->text()); models_.update(ui->tessdataPath->text(), ui->translatorsPath->text());
if (!source.isEmpty()) { if (!source.isEmpty()) {
ui->tesseractLangCombo->setCurrentText(source); ui->tesseractLangCombo->setCurrentText(source);
} else if (ui->tesseractLangCombo->count() > 0) { } else if (ui->tesseractLangCombo->count() > 0) {
@ -489,6 +486,15 @@ void SettingsEditor::pickColor(QWidget *widget)
void SettingsEditor::validateSettings() void SettingsEditor::validateSettings()
{ {
SettingsValidator validator;
{
auto settings = this->settings();
if (validator.correct(settings, models_)) {
setSettings(settings);
return;
}
}
for (auto i = 0, end = pageModel_->rowCount(); i < end; ++i) { for (auto i = 0, end = pageModel_->rowCount(); i < end; ++i) {
const auto name = pageModel_->index(i, int(PageColumn::Name)); const auto name = pageModel_->index(i, int(PageColumn::Name));
pageModel_->setData(name, QBrush(Qt::black), Qt::ForegroundRole); pageModel_->setData(name, QBrush(Qt::black), Qt::ForegroundRole);
@ -497,7 +503,6 @@ void SettingsEditor::validateSettings()
pageModel_->setData(error, {}); pageModel_->setData(error, {});
} }
SettingsValidator validator;
const auto errors = validator.check(settings(), models_); const auto errors = validator.check(settings(), models_);
if (errors.isEmpty()) if (errors.isEmpty())
return; return;

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="QKeySequenceEdit" 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="QKeySequenceEdit" 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="QKeySequenceEdit" 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="QKeySequenceEdit" 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="QKeySequenceEdit" 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">
@ -775,6 +765,11 @@
<extends>QTableWidget</extends> <extends>QTableWidget</extends>
<header>substitutionstable.h</header> <header>substitutionstable.h</header>
</customwidget> </customwidget>
<customwidget>
<class>service::KeySequenceEdit</class>
<extends>QWidget</extends>
<header>keysequenceedit.h</header>
</customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>captureEdit</tabstop> <tabstop>captureEdit</tabstop>

View File

@ -14,7 +14,7 @@ QVector<SettingsValidator::Error> SettingsValidator::check(
if (settings.sourceLanguage.isEmpty()) if (settings.sourceLanguage.isEmpty())
result.append(Error::NoSourceSet); result.append(Error::NoSourceSet);
if (settings.doTranslation && models.targetLanguageModel()->rowCount() == 0) if (settings.doTranslation && models.translators().isEmpty())
result.append(Error::NoTranslatorInstalled); result.append(Error::NoTranslatorInstalled);
if (settings.doTranslation && settings.translators.isEmpty()) if (settings.doTranslation && settings.translators.isEmpty())
@ -26,6 +26,18 @@ QVector<SettingsValidator::Error> SettingsValidator::check(
return result; return result;
} }
bool SettingsValidator::correct(Settings &settings, const CommonModels &models)
{
auto changed = false;
if (settings.doTranslation && settings.translators.isEmpty() &&
!models.translators().isEmpty()) {
settings.translators = models.translators();
changed = true;
}
return changed;
}
QString SettingsValidator::toString(Error error) const QString SettingsValidator::toString(Error error) const
{ {
switch (error) { switch (error) {

View File

@ -17,5 +17,6 @@ public:
QVector<Error> check(const Settings& settings, QVector<Error> check(const Settings& settings,
const CommonModels& models) const; const CommonModels& models) const;
bool correct(Settings& settings, const CommonModels& models);
QString toString(Error error) const; QString toString(Error error) const;
}; };

View File

@ -132,11 +132,11 @@ void Translator::updateSettings()
return; return;
const auto loaded = const auto loaded =
loadScripts(settings_.translatorsDir, settings_.translators); loadScripts(settings_.translatorsPath, settings_.translators);
if (loaded.empty()) { if (loaded.empty()) {
manager_.fatalError( manager_.fatalError(
tr("No translators loaded from\n%1\n(%2)") tr("No translators loaded from\n%1\n(%2)")
.arg(settings_.translatorsDir, settings_.translators.join(", "))); .arg(settings_.translatorsPath, settings_.translators.join(", ")));
return; return;
} }

View File

@ -59,6 +59,16 @@ void TrayIcon::blockActions(bool block)
{ {
isActionsBlocked_ = block; isActionsBlocked_ = block;
updateActions(); updateActions();
const auto actions =
QVector<QAction *>{captureAction_, repeatCaptureAction_, showLastAction_,
clipboardAction_, captureLockedAction_};
for (const auto i : actions) {
if (block) {
GlobalAction::removeGlobal(i);
} else {
GlobalAction::makeGlobal(i);
}
}
} }
void TrayIcon::setTaskActionsEnabled(bool isEnabled) void TrayIcon::setTaskActionsEnabled(bool isEnabled)

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;
@ -27,7 +35,9 @@ function translate(text, from, to) {
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');
if (input == null)
input = document.querySelector('d-textarea.lmt__source_textarea p');
if (input == null)
input = document.querySelector('d-textarea[data-testid=translator-source-input] p');
if (input.innerText == singleLineText) {
console.log('using cached result'); console.log('using cached result');
lastText = ''; lastText = '';
return; return;
} }
input.value = text; input.innerText = singleLineText;
if (areaCopy = document.querySelector('div#source-dummydiv'))
areaCopy.innerHTML = singleLineText;
setTimeout(function () {
input.dispatchEvent(new Event("input", { bubbles: true, cancelable: true })); 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,384 +2,384 @@
"version":1 "version":1
,"app":{ ,"app":{
"win32":{"version":"3.2.1", "host":"win32", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"30a87d5ae32c6cb384a021f53566f8a9"}]} "win32":{"version":"3.3.0", "host":"win32", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"414c74c4594e0b90aff3cd86a73f96dd"}]}
,"win64":{"version":"3.2.1", "host":"win64", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"181a72953ed3bcfa1de41c8f9ca7360c"}]} ,"win64":{"version":"3.3.0", "host":"win64", "files":[{"path":"$appdir$/screen-translator.exe", "md5":"3f2c3c27364f25c239ea63243a8910a3"}]}
,"linux":{"version":"3.2.1", "host":"linux", "files":[{"path":"$appdir$/screen-translator", "md5":"be84c13ee89badfb99a5df579176353a"}]} ,"linux":{"version":"3.3.0", "host":"linux", "files":[{"path":"$appdir$/screen-translator", "md5":"a091be0443fd128a02b01b313e0270bc"}]}
} }
,"recognizers": { ,"recognizers": {
"Afrikaans":{"files":[ "Afrikaans":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/afr.traineddata","https://translator.gres.biz/resources/tessdata_best/afr.traineddata.zip"], "path":"$tessdata$/afr.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12800552} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/afr.traineddata","https://translator.gres.biz/resources/tessdata_best/afr.traineddata.zip"], "path":"$tessdata$/afr.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12800552}
]} ]}
, "Amharic":{"files":[ , "Amharic":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/amh.traineddata","https://translator.gres.biz/resources/tessdata_best/amh.traineddata.zip"], "path":"$tessdata$/amh.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8389639} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/amh.traineddata","https://translator.gres.biz/resources/tessdata_best/amh.traineddata.zip"], "path":"$tessdata$/amh.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8389639}
]} ]}
, "Arabic":{"files":[ , "Arabic":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ara.traineddata","https://translator.gres.biz/resources/tessdata_best/ara.traineddata.zip"], "path":"$tessdata$/ara.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12603724} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ara.traineddata","https://translator.gres.biz/resources/tessdata_best/ara.traineddata.zip"], "path":"$tessdata$/ara.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12603724}
]} ]}
, "Assamese":{"files":[ , "Assamese":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/asm.traineddata","https://translator.gres.biz/resources/tessdata_best/asm.traineddata.zip"], "path":"$tessdata$/asm.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11315350} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/asm.traineddata","https://translator.gres.biz/resources/tessdata_best/asm.traineddata.zip"], "path":"$tessdata$/asm.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11315350}
]} ]}
, "Azerbaijani":{"files":[ , "Azerbaijani":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/aze.traineddata","https://translator.gres.biz/resources/tessdata_best/aze.traineddata.zip"], "path":"$tessdata$/aze.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":6281404} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/aze.traineddata","https://translator.gres.biz/resources/tessdata_best/aze.traineddata.zip"], "path":"$tessdata$/aze.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":6281404}
]} ]}
, "aze_cyrl":{"files":[ , "aze_cyrl":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/aze_cyrl.traineddata","https://translator.gres.biz/resources/tessdata_best/aze_cyrl.traineddata.zip"], "path":"$tessdata$/aze_cyrl.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4700277} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/aze_cyrl.traineddata","https://translator.gres.biz/resources/tessdata_best/aze_cyrl.traineddata.zip"], "path":"$tessdata$/aze_cyrl.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4700277}
]} ]}
, "Belarusian":{"files":[ , "Belarusian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/bel.traineddata","https://translator.gres.biz/resources/tessdata_best/bel.traineddata.zip"], "path":"$tessdata$/bel.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10870278} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/bel.traineddata","https://translator.gres.biz/resources/tessdata_best/bel.traineddata.zip"], "path":"$tessdata$/bel.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10870278}
]} ]}
, "Bengali":{"files":[ , "Bengali":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ben.traineddata","https://translator.gres.biz/resources/tessdata_best/ben.traineddata.zip"], "path":"$tessdata$/ben.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11045427} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ben.traineddata","https://translator.gres.biz/resources/tessdata_best/ben.traineddata.zip"], "path":"$tessdata$/ben.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11045427}
]} ]}
, "Tibetan":{"files":[ , "Tibetan":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/bod.traineddata","https://translator.gres.biz/resources/tessdata_best/bod.traineddata.zip"], "path":"$tessdata$/bod.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8623846} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/bod.traineddata","https://translator.gres.biz/resources/tessdata_best/bod.traineddata.zip"], "path":"$tessdata$/bod.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8623846}
]} ]}
, "Bosnian":{"files":[ , "Bosnian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/bos.traineddata","https://translator.gres.biz/resources/tessdata_best/bos.traineddata.zip"], "path":"$tessdata$/bos.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":5264248} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/bos.traineddata","https://translator.gres.biz/resources/tessdata_best/bos.traineddata.zip"], "path":"$tessdata$/bos.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":5264248}
]} ]}
, "Breton":{"files":[ , "Breton":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/bre.traineddata","https://translator.gres.biz/resources/tessdata_best/bre.traineddata.zip"], "path":"$tessdata$/bre.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":15640760} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/bre.traineddata","https://translator.gres.biz/resources/tessdata_best/bre.traineddata.zip"], "path":"$tessdata$/bre.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":15640760}
]} ]}
, "Bulgarian":{"files":[ , "Bulgarian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/bul.traineddata","https://translator.gres.biz/resources/tessdata_best/bul.traineddata.zip"], "path":"$tessdata$/bul.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8844613} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/bul.traineddata","https://translator.gres.biz/resources/tessdata_best/bul.traineddata.zip"], "path":"$tessdata$/bul.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8844613}
]} ]}
, "Catalan":{"files":[ , "Catalan":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/cat.traineddata","https://translator.gres.biz/resources/tessdata_best/cat.traineddata.zip"], "path":"$tessdata$/cat.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3802329} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/cat.traineddata","https://translator.gres.biz/resources/tessdata_best/cat.traineddata.zip"], "path":"$tessdata$/cat.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3802329}
]} ]}
, "Cebuano":{"files":[ , "Cebuano":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ceb.traineddata","https://translator.gres.biz/resources/tessdata_best/ceb.traineddata.zip"], "path":"$tessdata$/ceb.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3452674} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ceb.traineddata","https://translator.gres.biz/resources/tessdata_best/ceb.traineddata.zip"], "path":"$tessdata$/ceb.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3452674}
]} ]}
, "Czech":{"files":[ , "Czech":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ces.traineddata","https://translator.gres.biz/resources/tessdata_best/ces.traineddata.zip"], "path":"$tessdata$/ces.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10918912} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ces.traineddata","https://translator.gres.biz/resources/tessdata_best/ces.traineddata.zip"], "path":"$tessdata$/ces.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10918912}
]} ]}
, "Chinese (Simplified)":{"files":[ , "Chinese (Simplified)":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/chi_sim.traineddata","https://translator.gres.biz/resources/tessdata_best/chi_sim.traineddata.zip"], "path":"$tessdata$/chi_sim.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13077423} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/chi_sim.traineddata","https://translator.gres.biz/resources/tessdata_best/chi_sim.traineddata.zip"], "path":"$tessdata$/chi_sim.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13077423}
]} ]}
, "Chinese (Simplified) vertical":{"files":[ , "Chinese (Simplified) vertical":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/chi_sim_vert.traineddata","https://translator.gres.biz/resources/tessdata_best/chi_sim_vert.traineddata.zip"], "path":"$tessdata$/chi_sim_vert.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13077507} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/chi_sim_vert.traineddata","https://translator.gres.biz/resources/tessdata_best/chi_sim_vert.traineddata.zip"], "path":"$tessdata$/chi_sim_vert.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13077507}
]} ]}
, "Chinese (Traditional)":{"files":[ , "Chinese (Traditional)":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/chi_tra.traineddata","https://translator.gres.biz/resources/tessdata_best/chi_tra.traineddata.zip"], "path":"$tessdata$/chi_tra.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12985735} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/chi_tra.traineddata","https://translator.gres.biz/resources/tessdata_best/chi_tra.traineddata.zip"], "path":"$tessdata$/chi_tra.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12985735}
]} ]}
, "Chinese (Traditional) vertical":{"files":[ , "Chinese (Traditional) vertical":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/chi_tra_vert.traineddata","https://translator.gres.biz/resources/tessdata_best/chi_tra_vert.traineddata.zip"], "path":"$tessdata$/chi_tra_vert.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12985521} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/chi_tra_vert.traineddata","https://translator.gres.biz/resources/tessdata_best/chi_tra_vert.traineddata.zip"], "path":"$tessdata$/chi_tra_vert.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12985521}
]} ]}
, "Cherokee":{"files":[ , "Cherokee":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/chr.traineddata","https://translator.gres.biz/resources/tessdata_best/chr.traineddata.zip"], "path":"$tessdata$/chr.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":2258703} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/chr.traineddata","https://translator.gres.biz/resources/tessdata_best/chr.traineddata.zip"], "path":"$tessdata$/chr.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":2258703}
]} ]}
, "Corsican":{"files":[ , "Corsican":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/cos.traineddata","https://translator.gres.biz/resources/tessdata_best/cos.traineddata.zip"], "path":"$tessdata$/cos.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8830216} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/cos.traineddata","https://translator.gres.biz/resources/tessdata_best/cos.traineddata.zip"], "path":"$tessdata$/cos.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8830216}
]} ]}
, "Welsh":{"files":[ , "Welsh":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/cym.traineddata","https://translator.gres.biz/resources/tessdata_best/cym.traineddata.zip"], "path":"$tessdata$/cym.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8750784} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/cym.traineddata","https://translator.gres.biz/resources/tessdata_best/cym.traineddata.zip"], "path":"$tessdata$/cym.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8750784}
]} ]}
, "Danish":{"files":[ , "Danish":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/dan.traineddata","https://translator.gres.biz/resources/tessdata_best/dan.traineddata.zip"], "path":"$tessdata$/dan.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9758142} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/dan.traineddata","https://translator.gres.biz/resources/tessdata_best/dan.traineddata.zip"], "path":"$tessdata$/dan.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9758142}
]} ]}
, "German":{"files":[ , "German":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/deu.traineddata","https://translator.gres.biz/resources/tessdata_best/deu.traineddata.zip"], "path":"$tessdata$/deu.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8628461} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/deu.traineddata","https://translator.gres.biz/resources/tessdata_best/deu.traineddata.zip"], "path":"$tessdata$/deu.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8628461}
]} ]}
, "Divehi, Dhivehi, Maldivian":{"files":[ , "Divehi, Dhivehi, Maldivian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/div.traineddata","https://translator.gres.biz/resources/tessdata_best/div.traineddata.zip"], "path":"$tessdata$/div.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4574116} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/div.traineddata","https://translator.gres.biz/resources/tessdata_best/div.traineddata.zip"], "path":"$tessdata$/div.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4574116}
]} ]}
, "Dzongkha":{"files":[ , "Dzongkha":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/dzo.traineddata","https://translator.gres.biz/resources/tessdata_best/dzo.traineddata.zip"], "path":"$tessdata$/dzo.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3243805} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/dzo.traineddata","https://translator.gres.biz/resources/tessdata_best/dzo.traineddata.zip"], "path":"$tessdata$/dzo.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3243805}
]} ]}
, "Greek":{"files":[ , "Greek":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ell.traineddata","https://translator.gres.biz/resources/tessdata_best/ell.traineddata.zip"], "path":"$tessdata$/ell.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8945021} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ell.traineddata","https://translator.gres.biz/resources/tessdata_best/ell.traineddata.zip"], "path":"$tessdata$/ell.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8945021}
]} ]}
, "English":{"files":[ , "English":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/eng.traineddata","https://translator.gres.biz/resources/tessdata_best/eng.traineddata.zip"], "path":"$tessdata$/eng.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":15400601} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata","https://translator.gres.biz/resources/tessdata_best/eng.traineddata.zip"], "path":"$tessdata$/eng.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":15400601}
]} ]}
, "English, Middle (1100-1500)":{"files":[ , "English, Middle (1100-1500)":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/enm.traineddata","https://translator.gres.biz/resources/tessdata_best/enm.traineddata.zip"], "path":"$tessdata$/enm.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13281564} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/enm.traineddata","https://translator.gres.biz/resources/tessdata_best/enm.traineddata.zip"], "path":"$tessdata$/enm.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13281564}
]} ]}
, "Esperanto":{"files":[ , "Esperanto":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/epo.traineddata","https://translator.gres.biz/resources/tessdata_best/epo.traineddata.zip"], "path":"$tessdata$/epo.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7402169} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/epo.traineddata","https://translator.gres.biz/resources/tessdata_best/epo.traineddata.zip"], "path":"$tessdata$/epo.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7402169}
]} ]}
, "Estonian":{"files":[ , "Estonian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/est.traineddata","https://translator.gres.biz/resources/tessdata_best/est.traineddata.zip"], "path":"$tessdata$/est.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":15833749} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/est.traineddata","https://translator.gres.biz/resources/tessdata_best/est.traineddata.zip"], "path":"$tessdata$/est.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":15833749}
]} ]}
, "Basque":{"files":[ , "Basque":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/eus.traineddata","https://translator.gres.biz/resources/tessdata_best/eus.traineddata.zip"], "path":"$tessdata$/eus.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7933869} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/eus.traineddata","https://translator.gres.biz/resources/tessdata_best/eus.traineddata.zip"], "path":"$tessdata$/eus.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7933869}
]} ]}
, "Faroese":{"files":[ , "Faroese":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/fao.traineddata","https://translator.gres.biz/resources/tessdata_best/fao.traineddata.zip"], "path":"$tessdata$/fao.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10030003} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/fao.traineddata","https://translator.gres.biz/resources/tessdata_best/fao.traineddata.zip"], "path":"$tessdata$/fao.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10030003}
]} ]}
, "Persian":{"files":[ , "Persian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/fas.traineddata","https://translator.gres.biz/resources/tessdata_best/fas.traineddata.zip"], "path":"$tessdata$/fas.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3325955} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/fas.traineddata","https://translator.gres.biz/resources/tessdata_best/fas.traineddata.zip"], "path":"$tessdata$/fas.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3325955}
]} ]}
, "Filipino":{"files":[ , "Filipino":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/fil.traineddata","https://translator.gres.biz/resources/tessdata_best/fil.traineddata.zip"], "path":"$tessdata$/fil.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8978743} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/fil.traineddata","https://translator.gres.biz/resources/tessdata_best/fil.traineddata.zip"], "path":"$tessdata$/fil.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8978743}
]} ]}
, "Finnish":{"files":[ , "Finnish":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/fin.traineddata","https://translator.gres.biz/resources/tessdata_best/fin.traineddata.zip"], "path":"$tessdata$/fin.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14369979} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/fin.traineddata","https://translator.gres.biz/resources/tessdata_best/fin.traineddata.zip"], "path":"$tessdata$/fin.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14369979}
]} ]}
, "French":{"files":[ , "French":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/fra.traineddata","https://translator.gres.biz/resources/tessdata_best/fra.traineddata.zip"], "path":"$tessdata$/fra.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3972885} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/fra.traineddata","https://translator.gres.biz/resources/tessdata_best/fra.traineddata.zip"], "path":"$tessdata$/fra.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3972885}
]} ]}
, "frk":{"files":[ , "frk":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/frk.traineddata","https://translator.gres.biz/resources/tessdata_best/frk.traineddata.zip"], "path":"$tessdata$/frk.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12938047} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/frk.traineddata","https://translator.gres.biz/resources/tessdata_best/frk.traineddata.zip"], "path":"$tessdata$/frk.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12938047}
]} ]}
, "French, Middle (ca.1400-1600)":{"files":[ , "French, Middle (ca.1400-1600)":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/frm.traineddata","https://translator.gres.biz/resources/tessdata_best/frm.traineddata.zip"], "path":"$tessdata$/frm.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4043005} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/frm.traineddata","https://translator.gres.biz/resources/tessdata_best/frm.traineddata.zip"], "path":"$tessdata$/frm.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4043005}
]} ]}
, "Western Frisian":{"files":[ , "Western Frisian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/fry.traineddata","https://translator.gres.biz/resources/tessdata_best/fry.traineddata.zip"], "path":"$tessdata$/fry.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8442509} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/fry.traineddata","https://translator.gres.biz/resources/tessdata_best/fry.traineddata.zip"], "path":"$tessdata$/fry.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8442509}
]} ]}
, "Gaelic":{"files":[ , "Gaelic":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/gla.traineddata","https://translator.gres.biz/resources/tessdata_best/gla.traineddata.zip"], "path":"$tessdata$/gla.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9599424} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/gla.traineddata","https://translator.gres.biz/resources/tessdata_best/gla.traineddata.zip"], "path":"$tessdata$/gla.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9599424}
]} ]}
, "Irish":{"files":[ , "Irish":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/gle.traineddata","https://translator.gres.biz/resources/tessdata_best/gle.traineddata.zip"], "path":"$tessdata$/gle.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3942458} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/gle.traineddata","https://translator.gres.biz/resources/tessdata_best/gle.traineddata.zip"], "path":"$tessdata$/gle.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3942458}
]} ]}
, "Galician":{"files":[ , "Galician":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/glg.traineddata","https://translator.gres.biz/resources/tessdata_best/glg.traineddata.zip"], "path":"$tessdata$/glg.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12709487} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/glg.traineddata","https://translator.gres.biz/resources/tessdata_best/glg.traineddata.zip"], "path":"$tessdata$/glg.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12709487}
]} ]}
, "Greek, Ancient (to 1453)":{"files":[ , "Greek, Ancient (to 1453)":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/grc.traineddata","https://translator.gres.biz/resources/tessdata_best/grc.traineddata.zip"], "path":"$tessdata$/grc.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":5168122} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/grc.traineddata","https://translator.gres.biz/resources/tessdata_best/grc.traineddata.zip"], "path":"$tessdata$/grc.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":5168122}
]} ]}
, "Gujarati":{"files":[ , "Gujarati":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/guj.traineddata","https://translator.gres.biz/resources/tessdata_best/guj.traineddata.zip"], "path":"$tessdata$/guj.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8515761} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/guj.traineddata","https://translator.gres.biz/resources/tessdata_best/guj.traineddata.zip"], "path":"$tessdata$/guj.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8515761}
]} ]}
, "Haitian":{"files":[ , "Haitian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/hat.traineddata","https://translator.gres.biz/resources/tessdata_best/hat.traineddata.zip"], "path":"$tessdata$/hat.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12128251} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/hat.traineddata","https://translator.gres.biz/resources/tessdata_best/hat.traineddata.zip"], "path":"$tessdata$/hat.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12128251}
]} ]}
, "Hebrew":{"files":[ , "Hebrew":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/heb.traineddata","https://translator.gres.biz/resources/tessdata_best/heb.traineddata.zip"], "path":"$tessdata$/heb.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3704077} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/heb.traineddata","https://translator.gres.biz/resources/tessdata_best/heb.traineddata.zip"], "path":"$tessdata$/heb.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3704077}
]} ]}
, "Hindi":{"files":[ , "Hindi":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/hin.traineddata","https://translator.gres.biz/resources/tessdata_best/hin.traineddata.zip"], "path":"$tessdata$/hin.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11895564} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/hin.traineddata","https://translator.gres.biz/resources/tessdata_best/hin.traineddata.zip"], "path":"$tessdata$/hin.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11895564}
]} ]}
, "Croatian":{"files":[ , "Croatian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/hrv.traineddata","https://translator.gres.biz/resources/tessdata_best/hrv.traineddata.zip"], "path":"$tessdata$/hrv.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11195424} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/hrv.traineddata","https://translator.gres.biz/resources/tessdata_best/hrv.traineddata.zip"], "path":"$tessdata$/hrv.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11195424}
]} ]}
, "Hungarian":{"files":[ , "Hungarian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/hun.traineddata","https://translator.gres.biz/resources/tessdata_best/hun.traineddata.zip"], "path":"$tessdata$/hun.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12350405} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/hun.traineddata","https://translator.gres.biz/resources/tessdata_best/hun.traineddata.zip"], "path":"$tessdata$/hun.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12350405}
]} ]}
, "Armenian":{"files":[ , "Armenian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/hye.traineddata","https://translator.gres.biz/resources/tessdata_best/hye.traineddata.zip"], "path":"$tessdata$/hye.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":6372242} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/hye.traineddata","https://translator.gres.biz/resources/tessdata_best/hye.traineddata.zip"], "path":"$tessdata$/hye.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":6372242}
]} ]}
, "Inuktitut":{"files":[ , "Inuktitut":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/iku.traineddata","https://translator.gres.biz/resources/tessdata_best/iku.traineddata.zip"], "path":"$tessdata$/iku.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":6139484} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/iku.traineddata","https://translator.gres.biz/resources/tessdata_best/iku.traineddata.zip"], "path":"$tessdata$/iku.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":6139484}
]} ]}
, "Indonesian":{"files":[ , "Indonesian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ind.traineddata","https://translator.gres.biz/resources/tessdata_best/ind.traineddata.zip"], "path":"$tessdata$/ind.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8253606} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ind.traineddata","https://translator.gres.biz/resources/tessdata_best/ind.traineddata.zip"], "path":"$tessdata$/ind.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8253606}
]} ]}
, "Icelandic":{"files":[ , "Icelandic":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/isl.traineddata","https://translator.gres.biz/resources/tessdata_best/isl.traineddata.zip"], "path":"$tessdata$/isl.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9486436} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/isl.traineddata","https://translator.gres.biz/resources/tessdata_best/isl.traineddata.zip"], "path":"$tessdata$/isl.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9486436}
]} ]}
, "Italian":{"files":[ , "Italian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ita.traineddata","https://translator.gres.biz/resources/tessdata_best/ita.traineddata.zip"], "path":"$tessdata$/ita.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8863667} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ita.traineddata","https://translator.gres.biz/resources/tessdata_best/ita.traineddata.zip"], "path":"$tessdata$/ita.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8863667}
]} ]}
, "ita_old":{"files":[ , "ita_old":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ita_old.traineddata","https://translator.gres.biz/resources/tessdata_best/ita_old.traineddata.zip"], "path":"$tessdata$/ita_old.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9852171} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ita_old.traineddata","https://translator.gres.biz/resources/tessdata_best/ita_old.traineddata.zip"], "path":"$tessdata$/ita_old.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9852171}
]} ]}
, "Javanese":{"files":[ , "Javanese":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/jav.traineddata","https://translator.gres.biz/resources/tessdata_best/jav.traineddata.zip"], "path":"$tessdata$/jav.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8650382} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/jav.traineddata","https://translator.gres.biz/resources/tessdata_best/jav.traineddata.zip"], "path":"$tessdata$/jav.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8650382}
]} ]}
, "Japanese":{"files":[ , "Japanese":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/jpn.traineddata","https://translator.gres.biz/resources/tessdata_best/jpn.traineddata.zip"], "path":"$tessdata$/jpn.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14330109} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/jpn.traineddata","https://translator.gres.biz/resources/tessdata_best/jpn.traineddata.zip"], "path":"$tessdata$/jpn.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14330109}
]} ]}
, "Japanese vertical":{"files":[ , "Japanese vertical":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/jpn_vert.traineddata","https://translator.gres.biz/resources/tessdata_best/jpn_vert.traineddata.zip"], "path":"$tessdata$/jpn_vert.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14330809} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/jpn_vert.traineddata","https://translator.gres.biz/resources/tessdata_best/jpn_vert.traineddata.zip"], "path":"$tessdata$/jpn_vert.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14330809}
]} ]}
, "Kannada":{"files":[ , "Kannada":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/kan.traineddata","https://translator.gres.biz/resources/tessdata_best/kan.traineddata.zip"], "path":"$tessdata$/kan.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10233763} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/kan.traineddata","https://translator.gres.biz/resources/tessdata_best/kan.traineddata.zip"], "path":"$tessdata$/kan.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10233763}
]} ]}
, "Georgian":{"files":[ , "Georgian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/kat.traineddata","https://translator.gres.biz/resources/tessdata_best/kat.traineddata.zip"], "path":"$tessdata$/kat.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4487336} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/kat.traineddata","https://translator.gres.biz/resources/tessdata_best/kat.traineddata.zip"], "path":"$tessdata$/kat.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4487336}
]} ]}
, "kat_old":{"files":[ , "kat_old":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/kat_old.traineddata","https://translator.gres.biz/resources/tessdata_best/kat_old.traineddata.zip"], "path":"$tessdata$/kat_old.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3174400} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/kat_old.traineddata","https://translator.gres.biz/resources/tessdata_best/kat_old.traineddata.zip"], "path":"$tessdata$/kat_old.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3174400}
]} ]}
, "Kazakh":{"files":[ , "Kazakh":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/kaz.traineddata","https://translator.gres.biz/resources/tessdata_best/kaz.traineddata.zip"], "path":"$tessdata$/kaz.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7528853} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/kaz.traineddata","https://translator.gres.biz/resources/tessdata_best/kaz.traineddata.zip"], "path":"$tessdata$/kaz.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7528853}
]} ]}
, "Central Khmer":{"files":[ , "Central Khmer":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/khm.traineddata","https://translator.gres.biz/resources/tessdata_best/khm.traineddata.zip"], "path":"$tessdata$/khm.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8104332} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/khm.traineddata","https://translator.gres.biz/resources/tessdata_best/khm.traineddata.zip"], "path":"$tessdata$/khm.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8104332}
]} ]}
, "Kyrgyz":{"files":[ , "Kyrgyz":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/kir.traineddata","https://translator.gres.biz/resources/tessdata_best/kir.traineddata.zip"], "path":"$tessdata$/kir.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11948344} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/kir.traineddata","https://translator.gres.biz/resources/tessdata_best/kir.traineddata.zip"], "path":"$tessdata$/kir.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11948344}
]} ]}
, "kmr":{"files":[ , "kmr":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/kmr.traineddata","https://translator.gres.biz/resources/tessdata_best/kmr.traineddata.zip"], "path":"$tessdata$/kmr.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10196464} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/kmr.traineddata","https://translator.gres.biz/resources/tessdata_best/kmr.traineddata.zip"], "path":"$tessdata$/kmr.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10196464}
]} ]}
, "Korean":{"files":[ , "Korean":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/kor.traineddata","https://translator.gres.biz/resources/tessdata_best/kor.traineddata.zip"], "path":"$tessdata$/kor.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12528128} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/kor.traineddata","https://translator.gres.biz/resources/tessdata_best/kor.traineddata.zip"], "path":"$tessdata$/kor.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12528128}
]} ]}
, "Korean vertical":{"files":[ , "Korean vertical":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/kor_vert.traineddata","https://translator.gres.biz/resources/tessdata_best/kor_vert.traineddata.zip"], "path":"$tessdata$/kor_vert.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3964469} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/kor_vert.traineddata","https://translator.gres.biz/resources/tessdata_best/kor_vert.traineddata.zip"], "path":"$tessdata$/kor_vert.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3964469}
]} ]}
, "Lao":{"files":[ , "Lao":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/lao.traineddata","https://translator.gres.biz/resources/tessdata_best/lao.traineddata.zip"], "path":"$tessdata$/lao.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13532551} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/lao.traineddata","https://translator.gres.biz/resources/tessdata_best/lao.traineddata.zip"], "path":"$tessdata$/lao.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13532551}
]} ]}
, "Latin":{"files":[ , "Latin":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/lat.traineddata","https://translator.gres.biz/resources/tessdata_best/lat.traineddata.zip"], "path":"$tessdata$/lat.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9705145} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/lat.traineddata","https://translator.gres.biz/resources/tessdata_best/lat.traineddata.zip"], "path":"$tessdata$/lat.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9705145}
]} ]}
, "Latvian":{"files":[ , "Latvian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/lav.traineddata","https://translator.gres.biz/resources/tessdata_best/lav.traineddata.zip"], "path":"$tessdata$/lav.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":5623473} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/lav.traineddata","https://translator.gres.biz/resources/tessdata_best/lav.traineddata.zip"], "path":"$tessdata$/lav.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":5623473}
]} ]}
, "Lithuanian":{"files":[ , "Lithuanian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/lit.traineddata","https://translator.gres.biz/resources/tessdata_best/lit.traineddata.zip"], "path":"$tessdata$/lit.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10252680} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/lit.traineddata","https://translator.gres.biz/resources/tessdata_best/lit.traineddata.zip"], "path":"$tessdata$/lit.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10252680}
]} ]}
, "Luxembourgish":{"files":[ , "Luxembourgish":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ltz.traineddata","https://translator.gres.biz/resources/tessdata_best/ltz.traineddata.zip"], "path":"$tessdata$/ltz.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12721945} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ltz.traineddata","https://translator.gres.biz/resources/tessdata_best/ltz.traineddata.zip"], "path":"$tessdata$/ltz.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12721945}
]} ]}
, "Malayalam":{"files":[ , "Malayalam":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/mal.traineddata","https://translator.gres.biz/resources/tessdata_best/mal.traineddata.zip"], "path":"$tessdata$/mal.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12524967} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/mal.traineddata","https://translator.gres.biz/resources/tessdata_best/mal.traineddata.zip"], "path":"$tessdata$/mal.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12524967}
]} ]}
, "Marathi":{"files":[ , "Marathi":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/mar.traineddata","https://translator.gres.biz/resources/tessdata_best/mar.traineddata.zip"], "path":"$tessdata$/mar.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13437670} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/mar.traineddata","https://translator.gres.biz/resources/tessdata_best/mar.traineddata.zip"], "path":"$tessdata$/mar.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13437670}
]} ]}
, "Macedonian":{"files":[ , "Macedonian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/mkd.traineddata","https://translator.gres.biz/resources/tessdata_best/mkd.traineddata.zip"], "path":"$tessdata$/mkd.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3453054} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/mkd.traineddata","https://translator.gres.biz/resources/tessdata_best/mkd.traineddata.zip"], "path":"$tessdata$/mkd.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3453054}
]} ]}
, "Maltese":{"files":[ , "Maltese":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/mlt.traineddata","https://translator.gres.biz/resources/tessdata_best/mlt.traineddata.zip"], "path":"$tessdata$/mlt.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":5060029} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/mlt.traineddata","https://translator.gres.biz/resources/tessdata_best/mlt.traineddata.zip"], "path":"$tessdata$/mlt.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":5060029}
]} ]}
, "Mongolian":{"files":[ , "Mongolian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/mon.traineddata","https://translator.gres.biz/resources/tessdata_best/mon.traineddata.zip"], "path":"$tessdata$/mon.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8646663} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/mon.traineddata","https://translator.gres.biz/resources/tessdata_best/mon.traineddata.zip"], "path":"$tessdata$/mon.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8646663}
]} ]}
, "Maori":{"files":[ , "Maori":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/mri.traineddata","https://translator.gres.biz/resources/tessdata_best/mri.traineddata.zip"], "path":"$tessdata$/mri.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3610177} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/mri.traineddata","https://translator.gres.biz/resources/tessdata_best/mri.traineddata.zip"], "path":"$tessdata$/mri.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3610177}
]} ]}
, "Malay":{"files":[ , "Malay":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/msa.traineddata","https://translator.gres.biz/resources/tessdata_best/msa.traineddata.zip"], "path":"$tessdata$/msa.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8230552} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/msa.traineddata","https://translator.gres.biz/resources/tessdata_best/msa.traineddata.zip"], "path":"$tessdata$/msa.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8230552}
]} ]}
, "Burmese":{"files":[ , "Burmese":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/mya.traineddata","https://translator.gres.biz/resources/tessdata_best/mya.traineddata.zip"], "path":"$tessdata$/mya.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14971060} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/mya.traineddata","https://translator.gres.biz/resources/tessdata_best/mya.traineddata.zip"], "path":"$tessdata$/mya.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14971060}
]} ]}
, "Nepali":{"files":[ , "Nepali":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/nep.traineddata","https://translator.gres.biz/resources/tessdata_best/nep.traineddata.zip"], "path":"$tessdata$/nep.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12387399} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/nep.traineddata","https://translator.gres.biz/resources/tessdata_best/nep.traineddata.zip"], "path":"$tessdata$/nep.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12387399}
]} ]}
, "Dutch":{"files":[ , "Dutch":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/nld.traineddata","https://translator.gres.biz/resources/tessdata_best/nld.traineddata.zip"], "path":"$tessdata$/nld.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8903736} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/nld.traineddata","https://translator.gres.biz/resources/tessdata_best/nld.traineddata.zip"], "path":"$tessdata$/nld.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8903736}
]} ]}
, "Norwegian":{"files":[ , "Norwegian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/nor.traineddata","https://translator.gres.biz/resources/tessdata_best/nor.traineddata.zip"], "path":"$tessdata$/nor.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14312333} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/nor.traineddata","https://translator.gres.biz/resources/tessdata_best/nor.traineddata.zip"], "path":"$tessdata$/nor.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14312333}
]} ]}
, "Occitan":{"files":[ , "Occitan":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/oci.traineddata","https://translator.gres.biz/resources/tessdata_best/oci.traineddata.zip"], "path":"$tessdata$/oci.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12917692} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/oci.traineddata","https://translator.gres.biz/resources/tessdata_best/oci.traineddata.zip"], "path":"$tessdata$/oci.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12917692}
]} ]}
, "Oriya":{"files":[ , "Oriya":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ori.traineddata","https://translator.gres.biz/resources/tessdata_best/ori.traineddata.zip"], "path":"$tessdata$/ori.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8110602} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ori.traineddata","https://translator.gres.biz/resources/tessdata_best/ori.traineddata.zip"], "path":"$tessdata$/ori.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8110602}
]} ]}
, "osd":{"files":[ , "osd":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/osd.traineddata","https://translator.gres.biz/resources/tessdata_best/osd.traineddata.zip"], "path":"$tessdata$/osd.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10562727} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/osd.traineddata","https://translator.gres.biz/resources/tessdata_best/osd.traineddata.zip"], "path":"$tessdata$/osd.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10562727}
]} ]}
, "Punjabi":{"files":[ , "Punjabi":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/pan.traineddata","https://translator.gres.biz/resources/tessdata_best/pan.traineddata.zip"], "path":"$tessdata$/pan.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11893154} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/pan.traineddata","https://translator.gres.biz/resources/tessdata_best/pan.traineddata.zip"], "path":"$tessdata$/pan.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11893154}
]} ]}
, "Polish":{"files":[ , "Polish":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/pol.traineddata","https://translator.gres.biz/resources/tessdata_best/pol.traineddata.zip"], "path":"$tessdata$/pol.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11978867} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/pol.traineddata","https://translator.gres.biz/resources/tessdata_best/pol.traineddata.zip"], "path":"$tessdata$/pol.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11978867}
]} ]}
, "Portuguese":{"files":[ , "Portuguese":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/por.traineddata","https://translator.gres.biz/resources/tessdata_best/por.traineddata.zip"], "path":"$tessdata$/por.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8159939} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/por.traineddata","https://translator.gres.biz/resources/tessdata_best/por.traineddata.zip"], "path":"$tessdata$/por.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8159939}
]} ]}
, "Pashto":{"files":[ , "Pashto":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/pus.traineddata","https://translator.gres.biz/resources/tessdata_best/pus.traineddata.zip"], "path":"$tessdata$/pus.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11987930} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/pus.traineddata","https://translator.gres.biz/resources/tessdata_best/pus.traineddata.zip"], "path":"$tessdata$/pus.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11987930}
]} ]}
, "Quechua":{"files":[ , "Quechua":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/que.traineddata","https://translator.gres.biz/resources/tessdata_best/que.traineddata.zip"], "path":"$tessdata$/que.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10774587} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/que.traineddata","https://translator.gres.biz/resources/tessdata_best/que.traineddata.zip"], "path":"$tessdata$/que.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10774587}
]} ]}
, "Romanian":{"files":[ , "Romanian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ron.traineddata","https://translator.gres.biz/resources/tessdata_best/ron.traineddata.zip"], "path":"$tessdata$/ron.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9595755} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ron.traineddata","https://translator.gres.biz/resources/tessdata_best/ron.traineddata.zip"], "path":"$tessdata$/ron.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9595755}
]} ]}
, "Russian":{"files":[ , "Russian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/rus.traineddata","https://translator.gres.biz/resources/tessdata_best/rus.traineddata.zip"], "path":"$tessdata$/rus.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":15301764} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/rus.traineddata","https://translator.gres.biz/resources/tessdata_best/rus.traineddata.zip"], "path":"$tessdata$/rus.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":15301764}
]} ]}
, "Sanskrit":{"files":[ , "Sanskrit":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/san.traineddata","https://translator.gres.biz/resources/tessdata_best/san.traineddata.zip"], "path":"$tessdata$/san.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":15136202} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/san.traineddata","https://translator.gres.biz/resources/tessdata_best/san.traineddata.zip"], "path":"$tessdata$/san.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":15136202}
]} ]}
, "Sinhala, Sinhalese":{"files":[ , "Sinhala, Sinhalese":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/sin.traineddata","https://translator.gres.biz/resources/tessdata_best/sin.traineddata.zip"], "path":"$tessdata$/sin.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8282713} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/sin.traineddata","https://translator.gres.biz/resources/tessdata_best/sin.traineddata.zip"], "path":"$tessdata$/sin.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":8282713}
]} ]}
, "Slovak":{"files":[ , "Slovak":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/slk.traineddata","https://translator.gres.biz/resources/tessdata_best/slk.traineddata.zip"], "path":"$tessdata$/slk.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11542252} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/slk.traineddata","https://translator.gres.biz/resources/tessdata_best/slk.traineddata.zip"], "path":"$tessdata$/slk.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11542252}
]} ]}
, "Slovenian":{"files":[ , "Slovenian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/slv.traineddata","https://translator.gres.biz/resources/tessdata_best/slv.traineddata.zip"], "path":"$tessdata$/slv.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":5879151} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/slv.traineddata","https://translator.gres.biz/resources/tessdata_best/slv.traineddata.zip"], "path":"$tessdata$/slv.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":5879151}
]} ]}
, "Sindhi":{"files":[ , "Sindhi":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/snd.traineddata","https://translator.gres.biz/resources/tessdata_best/snd.traineddata.zip"], "path":"$tessdata$/snd.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11981538} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/snd.traineddata","https://translator.gres.biz/resources/tessdata_best/snd.traineddata.zip"], "path":"$tessdata$/snd.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":11981538}
]} ]}
, "Spanish":{"files":[ , "Spanish":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/spa.traineddata","https://translator.gres.biz/resources/tessdata_best/spa.traineddata.zip"], "path":"$tessdata$/spa.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13570187} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/spa.traineddata","https://translator.gres.biz/resources/tessdata_best/spa.traineddata.zip"], "path":"$tessdata$/spa.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13570187}
]} ]}
, "spa_old":{"files":[ , "spa_old":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/spa_old.traineddata","https://translator.gres.biz/resources/tessdata_best/spa_old.traineddata.zip"], "path":"$tessdata$/spa_old.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9476925} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/spa_old.traineddata","https://translator.gres.biz/resources/tessdata_best/spa_old.traineddata.zip"], "path":"$tessdata$/spa_old.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9476925}
]} ]}
, "Albanian":{"files":[ , "Albanian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/sqi.traineddata","https://translator.gres.biz/resources/tessdata_best/sqi.traineddata.zip"], "path":"$tessdata$/sqi.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4631498} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/sqi.traineddata","https://translator.gres.biz/resources/tessdata_best/sqi.traineddata.zip"], "path":"$tessdata$/sqi.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4631498}
]} ]}
, "Serbian":{"files":[ , "Serbian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/srp.traineddata","https://translator.gres.biz/resources/tessdata_best/srp.traineddata.zip"], "path":"$tessdata$/srp.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9345851} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/srp.traineddata","https://translator.gres.biz/resources/tessdata_best/srp.traineddata.zip"], "path":"$tessdata$/srp.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9345851}
]} ]}
, "srp_latn":{"files":[ , "srp_latn":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/srp_latn.traineddata","https://translator.gres.biz/resources/tessdata_best/srp_latn.traineddata.zip"], "path":"$tessdata$/srp_latn.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9831713} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/srp_latn.traineddata","https://translator.gres.biz/resources/tessdata_best/srp_latn.traineddata.zip"], "path":"$tessdata$/srp_latn.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9831713}
]} ]}
, "Sundanese":{"files":[ , "Sundanese":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/sun.traineddata","https://translator.gres.biz/resources/tessdata_best/sun.traineddata.zip"], "path":"$tessdata$/sun.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4132820} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/sun.traineddata","https://translator.gres.biz/resources/tessdata_best/sun.traineddata.zip"], "path":"$tessdata$/sun.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4132820}
]} ]}
, "Swahili":{"files":[ , "Swahili":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/swa.traineddata","https://translator.gres.biz/resources/tessdata_best/swa.traineddata.zip"], "path":"$tessdata$/swa.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4914855} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/swa.traineddata","https://translator.gres.biz/resources/tessdata_best/swa.traineddata.zip"], "path":"$tessdata$/swa.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4914855}
]} ]}
, "Swedish":{"files":[ , "Swedish":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/swe.traineddata","https://translator.gres.biz/resources/tessdata_best/swe.traineddata.zip"], "path":"$tessdata$/swe.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14325549} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/swe.traineddata","https://translator.gres.biz/resources/tessdata_best/swe.traineddata.zip"], "path":"$tessdata$/swe.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":14325549}
]} ]}
, "Syriac":{"files":[ , "Syriac":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/syr.traineddata","https://translator.gres.biz/resources/tessdata_best/syr.traineddata.zip"], "path":"$tessdata$/syr.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12498294} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/syr.traineddata","https://translator.gres.biz/resources/tessdata_best/syr.traineddata.zip"], "path":"$tessdata$/syr.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12498294}
]} ]}
, "Tamil":{"files":[ , "Tamil":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/tam.traineddata","https://translator.gres.biz/resources/tessdata_best/tam.traineddata.zip"], "path":"$tessdata$/tam.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":6023201} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/tam.traineddata","https://translator.gres.biz/resources/tessdata_best/tam.traineddata.zip"], "path":"$tessdata$/tam.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":6023201}
]} ]}
, "Tatar":{"files":[ , "Tatar":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/tat.traineddata","https://translator.gres.biz/resources/tessdata_best/tat.traineddata.zip"], "path":"$tessdata$/tat.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7585204} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/tat.traineddata","https://translator.gres.biz/resources/tessdata_best/tat.traineddata.zip"], "path":"$tessdata$/tat.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7585204}
]} ]}
, "Telugu":{"files":[ , "Telugu":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/tel.traineddata","https://translator.gres.biz/resources/tessdata_best/tel.traineddata.zip"], "path":"$tessdata$/tel.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9098795} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/tel.traineddata","https://translator.gres.biz/resources/tessdata_best/tel.traineddata.zip"], "path":"$tessdata$/tel.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":9098795}
]} ]}
, "Tajik":{"files":[ , "Tajik":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/tgk.traineddata","https://translator.gres.biz/resources/tessdata_best/tgk.traineddata.zip"], "path":"$tessdata$/tgk.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4602842} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/tgk.traineddata","https://translator.gres.biz/resources/tessdata_best/tgk.traineddata.zip"], "path":"$tessdata$/tgk.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4602842}
]} ]}
, "Thai":{"files":[ , "Thai":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/tha.traineddata","https://translator.gres.biz/resources/tessdata_best/tha.traineddata.zip"], "path":"$tessdata$/tha.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7614571} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/tha.traineddata","https://translator.gres.biz/resources/tessdata_best/tha.traineddata.zip"], "path":"$tessdata$/tha.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7614571}
]} ]}
, "Tigrinya":{"files":[ , "Tigrinya":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/tir.traineddata","https://translator.gres.biz/resources/tessdata_best/tir.traineddata.zip"], "path":"$tessdata$/tir.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":2410256} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/tir.traineddata","https://translator.gres.biz/resources/tessdata_best/tir.traineddata.zip"], "path":"$tessdata$/tir.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":2410256}
]} ]}
, "Tonga (Tonga Islands)":{"files":[ , "Tonga (Tonga Islands)":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ton.traineddata","https://translator.gres.biz/resources/tessdata_best/ton.traineddata.zip"], "path":"$tessdata$/ton.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3729371} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ton.traineddata","https://translator.gres.biz/resources/tessdata_best/ton.traineddata.zip"], "path":"$tessdata$/ton.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3729371}
]} ]}
, "Turkish":{"files":[ , "Turkish":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/tur.traineddata","https://translator.gres.biz/resources/tessdata_best/tur.traineddata.zip"], "path":"$tessdata$/tur.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7456265} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/tur.traineddata","https://translator.gres.biz/resources/tessdata_best/tur.traineddata.zip"], "path":"$tessdata$/tur.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7456265}
]} ]}
, "Uighur, Uyghur":{"files":[ , "Uighur, Uyghur":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/uig.traineddata","https://translator.gres.biz/resources/tessdata_best/uig.traineddata.zip"], "path":"$tessdata$/uig.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13074609} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/uig.traineddata","https://translator.gres.biz/resources/tessdata_best/uig.traineddata.zip"], "path":"$tessdata$/uig.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":13074609}
]} ]}
, "Ukrainian":{"files":[ , "Ukrainian":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/ukr.traineddata","https://translator.gres.biz/resources/tessdata_best/ukr.traineddata.zip"], "path":"$tessdata$/ukr.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10859081} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/ukr.traineddata","https://translator.gres.biz/resources/tessdata_best/ukr.traineddata.zip"], "path":"$tessdata$/ukr.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":10859081}
]} ]}
, "Urdu":{"files":[ , "Urdu":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/urd.traineddata","https://translator.gres.biz/resources/tessdata_best/urd.traineddata.zip"], "path":"$tessdata$/urd.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7994323} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/urd.traineddata","https://translator.gres.biz/resources/tessdata_best/urd.traineddata.zip"], "path":"$tessdata$/urd.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":7994323}
]} ]}
, "Uzbek":{"files":[ , "Uzbek":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/uzb.traineddata","https://translator.gres.biz/resources/tessdata_best/uzb.traineddata.zip"], "path":"$tessdata$/uzb.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12953454} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/uzb.traineddata","https://translator.gres.biz/resources/tessdata_best/uzb.traineddata.zip"], "path":"$tessdata$/uzb.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12953454}
]} ]}
, "uzb_cyrl":{"files":[ , "uzb_cyrl":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/uzb_cyrl.traineddata","https://translator.gres.biz/resources/tessdata_best/uzb_cyrl.traineddata.zip"], "path":"$tessdata$/uzb_cyrl.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4325478} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/uzb_cyrl.traineddata","https://translator.gres.biz/resources/tessdata_best/uzb_cyrl.traineddata.zip"], "path":"$tessdata$/uzb_cyrl.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":4325478}
]} ]}
, "Vietnamese":{"files":[ , "Vietnamese":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/vie.traineddata","https://translator.gres.biz/resources/tessdata_best/vie.traineddata.zip"], "path":"$tessdata$/vie.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12435550} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/vie.traineddata","https://translator.gres.biz/resources/tessdata_best/vie.traineddata.zip"], "path":"$tessdata$/vie.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":12435550}
]} ]}
, "Yiddish":{"files":[ , "Yiddish":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/yid.traineddata","https://translator.gres.biz/resources/tessdata_best/yid.traineddata.zip"], "path":"$tessdata$/yid.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3278995} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/yid.traineddata","https://translator.gres.biz/resources/tessdata_best/yid.traineddata.zip"], "path":"$tessdata$/yid.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3278995}
]} ]}
, "Yoruba":{"files":[ , "Yoruba":{"files":[
{"url":["https://github.com/tesseract-ocr/tessdata_best/raw/master/yor.traineddata","https://translator.gres.biz/resources/tessdata_best/yor.traineddata.zip"], "path":"$tessdata$/yor.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3736121} {"url":["https://github.com/tesseract-ocr/tessdata_best/raw/main/yor.traineddata","https://translator.gres.biz/resources/tessdata_best/yor.traineddata.zip"], "path":"$tessdata$/yor.traineddata", "date":"2020-03-09T08:28:45+01:00", "size":3736121}
]} ]}
} }
@ -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}
]} ]}
} }

View File

@ -1,15 +0,0 @@
{
"version": 1,
"url": "https://raw.githubusercontent.com/OneMoreGres/ScreenTranslator/master/version.json",
"Application": {
"version": 3,
"compatibleVersion": 3,
"built_in": true,
"versionString": "3.0.0",
"permissions": "0x7755",
"url_win": "disabled",
"path_win": "ScreenTranslator.exe",
"url_linux": "disabled",
"path_linux": "ScreenTranslator"
}
}