Add Lingua Libre support (#268)

* lingua: add a dummy dict

* lingua: working but output plain json as article

* lingua: add html audio plays

* lingua: fix qmake build

* fix: qmake on mac INCLUDEPATH

* lingua: add config ui to dict sources edit dialog

* lingua: add config logics

* lingua: use the configured iso language code to do query

* lingua: style polish
This commit is contained in:
shenlebantongying 2022-12-24 09:42:40 -05:00 committed by GitHub
parent d1dc024375
commit 6fc3684b0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 722 additions and 10 deletions

1
.gitignore vendored
View file

@ -41,3 +41,4 @@ GoldenDict.xcodeproj/
# cmake files
/cmake-build-**/
/build**/
CMakeLists.txt.user

View file

@ -467,14 +467,15 @@ set(PROJECT_SOURCES
zipfile.hh
zipsounds.cc
zipsounds.hh
)
src/dict/lingualibre.cpp src/dict/lingualibre.h)
qt_add_executable(${CMAKE_PROJECT_NAME}
MANUAL_FINALIZATION
${PROJECT_SOURCES})
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC
${PROJECT_SOURCE_DIR}/thirdparty/qtsingleapplication/src)
${PROJECT_SOURCE_DIR}/thirdparty/qtsingleapplication/src
${PROJECT_SOURCE_DIR}/src/)
if(MSVC)
add_compile_definitions(INCLUDE_LIBRARY_PATH)

View file

