merge conflict

This commit is contained in:
YiFang Xiao 2023-12-08 09:34:00 +08:00
commit 299bc876b1
22 changed files with 1401 additions and 124 deletions

View file

@ -49,6 +49,7 @@ jobs:
- name: install deps on macos
run: |
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=TRUE
brew install cmake ninja
brew install automake
brew install autoconf

View file

@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
os: [macos-13]
qt_ver: [ 6.5.2,6.6.0 ]
qt_ver: [ 6.6.0 ]
qt_arch: [clang_64]
env:
targetName: GoldenDict

View file

@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
os: [macos-12,macos-13]
qt_ver: [ 6.5.2,6.6.0 ]
qt_ver: [ 6.6.0,6.6.1 ]
qt_arch: [clang_64]
env:
targetName: GoldenDict
@ -42,6 +42,7 @@ jobs:
- name: install deps on macos
run: |
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=TRUE
brew install cmake ninja
brew install automake
brew install autoconf
@ -101,22 +102,16 @@ jobs:
macdeployqt ${targetName}.app -qmldir=. -verbose=1
otool -L GoldenDict.app/Contents/MacOS/GoldenDict
ls -al GoldenDict.app/Contents/Frameworks
otool -L GoldenDict.app/Contents/Frameworks/libzim.8.dylib
# otool -L GoldenDict.app/Contents/Frameworks/libav*
# otool -L GoldenDict.app/Contents/Frameworks/libjxl.0.8.dylib
# cp -r /usr/local/Cellar/icu4c/7*/lib/libicu*.dylib GoldenDict.app/Contents/Frameworks
# cp -r /usr/local/Cellar/zstd/1.5.5/lib/libzstd.1.dylib GoldenDict.app/Contents/Frameworks
dylibbundler -of -b -x GoldenDict.app/Contents/Frameworks/libzim.8.dylib -d GoldenDict.app/Contents/Frameworks/ -p @executable_path/../Frameworks -s /usr/local/ -s /opt/
# dylibbundler -of -b -x GoldenDict.app/Contents/Frameworks/libicu* -d GoldenDict.app/Contents/Frameworks/ -p @executable_path/../Frameworks -s /usr/local/ -s /opt/
find /usr/local/Cellar -name "libicudata.73.dylib" -exec cp {} GoldenDict.app/Contents/Frameworks/ \;
find GoldenDict.app/Contents/Frameworks/ -maxdepth 1 -type f -name "libicu*" -exec dylibbundler -of -b -x {} -d GoldenDict.app/Contents/Frameworks/ -p @executable_path/../Frameworks -s /usr/local/ -s /opt/ \;
# dylibbundler -of -x GoldenDict.app/Contents/Frameworks/libavformat.60.dylib -x GoldenDict.app/Contents/Frameworks/libavcodec.60.dylib -d GoldenDict.app/Contents/Frameworks/ -p @executable_path/../Frameworks -s /usr/local/ -s /opt/
# dylibbundler -of -b -x GoldenDict.app/Contents/Frameworks/libjxl.0.8.dylib -d GoldenDict.app/Contents/Frameworks/ -p @executable_path/../Frameworks -s /usr/local/ -s /opt/
find GoldenDict.app/Contents/Frameworks/ -maxdepth 1 -name "libicu*" -exec ls -al {} \;
find GoldenDict.app/Contents/Frameworks/ -maxdepth 1 -type f -name "libicu*" -exec ls -al {} \;
find GoldenDict.app/Contents/Frameworks/ -maxdepth 1 -type f -name "libzim*" -exec dylibbundler -of -b -x {} -d GoldenDict.app/Contents/Frameworks/ -p @executable_path/../Frameworks -s /usr/local/ -s /opt/ \;
find GoldenDict.app/Contents/Frameworks/ -maxdepth 1 -name "libicu*" -exec dylibbundler -of -b -x {} -d GoldenDict.app/Contents/Frameworks/ -p @executable_path/../Frameworks -s /usr/local/ -s /opt/ \;
otool -L GoldenDict.app/Contents/Frameworks/libicu*
otool -L GoldenDict.app/Contents/Frameworks/libzim.8.dylib
otool -L GoldenDict.app/Contents/Frameworks/libxapian.30.dylib
otool -L GoldenDict.app/Contents/Frameworks/liblzma.5.dylib
otool -L GoldenDict.app/Contents/Frameworks/libzim*
codesign --force --deep -s - GoldenDict.app

View file

@ -21,7 +21,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-20.04]
qt_ver: [ 6.5.2,6.6.0 ]
qt_ver: [ 6.6.0 ]
qt_arch: [gcc_64]
env:
version: 23.11.08

View file

@ -27,7 +27,7 @@ jobs:
strategy:
matrix:
os: [windows-2019]
qt_ver: [6.5.2,6.6.0 ]
qt_ver: [ 6.6.0,6.6.1 ]
qt_arch: [win64_msvc2019_64]
env:
targetName: GoldenDict.exe

View file

@ -41,9 +41,4 @@
<provides>
<id>org.goldendict_ng.desktop</id>
</provides>
<releases>
<release version="23.09.08" date="2023-09-08"/>
<release version="23.07.23" date="2023-07-23"/>
<release version="23.06.01" date="2023-06-01"/>
</releases>
</component>

View file

@ -141,6 +141,7 @@ std::string ArticleMaker::makeHtmlHeader( QString const & word, QString const &
.toStdString();
result += R"(<script src="qrc:///scripts/gd-builtin.js"></script>)";
result += R"(<script src="qrc:///scripts/mark.min.js"></script>)";
if ( GlobalBroadcaster::instance()->getPreference()->darkReaderMode ) {
//only enable this darkmode on modern style.
@ -674,8 +675,8 @@ void ArticleRequest::bodyFinished()
fmt::format_to( std::back_inserter( head ),
FMT_COMPILE(
R"( <div class="gdarticle {0} {1}" id="{2}"
onClick="gdMakeArticleActive( '{3}', false );"
onContextMenu="gdMakeArticleActive( '{3}', false );">)" ),
onClick="if(typeof gdMakeArticleActive !='undefined') gdMakeArticleActive( '{3}', false );"
onContextMenu="if(typeof gdMakeArticleActive !='undefined') gdMakeArticleActive( '{3}', false );">)" ),
closePrevSpan ? "" : " gdactivearticle",
collapse ? " gdcollapsedarticle" : "",
gdFrom,

View file

@ -35,6 +35,20 @@ bool endsWithIgnoreCase( const string & str1, string str2 )
return ( str1.size() >= (unsigned)str2.size() )
&& ( strcasecmp( str1.c_str() + ( str1.size() - str2.size() ), str2.data() ) == 0 );
}
QString escapeAmps( QString const & str )
{
QString result( str );
result.replace( "&", "&&" );
return result;
}
QString unescapeAmps( QString const & str )
{
QString result( str );
result.replace( "&&", "&" );
return result;
}
} // namespace Utils
QString Utils::Path::combine( const QString & path1, const QString & path2 )

View file

@ -341,6 +341,10 @@ void removeDirectory( QString const & directory );
void removeDirectory( string const & directory );
} // namespace Fs
QString escapeAmps( QString const & str );
QString unescapeAmps( QString const & str );
} // namespace Utils
#endif // UTILS_HH

View file