@ -694,6 +694,14 @@ Class load()
}
}
QDomNode lingua = root.namedItem("lingua");
if(!lingua.isNull()){
applyBoolOption(c.lingua.enable,lingua.namedItem("enable"));
c.lingua.languageCodes = lingua.namedItem("languageCodes").toElement().text();
}
QDomNode forvo = root.namedItem( "forvo" );
if ( !forvo.isNull() )
@ -1451,6 +1459,22 @@ void save( Class const & c )
romaji.appendChild( opt );
}
{
// Lingua
QDomElement lingua = dd.createElement("lingua");
root.appendChild(lingua);
QDomElement opt = dd.createElement("enable");
opt.appendChild(dd.createTextNode(c.lingua.enable?"1":"0"));
lingua.appendChild(opt);
opt = dd.createElement( "languageCodes" );
opt.appendChild( dd.createTextNode( c.lingua.languageCodes ) );
lingua.appendChild( opt );
}
{
// Forvo

View file

@ -556,6 +556,21 @@ struct Transliteration
{}
};
struct Lingua
{
bool enable;
QString languageCodes;
bool operator == ( Lingua const & other ) const
{ return enable == other.enable &&
languageCodes == other.languageCodes;
}
bool operator != ( Lingua const & other ) const
{ return ! operator == ( other ); }
};
struct Forvo
{
bool enable;
@ -675,6 +690,7 @@ struct Class
DictServers dictServers;
Hunspell hunspell;
Transliteration transliteration;
Lingua lingua;
Forvo forvo;
Programs programs;
VoiceEngines voiceEngines;

View file

@ -179,6 +179,7 @@ bool EditDictionaries::isSourcesChanged() const
sources.getSoundDirs() != cfg.soundDirs ||
sources.getHunspell() != cfg.hunspell ||
sources.getTransliteration() != cfg.transliteration ||
sources.getLingua() != cfg.lingua ||
sources.getForvo() != cfg.forvo ||
sources.getMediaWikis() != cfg.mediawikis ||
sources.getWebSites() != cfg.webSites ||
@ -199,6 +200,7 @@ void EditDictionaries::acceptChangedSources( bool rebuildGroups )
cfg.soundDirs = sources.getSoundDirs();
cfg.hunspell = sources.getHunspell();
cfg.transliteration = sources.getTransliteration();
cfg.lingua = sources.getLingua();
cfg.forvo = sources.getForvo();
cfg.mediawikis = sources.getMediaWikis();
cfg.webSites = sources.getWebSites();

View file

@ -33,6 +33,7 @@ CONFIG( release, debug|release ) {
# DEPENDPATH += . generators
INCLUDEPATH += .
INCLUDEPATH += ./src/
QT += core \
gui \
@ -220,12 +221,12 @@ mac {
!CONFIG( no_macos_universal ) {
LIBS+= -lhunspell
INCLUDEPATH = $${PWD}/maclibs/include
INCLUDEPATH += $${PWD}/maclibs/include
LIBS += -L$${PWD}/maclibs/lib -framework AppKit -framework Carbon
}
else{
PKGCONFIG += hunspell
INCLUDEPATH = /opt/homebrew/include /usr/local/include
INCLUDEPATH += /opt/homebrew/include /usr/local/include
LIBS += -L/opt/homebrew/lib -L/usr/local/lib -framework AppKit -framework Carbon
}
@ -389,7 +390,8 @@ HEADERS += folding.hh \
gls.hh \
splitfile.hh \
favoritespanewidget.hh \
treeview.hh
treeview.hh \
src/dict/lingualibre.h
FORMS += groups.ui \
dictgroupwidget.ui \
@ -526,7 +528,8 @@ SOURCES += folding.cc \
gls.cc \
splitfile.cc \
favoritespanewidget.cc \
treeview.cc
treeview.cc \
src/dict/lingualibre.cpp
win32 {
FORMS += texttospeechsource.ui

5
icons/lingualibre.svg Normal file
View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="185" height="185" viewBox="0 0 185 185">
<path fill="#36c" d="M68.561 121.597c-2.978-4.623-6.253-8.865-6.818-16.284-.563-7.4-2.18-12.553-6.223-19.84-5.833-10.512-15.013-20.655-26.112-28.85-3.52-2.6-9.02-7.255-12.223-10.346-3.202-3.091-6.01-5.62-6.24-5.62-1.484 0 2.94 9.14 7.553 15.604 3.584 5.023 10.733 11.853 14.866 14.205 3.754 2.135 4.684 3.208 4.684 5.402 0 1.9-2.365 4.469-4.112 4.469-2.328 0-18.575-9.74-20.88-12.518-1.023-1.232-1.889-1.167-1.889.142 0 3.658 8.741 12.649 17.503 18.003 5.243 3.203 8.098 5.845 8.098 7.493 0 .433-.597 1.546-1.327 2.474-2.03 2.581-4.498 2.22-10.514-1.54-2.816-1.76-5.769-3.53-6.562-3.931-2.703-1.37-2.327.14.84 3.375 4.994 5.1 14.499 10.881 19.552 11.892 3.83.766 5.083 5.484 2.083 7.844-2.09 1.644-2.449 1.643-6.708-.016-11.616-4.524-21.336-11.74-26.762-19.866-2.19-3.279-2.603-4.414-2.603-7.144 0-2.474.338-3.606 1.424-4.761 1.371-1.46 1.383-1.58.331-3.242-3.096-4.888-4.303-8.204-4.309-11.837-.007-4.263 1.098-6.82 3.77-8.722l1.875-1.336-2.77-5.595c-1.523-3.077-3.109-7.28-3.524-9.34C-.84 29.786 8.388 20.882 14.398 29.33c6.147 8.639 11.546 13.983 20.498 20.287 5.188 3.653 18.621 16.948 22.634 22.4 1.684 2.288 4.994 6.558 5.35 6.558.355 0 2.793-4.37 3.604-6.778 2.786-8.27 5.74-12.084 13.701-15.947 4.966-2.41 4.496-3.708 11.72-3.724 6.716-.016 7.17 1.313 11.535 3.062 8.194 3.28 15.84 9.357 18.14 18.076.414 1.566-.354 3.825-.009 3.94.346.115 4.188-3.49 6.841-6.931 5.899-7.651 12.597-14.092 22.281-21.425 8.547-6.472 14.107-11.95 18.06-17.792 2.239-3.311 3.273-4.276 5.065-4.727 6.06-1.524 10.468 5.563 9.167 14.734-.243 1.712-1.743 5.908-3.333 9.324L176.76 56.6l2.026 1.705c2.734 2.3 4.068 5.636 3.731 9.329-.26 2.849-2.79 8.66-4.734 10.868-.81.92-.724 1.334.712 3.45.897 1.322 1.631 3.23 1.631 4.241 0 6.76-12.674 19.738-24.605 25.195-4.535 2.075-8.518 3.509-9.744 3.509-1.445 0-4.05-2.997-4.05-4.66 0-1.873 2.242-4.053 4.8-4.666 5.599-1.341 16.389-8.313 20.082-12.977 1.773-2.238 1.92-2.657.931-2.656-.645.002-2.902 1.169-5.014 2.595-2.112 1.425-4.908 3.152-6.214 3.838-4.576 2.4-8.186 1.046-8.186-3.071 0-2.215 1.943-3.998 8.582-7.875 6.598-3.854 16.379-13.806 16.379-16.666 0-1.742-.704-1.541-4.237 1.211-3.882 3.025-10.426 7.06-14.63 9.023-3.784 1.767-5.941 1.333-7.282-1.464-1.275-2.662-.246-4.289 4.83-7.628 7.74-5.095 14.262-12.436 19.268-21.693 1.969-3.64 3.558-8.191 2.86-8.191-.202 0-2.411 2.095-4.908 4.655-2.498 2.56-7.133 6.656-10.3 9.102-17.121 13.216-24.623 21.449-30.908 33.923-3.492 6.93-4.613 10.946-5.271 18.88-.642 7.738-1.937 11.677-5.623 17.105-21.196 12.229-35.879 16.783-48.327-2.086zm18.743-63.119c-2.192 0-9.34 3.062-12.143 5.992-3.094 3.235-6.644 9.611-6.361 11.596 1.328 22.81 1.546 37.198 1.907 41.092.556 5.09 12.614 9.97 16.38 11.691 5.286-6.76 2.047-70.303.218-70.372zm27.896 53.119c.22-12.293.79-7.607.22-12.293.47-13.768 1.727-3.3.488-10.908-.26-9.476-5.559-6.602 1.432-10.981.6-1.565-5.046-10.365-8.061-13.381-2.9-2.9-8.132-6.145-10.347-6.173-13.611-.04-9.4 41.59-2.454 71.554 5.77-3.212 18.338-10.785 18.722-17.818z"/>
<path fill="#474847" d="M90.209 155.748c-.704-.393-1.424-.84-1.6-.991s-.464-4.321-.64-9.264l-.32-8.987-4.8-1.696c-9.584-3.387-15.851-9.66-19.301-19.321-1.36-3.808-1.483-5.334-1.69-20.937-.222-16.691-.21-16.874 1.454-22.1 3.941-12.376 14.11-20.458 26.862-21.351 14.327-1.003 26.917 7.729 31.127 21.589 1.226 4.035 1.302 5.6 1.079 22.157-.276 20.378-.401 21.005-5.788 28.856-4.268 6.221-8.45 9.024-18.863 12.64-.585.204-.8 2.527-.8 8.648 0 8.032-.063 8.432-1.571 9.94-1.704 1.704-3.15 1.933-5.15.817zm-2.24-61.928c0-22.58-.216-33.376-.674-33.659-1.114-.689-7.648 2.9-10.354 5.69-2.918 3.007-5.612 7.955-5.612 10.31 0 1.505.216 1.621 3.04 1.63 1.672.006 3.386.23 3.808.499 1.325.842 1.98 3.517 1.324 5.4-.604 1.732-2.527 2.616-6.892 3.17-2.503.316-2.011 2.088.64 2.305 4.976.406 7.584 2.997 6.357 6.315-.697 1.882-1.676 2.385-5.397 2.77-2.663.276-3.2.547-3.2 1.612 0 .956.485 1.324 1.92 1.455 4.975.455 6.72 1.667 6.72 4.67 0 2.699-2.012 4.435-5.14 4.435-3.311 0-3.795 1.18-1.998 4.879 2.73 5.616 9.934 11.647 14.017 11.73l1.44.03zm13.954 31.706c1.667-.845 4.414-3.014 6.104-4.821 3.133-3.35 5.923-8.51 5.218-9.65-.216-.348-1.599-.637-3.074-.643-3.044-.01-3.786-.372-4.826-2.348-1.818-3.453.228-6.087 5.107-6.577 2.895-.29 3.437-.547 3.437-1.625 0-1.096-.537-1.328-3.74-1.613-4.004-.355-5.54-1.52-5.54-4.198 0-2.631 2.106-4.348 5.793-4.724 1.867-.19 3.504-.704 3.65-1.145.309-.936-.37-1.2-4.495-1.753-3.52-.472-5.356-2.455-4.697-5.078.638-2.545 2.146-3.569 5.255-3.569 1.912 0 2.973-.308 3.213-.934.542-1.414-2.496-7.51-5.285-10.602-2.398-2.66-9.482-6.677-10.578-5.999-.63.39-.736 65.761-.109 66.388.683.683 1.352.52 4.568-1.11z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.6 KiB

View file

@ -68,3 +68,6 @@ sources.png https://icons.iconarchive.com/icons/oxygen-icons.org/oxygen/128/Apps
book.svg https://github.com/johnfactotum/foliate
lingualibre.svg https://en.m.wikipedia.org/wiki/File:Lingualibre-logo-no-text.svg

View file

@ -31,6 +31,7 @@
#include "dictserver.hh"
#include "slob.hh"
#include "gls.hh"
#include "dict/lingualibre.h"
#ifndef NO_EPWING_SUPPORT
#include "epwing.hh"
@ -351,6 +352,15 @@ void loadDictionaries( QWidget * parent, bool showInitially,
dictionaries.insert( dictionaries.end(), dicts.begin(), dicts.end() );
}
//// Lingua Libre
{
vector< sptr< Dictionary::Class > > dicts =
Lingua::makeDictionaries( loadDicts, cfg.lingua, dictNetMgr );
dictionaries.insert( dictionaries.end(), dicts.begin(), dicts.end() );
}
//// Programs
{
vector< sptr< Dictionary::Class > > dicts =

View file

@ -22,6 +22,7 @@
<file>article-style-st-lingvo.css</file>
<file>icons/icon_dsl_native.png</file>
<file>icons/forvo.png</file>
<file>icons/lingualibre.svg</file>
<file>CREDITS.txt</file>
<file>icons/highlighter.png</file>
<file>icons/macicon.png</file>

View file

@ -34,6 +34,8 @@ Sources::Sources( QWidget * parent, Config::Class const & cfg):
Config::Hunspell const & hunspell = cfg.hunspell;
Config::Transliteration const & trs = cfg.transliteration;
Config::Lingua const & lingua = cfg.lingua;
Config::Forvo const & forvo = cfg.forvo;
// TODO: will programTypeEditorCreator and itemEditorFactory be destroyed by
@ -114,6 +116,9 @@ Sources::Sources( QWidget * parent, Config::Class const & cfg):
ui.enableHiragana->setChecked( trs.romaji.enableHiragana );
ui.enableKatakana->setChecked( trs.romaji.enableKatakana );
ui.linguaEnabled->setChecked(lingua.enable);
ui.linguaLangCode->setText(lingua.languageCodes);
ui.forvoEnabled->setChecked( forvo.enable );
ui.forvoApiKey->setText( forvo.apiKey );
ui.forvoLanguageCodes->setText( forvo.languageCodes );
@ -376,6 +381,17 @@ Config::Transliteration Sources::getTransliteration() const
return tr;
}
Config::Lingua Sources::getLingua() const
{
Config::Lingua lingua;
lingua.enable = ui.linguaEnabled->isChecked();
lingua.languageCodes = ui.linguaLangCode -> text();
return lingua;
}
Config::Forvo Sources::getForvo() const
{
Config::Forvo forvo;

View file

@ -279,6 +279,8 @@ public:
Config::Transliteration getTransliteration() const;
Config::Lingua getLingua() const;
Config::Forvo getForvo() const;
signals:

View file

@ -6,18 +6,18 @@
<rect>
<x>0</x>
<y>0</y>
<width>929</width>
<width>1010</width>
<height>336</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">Sources</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
<number>7</number>
</property>
<property name="iconSize">
<size>
@ -456,6 +456,74 @@ of the appropriate groups to use them.</string>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_lingua">
<attribute name="icon">
<iconset resource="resources.qrc">
<normaloff>:/icons/lingualibre.svg</normaloff>:/icons/lingualibre.svg</iconset>
</attribute>
<attribute name="title">
<string>Lingua Libre</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QLabel" name="label_17">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Prouncations provied by &lt;a href=&quot;https://lingualibre.org&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#2980b9;&quot;&gt;Lingua Libre&lt;/span&gt;&lt;/a&gt;, a collaborative linguistic media library of Wikimedia France. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="linguaEnabled">
<property name="title">
<string>Enable Lingua Libre</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>ISO 639-3 language code</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="linguaLangCode"/>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Examples: &amp;quot;eng&amp;quot; for Enligh, &amp;quot;fra&amp;quot; for French) &lt;br&gt;
Full list of availiable languages can be found &lt;a href=&quot;https://lingualibre.org/wiki/LinguaLibre:Stats/Languages&quot;&gt; here &lt;/a&gt;</string>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_5">
<attribute name="icon">
<iconset resource="resources.qrc">

495
src/dict/lingualibre.cpp Normal file
View file

@ -0,0 +1,495 @@
#include "lingualibre.h"
#include "utf8.hh"
#include "audiolink.hh"
#include <string>
#include <mutex.hh>
#include <QJsonDocument>
#include <utility>
namespace Lingua {
using namespace Dictionary;
namespace {
class LinguaDictionary: public Dictionary::Class
{
string name;
QString languageCode;
QString langWikipediaID;
QNetworkAccessManager & netMgr;
public:
LinguaDictionary( string const & id, string name_, QString languageCode_, QNetworkAccessManager & netMgr_ ):
Dictionary::Class( id, vector< string >() ),
name( std::move( name_ ) ),
languageCode( std::move( languageCode_ ) ),
netMgr( netMgr_ )
{
/* map of iso lang code to wikipedia lang id
Data was obtained by this query on https://commons-query.wikimedia.org/
SELECT ?language ?languageLabel ?iso ?audios
WHERE {
{
SELECT ?language (COUNT(?audio) AS ?audios) WHERE {
# Comment out the below statement to filter to only certain languages (e.g. Q34 or others)
# VALUES ?language { entity:Q34 }
?audio # Filter: P2 'instance of' is Q2 'record'
wdt:P407 ?language .
}
GROUP BY ?language
}
SERVICE <https://query.wikidata.org/sparql> {
?language wdt:P220 ?iso . # Assign value: P220 'ISO-639-3' into ?iso.
}
SERVICE <https://query.wikidata.org/sparql> {
SERVICE wikibase:label {
bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en".
?language rdfs:label ?languageLabel .
}
}
}
*/
const map< string, string > iso_to_wikipedia_id = { { "grc", "Q35497" },
{ "non", "Q35505" },
{ "ken", "Q35650" },
{ "got", "Q35722" },
{ "gsc", "Q35735" },
{ "ldn", "Q35757" },
{ "csc", "Q35768" },
{ "lns", "Q35788" },
{ "kab", "Q35853" },
{ "ina", "Q35934" },
{ "jam", "Q35939" },
{ "mua", "Q36032" },
{ "mhk", "Q36068" },
{ "mos", "Q36096" },
{ "kmr", "Q36163" },
{ "num", "Q36173" },
{ "mad", "Q36213" },
{ "lin", "Q36217" },
{ "mal", "Q36236" },
{ "srr", "Q36284" },
{ "jbo", "Q36350" },
{ "yas", "Q36358" },
{ "kur", "Q36368" },
{ "ell", "Q36510" },
{ "swl", "Q36558" },
{ "gya", "Q36594" },
{ "tvu", "Q36632" },
{ "mlu", "Q36645" },
{ "tui", "Q36646" },
{ "ota", "Q36730" },
{ "rar", "Q36745" },
{ "ckb", "Q36811" },
{ "tok", "Q36846" },
{ "twi", "Q36850" },
{ "vut", "Q36897" },
{ "ybb", "Q36917" },
{ "bse", "Q36973" },
{ "wls", "Q36979" },
{ "lzh", "Q37041" },
{ "ang", "Q42365" },
{ "ker", "Q56251" },
{ "ary", "Q56426" },
{ "sjn", "Q56437" },
{ "hau", "Q56475" },
{ "arq", "Q56499" },
{ "atj", "Q56590" },
{ "mcn", "Q56668" },
{ "tpw", "Q56944" },
{ "vls", "Q100103" },
{ "gsw", "Q131339" },
{ "hrx", "Q304049" },
{ "lms", "Q427614" },
{ "sxu", "Q699284" },
{ "pwn", "Q715755" },
{ "tay", "Q715766" },
{ "guc", "Q891085" },
{ "lnc", "Q942602" },
{ "blc", "Q977808" },
{ "avk", "Q1377116" },
{ "sba", "Q2372207" },
{ "gcf", "Q3006280" },
{ "far", "Q3067168" },
{ "kld", "Q3111818" },
{ "swh", "Q3197533" },
{ "rhg", "Q3241177" },
{ "vsl", "Q3322064" },
{ "xzh", "Q3437292" },
{ "ane", "Q3571097" },
{ "kcg", "Q3912765" },
{ "hav", "Q5684097" },
{ "isu", "Q6089423" },
{ "mdl", "Q6744816" },
{ "duf", "Q6983819" },
{ "sru", "Q7646993" },
{ "yat", "Q8048020" },
{ "lem", "Q13479983" },
{ "mul", "Q20923490" },
{ "cmn", "Q9192" },
{ "vie", "Q9199" },
{ "tha", "Q9217" },
{ "msa", "Q9237" },
{ "ind", "Q9240" },
{ "mon", "Q9246" },
{ "tgk", "Q9260" },
{ "uzb", "Q9264" },
{ "heb", "Q9288" },
{ "aze", "Q9292" },
{ "mkd", "Q9296" },
{ "bos", "Q9303" },
{ "glg", "Q9307" },
{ "cym", "Q9309" },
{ "gla", "Q9314" },
{ "ben", "Q9610" },
{ "tlh", "Q10134" },
{ "bre", "Q12107" },
{ "rcf", "Q13198" },
{ "xho", "Q13218" },
{ "hsb", "Q13248" },
{ "sms", "Q13271" },
{ "nav", "Q13310" },
{ "min", "Q13324" },
{ "mnw", "Q13349" },
{ "ara", "Q13955" },
{ "oci", "Q14185" },
{ "afr", "Q14196" },
{ "sco", "Q14549" },
{ "ase", "Q14759" },
{ "pms", "Q15085" },
{ "fao", "Q25258" },
{ "tat", "Q25285" },
{ "cor", "Q25289" },
{ "kal", "Q25355" },
{ "nds", "Q25433" },
{ "fry", "Q27175" },
{ "ace", "Q27683" },
{ "ain", "Q27969" },
{ "aka", "Q28026" },
{ "amh", "Q28244" },
{ "anp", "Q28378" },
{ "rup", "Q29316" },
{ "arz", "Q29919" },
{ "myv", "Q29952" },
{ "dag", "Q32238" },
{ "dyu", "Q32706" },
{ "bfi", "Q33000" },
{ "dua", "Q33013" },
{ "ban", "Q33070" },
{ "bas", "Q33093" },
{ "cos", "Q33111" },
{ "bam", "Q33243" },
{ "chy", "Q33265" },
{ "shy", "Q33274" },
{ "bcl", "Q33284" },
{ "gaa", "Q33287" },
{ "fon", "Q33291" },
{ "fil", "Q33298" },
{ "fsl", "Q33302" },
{ "che", "Q33350" },
{ "chr", "Q33388" },
{ "fur", "Q33441" },
{ "smn", "Q33462" },
{ "hat", "Q33491" },
{ "syc", "Q33538" },
{ "jav", "Q33549" },
{ "kas", "Q33552" },
{ "haw", "Q33569" },
{ "ibo", "Q33578" },
{ "kik", "Q33587" },
{ "mnc", "Q33638" },
{ "kan", "Q33673" },
{ "krc", "Q33714" },
{ "ory", "Q33810" },
{ "orm", "Q33864" },
{ "mni", "Q33868" },
{ "nso", "Q33890" },
{ "sat", "Q33965" },
{ "scn", "Q33973" },
{ "srd", "Q33976" },
{ "srn", "Q33989" },
{ "snd", "Q33997" },
{ "sun", "Q34002" },
{ "pcd", "Q34024" },
{ "ddo", "Q34033" },
{ "tvl", "Q34055" },
{ "tgl", "Q34057" },
{ "nmg", "Q34098" },
{ "tsn", "Q34137" },
{ "shi", "Q34152" },
{ "lua", "Q34173" },
{ "rif", "Q34174" },
{ "wln", "Q34219" },
{ "wol", "Q34257" },
{ "bci", "Q35107" },
{ "cak", "Q35115" },
{ "ido", "Q35224" },
{ "bbj", "Q35271" },
{ "bik", "Q35455" },
{ "epo", "Q143" },
{ "fra", "Q150" },
{ "deu", "Q188" },
{ "tur", "Q256" },
{ "isl", "Q294" },
{ "lat", "Q397" },
{ "ita", "Q652" },
{ "pol", "Q809" },
{ "spa", "Q1321" },
{ "fin", "Q1412" },
{ "hin", "Q1568" },
{ "mar", "Q1571" },
{ "eng", "Q1860" },
{ "aym", "Q4627" },
{ "guj", "Q5137" },
{ "por", "Q5146" },
{ "que", "Q5218" },
{ "jpn", "Q5287" },
{ "tam", "Q5885" },
{ "hrv", "Q6654" },
{ "cat", "Q7026" },
{ "nld", "Q7411" },
{ "rus", "Q7737" },
{ "swa", "Q7838" },
{ "zho", "Q7850" },
{ "ron", "Q7913" },
{ "bul", "Q7918" },
{ "mlg", "Q7930" },
{ "tel", "Q8097" },
{ "yid", "Q8641" },
{ "sqi", "Q8748" },
{ "eus", "Q8752" },
{ "hye", "Q8785" },
{ "ukr", "Q8798" },
{ "swe", "Q9027" },
{ "dan", "Q9035" },
{ "nor", "Q9043" },
{ "ltz", "Q9051" },
{ "ces", "Q9056" },
{ "slv", "Q9063" },
{ "hun", "Q9067" },
{ "est", "Q9072" },
{ "bel", "Q9091" },
{ "ell", "Q9129" },
{ "gle", "Q9142" },
{ "mlt", "Q9166" },
{ "fas", "Q9168" },
{ "kor", "Q9176" },
{ "yue", "Q9186" } };
// END OF iso_to_wikipedia_id
auto it = iso_to_wikipedia_id.find(languageCode.toStdString());
if (it != iso_to_wikipedia_id.end()){
langWikipediaID = QString::fromStdString(it->second);
}
}
string getName() noexcept override { return name; }
map< Property, string > getProperties() noexcept override { return {}; }
unsigned long getArticleCount() noexcept override { return 0; }
unsigned long getWordCount() noexcept override { return 0; }
sptr< WordSearchRequest > prefixMatch( wstring const & /*word*/, unsigned long /*maxResults*/ ) override
{
sptr< WordSearchRequestInstant > sr = std::make_shared< WordSearchRequestInstant >();
sr->setUncertain( true );
return sr;
}
sptr< DataRequest > getArticle(
wstring const & word, vector< wstring > const & alts, wstring const &, bool ) override
{
if( word.size() > 50 )
{
return std::make_shared< DataRequestInstant >( false );
}
else
{
return std::make_shared< LinguaArticleRequest >( word, alts, languageCode,langWikipediaID, getId(), netMgr );
}
}
protected:
void loadIcon() noexcept override
{
if( dictionaryIconLoaded )
return;
dictionaryIcon = dictionaryNativeIcon = QIcon( ":/icons/lingualibre.svg" );
dictionaryIconLoaded = true;
}
};
}
vector< sptr< Dictionary::Class > > makeDictionaries(
Dictionary::Initializing &, Config::Lingua const & lingua, QNetworkAccessManager & mgr )
{
vector< sptr< Dictionary::Class > > result;
if( lingua.enable and !lingua.languageCodes.isEmpty() )
{
QCryptographicHash hash( QCryptographicHash::Md5 );
hash.addData( "Lingua libre via Wiki Commons" );
result.push_back( std::make_shared< LinguaDictionary >( hash.result().toHex().data(),
QString( "LinguaLibre" ).toUtf8().data(),
lingua.languageCodes,
mgr ) );
}
return result;
};
void LinguaArticleRequest::cancel() {}
LinguaArticleRequest::LinguaArticleRequest( const wstring & str,
const vector< wstring > & alts,
const QString & languageCode_,
const QString & langWikipediaID,
const string & dictionaryId_,
QNetworkAccessManager & mgr ):
languageCode(languageCode_),
langWikipediaID(langWikipediaID)
{
connect( &mgr, &QNetworkAccessManager::finished, this, &LinguaArticleRequest::requestFinished, Qt::QueuedConnection );
addQuery( mgr, str );
}
void LinguaArticleRequest::addQuery( QNetworkAccessManager & mgr, const wstring & word )
{
// Doc of the <https://www.mediawiki.org/wiki/API:Query>
QString reqUrl = R"(https://commons.wikimedia.org/w/api.php?)"
R"(action=query)"
R"(&format=json)"
R"(&prop=imageinfo)"
R"(&generator=search)"
R"(&iiprop=url)"
R"(&iimetadataversion=1)"
R"(&iiextmetadatafilter=Categories)"
R"(&gsrsearch=intitle:LL-%1 \(%2\)-.*-%3\.wav/)"
R"(&gsrnamespace=6)"
R"(&gsrlimit=10)"
R"(&gsrwhat=text)";
reqUrl = reqUrl.arg(languageCode,langWikipediaID,QString::fromStdU32String( word ) );
qDebug()<< "lingualibre query " << reqUrl;
auto netReply =
std::shared_ptr< QNetworkReply >( mgr.get(
QNetworkRequest( reqUrl ) ) );
netReplies.emplace_back( netReply, Utf8::encode( word ) );
}
void LinguaArticleRequest::requestFinished( QNetworkReply * r )
{
qDebug() << "Lingua query finished";
sptr< QNetworkReply > netReply = netReplies.front().reply;
QJsonObject resultJson = QJsonDocument::fromJson( netReply->readAll() ).object();
/*
Code below is to process returned json:
{
"batchcomplete": "",
"query": {
"pages": {
"88511149": {
"pageid": 88511149,
"ns": 6,
"title": "File:LL-Q1860 (eng)-Back ache-nice.wav",
"index": 2,
"imagerepository": "local",
"imageinfo": [
{
"url": "https://upload.wikimedia.org/wikipedia/commons/6/6a/LL-Q1860_%28eng%29-Back_ache-nice.wav",
"descriptionurl": "https://commons.wikimedia.org/wiki/File:LL-Q1860_(eng)-Back_ache-nice.wav",
"descriptionshorturl": "https://commons.wikimedia.org/w/index.php?curid=88511149"
}
]
},
"73937351": {
"pageid": 73937351,
"ns": 6,
"title": "File:LL-Q1860 (eng)-Nattes à chat-nice.wav",
"index": 1,
"imagerepository": "local",
"imageinfo": [
{
"url": "https://upload.wikimedia.org/wikipedia/commons/b/b0/LL-Q1860_%28eng%29-Nattes_%C3%A0_chat-nice.wav",
"descriptionurl": "https://commons.wikimedia.org/wiki/File:LL-Q1860_(eng)-Nattes_%C3%A0_chat-nice.wav",
"descriptionshorturl": "https://commons.wikimedia.org/w/index.php?curid=73937351"
}
]
}
}
}
}
*/
if( resultJson.contains( "query" ) )
{
string articleBody = "<p>";
for( auto pageJsonVal : resultJson[ "query" ].toObject()[ "pages" ].toObject() )
{
auto pageJsonObj = pageJsonVal.toObject();
string title = pageJsonObj[ "title" ].toString().toHtmlEscaped().toStdString();
string audiolink =
pageJsonObj[ "imageinfo" ].toArray().at( 0 ).toObject()[ "url" ].toString().toHtmlEscaped().toStdString();
articleBody += addAudioLink( audiolink, dictionaryId );
articleBody += "<a href=";
articleBody += audiolink;
articleBody += ">";
articleBody += R"(<img src="qrcx://localhost/icons/playsound.png" border="0" alt="Play"/>)";
articleBody += title;
articleBody += "</a><br>";
}
articleBody += "</p>";
Mutex::Lock _( dataMutex );
size_t prevSize = data.size();
data.resize( prevSize + articleBody.size() );
memcpy( &data.front() + prevSize, articleBody.data(), articleBody.size() );
hasAnyData = true;
finish();
}
else
{
hasAnyData = false;
}
}
} // end namespace Lingua

65
src/dict/lingualibre.h Normal file
View file

@ -0,0 +1,65 @@
#ifndef GOLDENDICT_LINGUALIBRE_H
#define GOLDENDICT_LINGUALIBRE_H
#include "dictionary.hh"
#include "config.hh"
#include "wstring.hh"
#include <QNetworkAccessManager>
#include <QNetworkReply>
namespace Lingua{
using std::vector;
using std::string;
using gd::wstring;
vector< sptr< Dictionary::Class > > makeDictionaries(
Dictionary::Initializing &,
Config::Lingua const &,
QNetworkAccessManager & );
/// Exposed here for moc
class LinguaArticleRequest: public Dictionary::DataRequest
{
Q_OBJECT
struct NetReply
{
sptr< QNetworkReply > reply;
string word;
bool finished;
NetReply( sptr< QNetworkReply > const & reply_, string const & word_ ):
reply( reply_ ), word( word_ ), finished( false )
{}
};
typedef std::list< NetReply > NetReplies;
NetReplies netReplies;
QString languageCode,langWikipediaID;
string dictionaryId;
public:
LinguaArticleRequest( wstring const & word,
vector< wstring > const & alts,
QString const & languageCode_,
QString const & langWikipediaID_,
string const & dictionaryId_,
QNetworkAccessManager & mgr );
virtual void cancel();
private:
void addQuery( QNetworkAccessManager & mgr, wstring const & word );
private slots:
virtual void requestFinished( QNetworkReply * );
};
}
#endif //GOLDENDICT_LINGUALIBRE_H