@ -12,7 +12,7 @@
#include <exception>
#include <stdio.h>
#include <wctype.h>
#include <QtEndian>
#include <algorithm>
namespace Dsl {
@ -832,7 +832,33 @@ DslScanner::DslScanner( string const & fileName ):
bool needExactEncoding = false;
QByteArray ba = QByteArray::fromRawData( (const char *)firstBytes, 50 );
codec = QTextCodec::codecForUtfText( ba, QTextCodec::codecForName( "UTF-8" ) );
codec = QTextCodec::codecForUtfText( ba, nullptr );
if ( !codec ) {
// the encoding has no bom.
// check the first char # (0x23).
auto hashTag = 0x0023;
auto uci = qFromUnaligned< uint32_t >( firstBytes );
if ( uci == qToBigEndian( hashTag ) ) {
codec = QTextCodec::codecForMib( 1018 ); // utf-32 be
}
else if ( uci == qToLittleEndian( hashTag ) ) {
codec = QTextCodec::codecForMib( 1019 ); // utf-32 le
}
else {
auto uc = qFromUnaligned< uint16_t >( firstBytes );
if ( uc == qToBigEndian( uint16_t( hashTag ) ) ) {
codec = QTextCodec::codecForMib( 1013 ); // utf16 be
}
else if ( uc == qToLittleEndian( uint16_t( hashTag ) ) ) {
codec = QTextCodec::codecForMib( 1014 ); // utf16 le
}
else {
//default encoding
codec = QTextCodec::codecForName( "UTF-8" );
}
}
}
encoding = Utf8::getEncodingForName( codec->name() );
qDebug() << codec->name();

View file

@ -320,7 +320,7 @@ bool MdictParser::readHeader( QDataStream & in )
if ( headerText.contains( "StyleSheet" ) ) {
// a workaround to bypass https://bugreports.qt.io/browse/QTBUG-102612
QRegularExpression rx( "StyleSheet=\"([^\"]*?)\"", QRegularExpression::CaseInsensitiveOption );
QRegularExpression const rx( "StyleSheet=\"([^\"]*?)\"", QRegularExpression::CaseInsensitiveOption );
auto match = rx.match( headerText );
@ -334,6 +334,9 @@ bool MdictParser::readHeader( QDataStream & in )
QDomNamedNodeMap headerAttributes = parseHeaderAttributes( headerText );
if ( headerAttributes.isEmpty() )
return false;
encoding_ = headerAttributes.namedItem( "Encoding" ).toAttr().value();
if ( encoding_ == "GBK" || encoding_ == "GB2312" ) {
encoding_ = "GB18030";

View file

@ -31,10 +31,8 @@ bool ftsIndexIsOldOrBad( BtreeIndexing::BtreeDictionary * dict )
auto document = db.get_document( docid );
string const lastDoc = document.get_data();
bool const notFinished = lastDoc != finish_mark;
qDebug() << dict->ftsIndexName().c_str() << document.get_data().c_str() << notFinished;
return lastDoc != finish_mark;
//use a special document to mark the end of the index.
return notFinished;
}
catch ( Xapian::Error & e ) {
qWarning() << e.get_description().c_str();
@ -118,8 +116,9 @@ void makeFTSIndex( BtreeIndexing::BtreeDictionary * dict, QAtomicInt & isCancell
for ( auto const & address : offsets ) {
indexedDoc++;
if ( address > lastAddress && skip ) {
if ( address == lastAddress && skip ) {
skip = false;
continue;
}
//skip until to the lastAddress;
if ( skip ) {
@ -138,12 +137,8 @@ void makeFTSIndex( BtreeIndexing::BtreeDictionary * dict, QAtomicInt & isCancell
indexer.set_document( doc );
if ( GlobalBroadcaster::instance()->getPreference()->fts.enablePosition ) {
indexer.index_text( articleStr.toStdString() );
}
else {
indexer.index_text_without_positions( articleStr.toStdString() );
}
doc.set_data( std::to_string( address ) );
// Add the document to the database.
@ -199,10 +194,14 @@ void FTSResultsRequest::run()
// Parse the query string to produce a Xapian::Query object.
Xapian::QueryParser qp;
qp.set_database( db );
Xapian::QueryParser::feature_flag flag = Xapian::QueryParser::FLAG_DEFAULT;
if ( searchMode == FTS::Wildcards )
flag = Xapian::QueryParser::FLAG_WILDCARD;
Xapian::Query query = qp.parse_query( query_string, flag | Xapian::QueryParser::FLAG_CJK_NGRAM );
qp.set_default_op( Xapian::Query::op::OP_AND );
int flag =
Xapian::QueryParser::FLAG_DEFAULT | Xapian::QueryParser::FLAG_PURE_NOT | Xapian::QueryParser::FLAG_CJK_NGRAM;
if ( searchMode == FTS::Wildcards ) {
flag = flag | Xapian::QueryParser::FLAG_WILDCARD;
qp.set_max_expansion( 1 );
}
Xapian::Query query = qp.parse_query( query_string, flag );
qDebug() << "Parsed query is: " << query.get_description().c_str();
// Find the top 100 results for the query.

View file

@ -60,7 +60,7 @@ void IframeSchemeHandler::requestStarted( QWebEngineUrlRequestJob * requestJob )
QString root = reply->url().scheme() + "://" + reply->url().host();
if ( reply->url().port() != 80 && reply->url().port() != 443 ) {
if ( reply->url().port() != 80 && reply->url().port() != 443 && reply->url().port() != -1 ) {
root = root + ":" + QString::number( reply->url().port() );
}
QString base = root + reply->url().path();

View file

@ -307,7 +307,7 @@ void processCommandLine( QCoreApplication * app, GDOptions * result )
int main( int argc, char ** argv )
{
#ifdef Q_OS_UNIX
#if defined( Q_OS_UNIX ) && !defined( Q_OS_MACOS )
// GoldenDict use lots of X11 functions and it currently cannot work
// natively on Wayland. This workaround will force GoldenDict to use
// XWayland.

1241
src/scripts/mark.js Normal file

File diff suppressed because it is too large Load diff

13
src/scripts/mark.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -9,5 +9,6 @@
<file>jquery-3.6.0.slim.min.js</file>
<file>popper.min.js</file>
<file>tippy.min.js</file>
<file>mark.min.js</file>
</qresource>
</RCC>

View file

@ -30,6 +30,7 @@
#include <QWebEngineSettings>
#include <map>
#include <QApplication>
#include <QRandomGenerator>
#if ( QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) && QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 ) )
#include <QWebEngineContextMenuData>
@ -477,9 +478,10 @@ void ArticleView::loadFinished( bool result )
if ( result ) {
emit pageLoaded( this );
}
if ( Utils::Url::hasQueryItem( webview->url(), "regexp" ) )
if ( Utils::Url::hasQueryItem( webview->url(), "regexp" ) ) {
highlightFTSResults();
}
}
void ArticleView::handleTitleChanged( QString const & title )
{
@ -555,9 +557,10 @@ bool ArticleView::setCurrentArticle( QString const & id, bool moveToIt )
QString dictId = id.mid( 7 );
if ( dictId.isEmpty() )
return false;
QString script = QString(
QString script =
QString(
"var elem=document.getElementById('%1'); "
"if(elem!=undefined){elem.scrollIntoView(true);} gdMakeArticleActive('%2',true);" )
"if(elem!=undefined){elem.scrollIntoView(true);} if(typeof gdMakeArticleActive !='undefined') gdMakeArticleActive('%2',true);" )
.arg( id, dictId );
onJsActiveArticleChanged( id );
webview->page()->runJavaScript( script );
@ -1491,6 +1494,7 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
QAction * addHeaderToHistoryAction = nullptr;
QAction * sendWordToInputLineAction = nullptr;
QAction * saveImageAction = nullptr;
QAction * openImageAction = nullptr;
QAction * saveSoundAction = nullptr;
QAction * saveBookmark = nullptr;
@ -1534,6 +1538,9 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
menu.addAction( webview->pageAction( QWebEnginePage::CopyImageToClipboard ) );
saveImageAction = new QAction( tr( "Save &image..." ), &menu );
menu.addAction( saveImageAction );
openImageAction = new QAction( tr( "Open image in system viewer..." ), &menu );
menu.addAction( openImageAction );
}
}
@ -1746,6 +1753,36 @@ void ArticleView::contextMenuRequested( QPoint const & pos )
saveResource( url, webview->url(), fileName );
}
}
else if ( result == openImageAction ) {
QUrl url = imageUrl;
QString fileName;
QString name = Utils::Url::path( url ).section( '/', -1 );
// Image data
// Check for babylon image name
if ( name[ 0 ] == '\x1E' )
name.remove( 0, 1 );
if ( name.length() && name[ name.length() - 1 ] == '\x1F' )
name.chop( 1 );
fileName = QDir::temp().filePath( QString::number( QRandomGenerator::global()->generate() ) + name );
if ( !fileName.isEmpty() ) {
QFileInfo fileInfo( fileName );
auto handler = saveResource( url, webview->url(), fileName );
if ( !handler->isEmpty() ) {
connect( handler, &ResourceToSaveHandler::done, this, [ fileName ]() {
QDesktopServices::openUrl( fileName );
} );
}
else {
QDesktopServices::openUrl( fileName );
}
}
}
else {
if ( !popupView && result == maxDictionaryRefsAction )
emit showDictsPane();
@ -2136,54 +2173,21 @@ void ArticleView::highlightFTSResults()
if ( regString.isEmpty() )
return;
//<div><i>watch</i>out</div> to plainText will return "watchout".
//if application goes here,that means the article text must contains the search text.
//whole word match regString will contain \b . can not match the above senario.
//workaround ,remove \b from the regstring="(\bwatch\b)"
regString.remove( QRegularExpression( R"(\b)" ) );
//make it simple ,and do not support too much complex cases. such as wildcard etc.
firstAvailableText = regString;
//replace any unicode Number ,Symbol ,Punctuation ,Mark character to whitespace
regString.replace( QRegularExpression( R"([\p{N}\p{S}\p{P}\p{M}])", QRegularExpression::UseUnicodePropertiesOption ),
" " );
if ( firstAvailableText.isEmpty() ) {
return;
}
//remove possible wildcard character.
auto cleaned =
firstAvailableText.split( QRegularExpression( "\\p{P}", QRegularExpression::UseUnicodePropertiesOption ) );
if ( cleaned.empty() )
if ( regString.trimmed().isEmpty() )
return;
firstAvailableText = cleaned.at( 0 );
#if ( QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 ) )
webview->findText( firstAvailableText,
QWebEnginePage::FindBackward,
[ & ]( const QWebEngineFindTextResult & result ) {
qInfo() << result.activeMatch() << "of" << result.numberOfMatches() << "matches";
QString script = QString(
"var context = document.querySelector(\"body\");\n"
"var instance = new Mark(context);\n"
"instance.mark(\"%1\",{\"accuracy\": \"exactly\"});" )
.arg( regString );
if ( result.numberOfMatches() == 0 ) {
ftsSearchPanel->statusLabel->setText( searchStatusMessageNoMatches() );
}
else {
ftsSearchPanel->statusLabel->setText(
searchStatusMessage( result.activeMatch(), result.numberOfMatches() ) );
}
ftsSearchPanel->show();
ftsSearchPanel->previous->setEnabled( result.numberOfMatches() > 1 );
ftsSearchPanel->next->setEnabled( result.numberOfMatches() > 1 );
ftsSearchIsOpened = true;
} );
#else
webview->findText( firstAvailableText, QWebEnginePage::FindBackward, [ this ]( bool res ) {
ftsSearchPanel->previous->setEnabled( res );
if ( !ftsSearchPanel->next->isEnabled() )
ftsSearchPanel->next->setEnabled( res );
} );
#endif
webview->page()->runJavaScript( script );
}
void ArticleView::setActiveDictIds( const ActiveDictIds & ad )

View file

@ -8,6 +8,7 @@
#include "langcoder.hh"
#include "language.hh"
#include "metadata.hh"
#include "utils.hh"
#include <QDir>
#include <QFileDialog>
@ -517,23 +518,6 @@ DictGroupsWidget::DictGroupsWidget( QWidget * parent ):
setUsesScrollButtons( true );
}
namespace {
QString escapeAmps( QString const & str )
{
QString result( str );
result.replace( "&", "&&" );
return result;
}
QString unescapeAmps( QString const & str )
{
QString result( str );
result.replace( "&&", "&" );
return result;
}
} // namespace
void DictGroupsWidget::populate( Config::Groups const & groups,
vector< sptr< Dictionary::Class > > const & allDicts_,
@ -546,7 +530,7 @@ void DictGroupsWidget::populate( Config::Groups const & groups,
for ( int x = 0; x < groups.size(); ++x ) {
const auto gr = new DictGroupWidget( this, *allDicts, groups[ x ] );
addTab( gr, escapeAmps( groups[ x ].name ) );
addTab( gr, Utils::escapeAmps( groups[ x ].name ) );
connect( gr, &DictGroupWidget::showDictionaryInfo, this, &DictGroupsWidget::showDictionaryInfo );
connect( gr->getModel(), &DictListModel::contentChanged, this, &DictGroupsWidget::tabDataChanged );
@ -569,7 +553,7 @@ Config::Groups DictGroupsWidget::makeGroups() const
for ( int x = 0; x < count(); ++x ) {
result.push_back( dynamic_cast< DictGroupWidget & >( *widget( x ) ).makeGroup() );
result.back().name = unescapeAmps( tabText( x ) );
result.back().name = Utils::unescapeAmps( tabText( x ) );
}
return result;
@ -638,7 +622,7 @@ int DictGroupsWidget::addNewGroup( QString const & name )
newGroup.id = nextId++;
const auto gr = new DictGroupWidget( this, *allDicts, newGroup );
const int idx = insertTab( currentIndex() + 1, gr, escapeAmps( name ) );
const int idx = insertTab( currentIndex() + 1, gr, Utils::escapeAmps( name ) );
connect( gr, &DictGroupWidget::showDictionaryInfo, this, &DictGroupsWidget::showDictionaryInfo );
connect( gr->getModel(), &DictListModel::contentChanged, this, &DictGroupsWidget::tabDataChanged );
@ -897,7 +881,7 @@ QString DictGroupsWidget::getCurrentGroupName() const
const int current = currentIndex();
if ( current >= 0 )
return unescapeAmps( tabText( current ) );
return Utils::unescapeAmps( tabText( current ) );
return QString();
}
@ -907,7 +891,7 @@ void DictGroupsWidget::renameCurrentGroup( QString const & name )
const int current = currentIndex();
if ( current >= 0 )
setTabText( current, escapeAmps( name ) );
setTabText( current, Utils::escapeAmps( name ) );
}
void DictGroupsWidget::removeCurrentGroup()

View file

@ -1814,8 +1814,7 @@ ArticleView * MainWindow::createNewTab( bool switchToIt, QString const & name )
int index = cfg.preferences.newTabsOpenAfterCurrentOne ? ui.tabWidget->currentIndex() + 1 : ui.tabWidget->count();
QString escaped = name;
escaped.replace( "&", "&&" );
QString escaped = Utils::escapeAmps( name );
ui.tabWidget->insertTab( index, view, escaped );
mruList.append( dynamic_cast< QWidget * >( view ) );
@ -1943,7 +1942,7 @@ void MainWindow::titleChanged( ArticleView * view, QString const & title )
else {
escaped = title;
}
escaped.replace( "&", "&&" );
escaped = Utils::escapeAmps( escaped );
int index = ui.tabWidget->indexOf( view );
if ( !escaped.isEmpty() )
@ -2856,7 +2855,7 @@ void MainWindow::toggleMainWindow( bool onlyShow )
void MainWindow::installHotKeys()
{
#if defined( Q_OS_LINUX )
#if defined( Q_OS_UNIX ) && !defined( Q_OS_MACOS )
if ( !qEnvironmentVariableIsEmpty( "GOLDENDICT_FORCE_WAYLAND" ) ) {
return;
}
@ -4218,7 +4217,7 @@ void MainWindow::showFullTextSearchDialog()
{
if ( !ftsDlg ) {
ftsDlg = new FTS::FullTextSearchDialog( this, cfg, dictionaries, groupInstances, ftsIndexing );
ftsDlg->setSearchText( translateLine->text() );
// ftsDlg->setSearchText( translateLine->text() );
addGlobalActionsToDialog( ftsDlg );
addGroupComboBoxActionsToDialog( ftsDlg, groupList );
@ -4264,11 +4263,7 @@ void MainWindow::showFTSIndexingName( QString const & name )
QString MainWindow::unescapeTabHeader( QString const & header )
{
// Reset table header to original headword
QString escaped = header;
escaped.replace( "&&", "&" );
return escaped;
return Utils::unescapeAmps( header );
}
void MainWindow::addCurrentTabToFavorites()

View file

@ -376,6 +376,7 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ):
ui.allowGls->setChecked( !p.fts.disabledTypes.contains( "GLS", Qt::CaseInsensitive ) );
ui.enablePosition->setChecked( p.fts.enablePosition );
ui.enablePosition->hide();
#ifndef MAKE_ZIM_SUPPORT
ui.allowZim->hide();
#endif

View file

@ -44,7 +44,7 @@ nav:
- Custom transliteration: topic_transliteration.md
- Customize Dictionary: custom_dictionary.md
- OCR Integration: howto/ocr.md
- Wayland/Linux: topic_wayland.md
- Wayland: topic_wayland.md
- Report Bugs & Feedbacks: feedbacks.md
- Contributor Guides:
- Developer: developer.md