mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-12-18 07:24:07 +00:00
Merge branch 'staged' into dev
Some checks are pending
Release All / build_macOS (macos-13, 6.6.3) (push) Waiting to run
Release All / build_macOS (macos-13, 6.7.2) (push) Waiting to run
Release All / build_macOS (macos-14, 6.6.3) (push) Waiting to run
Release All / build_macOS (macos-14, 6.7.2) (push) Waiting to run
Release All / build_Windows (windows-2022, 6.6.3) (push) Waiting to run
Release All / build_Windows (windows-2022, 6.7.2) (push) Waiting to run
Release All / generate_other_staffs (push) Waiting to run
Release All / publish (push) Blocked by required conditions
Some checks are pending
Release All / build_macOS (macos-13, 6.6.3) (push) Waiting to run
Release All / build_macOS (macos-13, 6.7.2) (push) Waiting to run
Release All / build_macOS (macos-14, 6.6.3) (push) Waiting to run
Release All / build_macOS (macos-14, 6.7.2) (push) Waiting to run
Release All / build_Windows (windows-2022, 6.6.3) (push) Waiting to run
Release All / build_Windows (windows-2022, 6.7.2) (push) Waiting to run
Release All / generate_other_staffs (push) Waiting to run
Release All / publish (push) Blocked by required conditions
This commit is contained in:
commit
7f62fc87c4
4
.github/workflows/PR-check-cmake.yml
vendored
4
.github/workflows/PR-check-cmake.yml
vendored
|
@ -56,7 +56,7 @@ jobs:
|
|||
brew update
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install \
|
||||
brew install --force --overwrite \
|
||||
ninja \
|
||||
opencc \
|
||||
ffmpeg \
|
||||
|
@ -68,7 +68,7 @@ jobs:
|
|||
hunspell \
|
||||
xapian \
|
||||
libzim \
|
||||
qt
|
||||
qt || true
|
||||
- name: Install eb
|
||||
run: |
|
||||
wget https://github.com/mistydemeo/eb/releases/download/v4.4.3/eb-4.4.3.tar.bz2
|
||||
|
|
4
.github/workflows/Release-all.yml
vendored
4
.github/workflows/Release-all.yml
vendored
|
@ -31,7 +31,7 @@ jobs:
|
|||
brew update
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
brew install \
|
||||
brew install --force --overwrite \
|
||||
bzip2 \
|
||||
create-dmg \
|
||||
hunspell \
|
||||
|
@ -42,7 +42,7 @@ jobs:
|
|||
lzip \
|
||||
ninja \
|
||||
opencc \
|
||||
xapian
|
||||
xapian || true
|
||||
- name: Install eb
|
||||
run: |
|
||||
git clone https://github.com/xiaoyifang/eb.git
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 8.1 KiB |
32
src/common/dictionary_icon_name.cc
Normal file
32
src/common/dictionary_icon_name.cc
Normal file
|
@ -0,0 +1,32 @@
|
|||
#include "dictionary_icon_name.hh"
|
||||
#include <QMutexLocker>
|
||||
|
||||
|
||||
QString Icons::DictionaryIconName::getIconName( const QString & dictionaryName )
|
||||
{
|
||||
if ( dictionaryName.isEmpty() ) {
|
||||
return {};
|
||||
}
|
||||
QMutexLocker _( &_mutex );
|
||||
|
||||
auto it = _dictionaryIconNames.contains( dictionaryName );
|
||||
if ( it ) {
|
||||
return _dictionaryIconNames.value( dictionaryName );
|
||||
}
|
||||
//get the first character of the dictionary name
|
||||
QString name = dictionaryName.at( 0 ).toUpper();
|
||||
auto it1 = _iconDictionaryNames.contains( name );
|
||||
std::vector< QString > vector = {};
|
||||
if ( it1 ) {
|
||||
vector = _iconDictionaryNames.value( name );
|
||||
vector.emplace_back( dictionaryName );
|
||||
}
|
||||
else {
|
||||
vector.emplace_back( dictionaryName );
|
||||
_iconDictionaryNames.insert( name, vector );
|
||||
}
|
||||
|
||||
name = name + QString::number( vector.size() );
|
||||
_dictionaryIconNames.insert( dictionaryName, name );
|
||||
return name;
|
||||
}
|
24
src/common/dictionary_icon_name.hh
Normal file
24
src/common/dictionary_icon_name.hh
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <QMap>
|
||||
#include <vector>
|
||||
#include <mutex>
|
||||
#include <QString>
|
||||
#include <QMutex>
|
||||
|
||||
namespace Icons {
|
||||
//use dictionary name's (first character + the order number) to represent the dictionary name in the icon image.
|
||||
class DictionaryIconName
|
||||
{
|
||||
//map icon name to dictionary names;
|
||||
QMap< QString, std::vector< QString > > _iconDictionaryNames;
|
||||
//map dictionary name to icon name;
|
||||
QMap< QString, QString > _dictionaryIconNames;
|
||||
|
||||
QMutex _mutex;
|
||||
|
||||
public:
|
||||
QString getIconName( const QString & dictionaryName );
|
||||
};
|
||||
} // namespace Icons
|
|
@ -155,8 +155,7 @@ std::u32string applyWhitespaceAndPunctOnly( std::u32string const & in )
|
|||
|
||||
bool isWhitespace( char32_t ch )
|
||||
{
|
||||
//invisible character should be treated as whitespace as well.
|
||||
return QChar::isSpace( ch ) || !QChar::isPrint( ch );
|
||||
return QChar::isSpace( ch );
|
||||
}
|
||||
|
||||
bool isWhitespaceOrPunct( char32_t ch )
|
||||
|
|
|
@ -38,4 +38,22 @@ bool GlobalBroadcaster::existedInWhitelist( QString url ) const
|
|||
{
|
||||
return whitelist.contains( url );
|
||||
}
|
||||
|
||||
|
||||
QString GlobalBroadcaster::getAbbrName( QString const & text )
|
||||
{
|
||||
if ( text.isEmpty() ) {
|
||||
return {};
|
||||
}
|
||||
//remove whitespace,number,mark,puncuation,symbol
|
||||
QString simplified = text;
|
||||
simplified.remove(
|
||||
QRegularExpression( R"([\p{Z}\p{N}\p{M}\p{P}\p{S}])", QRegularExpression::UseUnicodePropertiesOption ) );
|
||||
|
||||
if ( simplified.isEmpty() ) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return _icon_names.getIconName( simplified );
|
||||
}
|
||||
// namespace global
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "config.hh"
|
||||
#include "pronounceengine.hh"
|
||||
#include <QCache>
|
||||
#include "dictionary_icon_name.hh"
|
||||
|
||||
struct ActiveDictIds
|
||||
{
|
||||
|
@ -25,6 +26,7 @@ class GlobalBroadcaster: public QObject
|
|||
|
||||
Config::Preferences * preference;
|
||||
QSet< QString > whitelist;
|
||||
Icons::DictionaryIconName _icon_names;
|
||||
|
||||
public:
|
||||
void setPreference( Config::Preferences * _pre );
|
||||
|
@ -40,6 +42,7 @@ public:
|
|||
QMap< QString, QSet< QString > > folderFavoritesMap;
|
||||
QMap< unsigned, QString > groupFolderMap;
|
||||
PronounceEngine pronounce_engine;
|
||||
QString getAbbrName( QString const & text );
|
||||
signals:
|
||||
void dictionaryChanges( ActiveDictIds ad );
|
||||
void dictionaryClear( ActiveDictIds ad );
|
||||
|
|
|
@ -71,8 +71,8 @@ const static QRegularExpression accentMark( R"(\p{M})", QRegularExpression::UseU
|
|||
//contain unicode space mark,invisible, and punctuation
|
||||
const static QRegularExpression markPuncSpace( R"([\p{M}\p{Z}\p{C}\p{P}])",
|
||||
QRegularExpression::UseUnicodePropertiesOption );
|
||||
//contain unicode space and mark.invisible
|
||||
const static QRegularExpression markSpace( R"([\p{M}\p{Z}\p{C}])", QRegularExpression::UseUnicodePropertiesOption );
|
||||
//contain unicode space and mark.
|
||||
const static QRegularExpression markSpace( R"([\p{M}\p{Z}])", QRegularExpression::UseUnicodePropertiesOption );
|
||||
|
||||
const static QRegularExpression whiteSpace( "\\s+" );
|
||||
|
||||
|
|
|
@ -39,6 +39,19 @@ inline QString rstrip( const QString & str )
|
|||
return {};
|
||||
}
|
||||
|
||||
inline uint32_t leadingSpaceCount( const QString & str )
|
||||
{
|
||||
for ( int i = 0; i < str.size(); i++ ) {
|
||||
if ( str.at( i ).isSpace() ) {
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string c_string( const QString & str );
|
||||
bool endsWithIgnoreCase( QByteArrayView str, QByteArrayView extension );
|
||||
/**
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <QRegularExpression>
|
||||
#include "utils.hh"
|
||||
#include "zipfile.hh"
|
||||
#include <array>
|
||||
|
||||
namespace Dictionary {
|
||||
|
||||
|
@ -291,7 +292,7 @@ bool Class::loadIconFromFile( QString const & _filename, bool isFullName )
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Class::loadIconFromText( QString iconUrl, QString const & text )
|
||||
bool Class::loadIconFromText( const QString & iconUrl, QString const & text )
|
||||
{
|
||||
if ( text.isEmpty() ) {
|
||||
return false;
|
||||
|
@ -308,7 +309,7 @@ bool Class::loadIconFromText( QString iconUrl, QString const & text )
|
|||
painter.setCompositionMode( QPainter::CompositionMode_SourceAtop );
|
||||
|
||||
QFont font = painter.font();
|
||||
//the text should be a little smaller than the icon
|
||||
//the orderNum should be a little smaller than the icon
|
||||
font.setPixelSize( iconSize * 0.6 );
|
||||
font.setWeight( QFont::Bold );
|
||||
painter.setFont( font );
|
||||
|
@ -318,8 +319,21 @@ bool Class::loadIconFromText( QString iconUrl, QString const & text )
|
|||
//select a single char.
|
||||
auto abbrName = getAbbrName( text );
|
||||
|
||||
painter.setPen( QColor( 4, 57, 108, 200 ) );
|
||||
painter.drawText( rectangle, Qt::AlignCenter, abbrName );
|
||||
painter.setPen( intToFixedColor( qHash( abbrName ) ) );
|
||||
|
||||
// Draw first character
|
||||
painter.drawText( rectangle, Qt::AlignCenter, abbrName.at( 0 ) );
|
||||
|
||||
//the orderNum should be a little smaller than the icon
|
||||
font.setPixelSize( iconSize * 0.4 );
|
||||
QFontMetrics fm1( font );
|
||||
const QString & orderNum = abbrName.mid( 1 );
|
||||
int orderNumberWidth = fm1.horizontalAdvance( orderNum );
|
||||
|
||||
painter.setFont( font );
|
||||
painter.drawText( rectangle.x() + rectangle.width() - orderNumberWidth * 1.2,
|
||||
rectangle.y() + rectangle.height(),
|
||||
orderNum );
|
||||
|
||||
painter.end();
|
||||
|
||||
|
@ -330,35 +344,30 @@ bool Class::loadIconFromText( QString iconUrl, QString const & text )
|
|||
return false;
|
||||
}
|
||||
|
||||
QColor Class::intToFixedColor( int index )
|
||||
{
|
||||
// Predefined list of colors
|
||||
static const std::array colors = {
|
||||
QColor( 255, 0, 0, 200 ), // Red
|
||||
QColor( 4, 57, 108, 200 ), //Custom
|
||||
QColor( 0, 255, 0, 200 ), // Green
|
||||
QColor( 0, 0, 255, 200 ), // Blue
|
||||
QColor( 255, 255, 0, 200 ), // Yellow
|
||||
QColor( 0, 255, 255, 200 ), // Cyan
|
||||
QColor( 255, 0, 255, 200 ), // Magenta
|
||||
QColor( 192, 192, 192, 200 ), // Gray
|
||||
QColor( 255, 165, 0, 200 ), // Orange
|
||||
QColor( 128, 0, 128, 200 ), // Violet
|
||||
QColor( 128, 128, 0, 200 ) // Olive
|
||||
};
|
||||
|
||||
// Use modulo operation to ensure index is within the range of the color list
|
||||
return colors[ index % colors.size() ];
|
||||
}
|
||||
|
||||
QString Class::getAbbrName( QString const & text )
|
||||
{
|
||||
if ( text.isEmpty() ) {
|
||||
return {};
|
||||
}
|
||||
//remove whitespace,number,mark,puncuation,symbol
|
||||
QString simplified = text;
|
||||
simplified.remove(
|
||||
QRegularExpression( R"([\p{Z}\p{N}\p{M}\p{P}\p{S}])", QRegularExpression::UseUnicodePropertiesOption ) );
|
||||
|
||||
if ( simplified.isEmpty() ) {
|
||||
return {};
|
||||
}
|
||||
int index = qHash( simplified ) % simplified.size();
|
||||
|
||||
QString abbrName;
|
||||
if ( !Utils::isCJKChar( simplified.at( index ).unicode() ) ) {
|
||||
// take two chars.
|
||||
abbrName = simplified.mid( index, 2 );
|
||||
if ( abbrName.size() == 1 ) {
|
||||
//make up two characters.
|
||||
abbrName = abbrName + simplified.at( 0 );
|
||||
}
|
||||
}
|
||||
else {
|
||||
abbrName = simplified.mid( index, 1 );
|
||||
}
|
||||
|
||||
return abbrName;
|
||||
return GlobalBroadcaster::instance()->getAbbrName( text );
|
||||
}
|
||||
|
||||
void Class::isolateCSS( QString & css, QString const & wrapperSelector )
|
||||
|
|
|
@ -318,10 +318,10 @@ protected:
|
|||
// Load icon from filename directly if isFullName == true
|
||||
// else treat filename as name without extension
|
||||
bool loadIconFromFile( QString const & filename, bool isFullName = false );
|
||||
bool loadIconFromText( QString iconUrl, QString const & text );
|
||||
|
||||
QString getAbbrName( QString const & text );
|
||||
bool loadIconFromText( const QString & iconUrl, QString const & text );
|
||||
|
||||
static QString getAbbrName( QString const & text );
|
||||
static QColor intToFixedColor( int index );
|
||||
/// Make css content usable only for articles from this dictionary
|
||||
void isolateCSS( QString & css, QString const & wrapperSelector = QString() );
|
||||
|
||||
|
|
|
@ -592,12 +592,49 @@ public:
|
|||
cancel();
|
||||
} );
|
||||
|
||||
connect( this, &DictServerArticleRequest::finishedArticle, this, [ this ]( QString articleText ) {
|
||||
connect( this, &DictServerArticleRequest::finishedArticle, this, [ this ]( QString _articleText ) {
|
||||
if ( Utils::AtomicInt::loadAcquire( isCancelled ) ) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
//modify the _articleText,remove extra lines[start with 15X etc.]
|
||||
QList< QString > lines = _articleText.split( "\n", Qt::SkipEmptyParts );
|
||||
|
||||
QString resultStr;
|
||||
|
||||
// process the line
|
||||
static QRegularExpression leadingRespCode( "^\\d{3} " );
|
||||
uint32_t leadingSpaceCount = 0;
|
||||
uint32_t firstLeadingSpaceCount = 0;
|
||||
for ( const QString & line : lines ) {
|
||||
//ignore 15X lines
|
||||
if ( leadingRespCode.match( line ).hasMatch() ) {
|
||||
continue;
|
||||
}
|
||||
// ignore dot(.),the end line character
|
||||
if ( line.trimmed() == "." ) {
|
||||
break;
|
||||
}
|
||||
|
||||
auto lsc = Utils::leadingSpaceCount( line );
|
||||
|
||||
if ( firstLeadingSpaceCount == 0 && lsc > firstLeadingSpaceCount ) {
|
||||
firstLeadingSpaceCount = lsc;
|
||||
}
|
||||
|
||||
if ( lsc >= leadingSpaceCount && lsc > firstLeadingSpaceCount ) {
|
||||
//extra space
|
||||
resultStr.append( " " );
|
||||
resultStr.append( line.trimmed() );
|
||||
}
|
||||
else {
|
||||
resultStr.append( "\n" );
|
||||
resultStr.append( line );
|
||||
}
|
||||
leadingSpaceCount = lsc;
|
||||
}
|
||||
|
||||
static QRegularExpression phonetic( R"(\\([^\\]+)\\)",
|
||||
QRegularExpression::CaseInsensitiveOption ); // phonetics: \stuff\ ...
|
||||
static QRegularExpression divs_inside_phonetic( "</div([^>]*)><div([^>]*)>",
|
||||
|
@ -610,26 +647,26 @@ public:
|
|||
|
||||
string articleStr;
|
||||
if ( contentInHtml ) {
|
||||
articleStr = articleText.toUtf8().data();
|
||||
articleStr = resultStr.toUtf8().data();
|
||||
}
|
||||
else {
|
||||
articleStr = Html::preformat( articleText.toUtf8().data() );
|
||||
articleStr = Html::preformat( resultStr.toUtf8().data() );
|
||||
}
|
||||
|
||||
articleText = QString::fromUtf8( articleStr.c_str(), articleStr.size() );
|
||||
_articleText = QString::fromUtf8( articleStr.c_str(), articleStr.size() );
|
||||
int pos;
|
||||
if ( !contentInHtml ) {
|
||||
articleText = articleText.replace( refs, R"(<a href="gdlookup://localhost/\1">\1</a>)" );
|
||||
_articleText = _articleText.replace( refs, R"(<a href="gdlookup://localhost/\1">\1</a>)" );
|
||||
|
||||
pos = 0;
|
||||
QString articleNewText;
|
||||
|
||||
// Handle phonetics
|
||||
|
||||
QRegularExpressionMatchIterator it = phonetic.globalMatch( articleText );
|
||||
QRegularExpressionMatchIterator it = phonetic.globalMatch( _articleText );
|
||||
while ( it.hasNext() ) {
|
||||
QRegularExpressionMatch match = it.next();
|
||||
articleNewText += articleText.mid( pos, match.capturedStart() - pos );
|
||||
articleNewText += _articleText.mid( pos, match.capturedStart() - pos );
|
||||
pos = match.capturedEnd();
|
||||
|
||||
QString phonetic_text = match.captured( 1 );
|
||||
|
@ -638,18 +675,18 @@ public:
|
|||
articleNewText += R"(<span class="dictd_phonetic">)" + phonetic_text + "</span>";
|
||||
}
|
||||
if ( pos ) {
|
||||
articleNewText += articleText.mid( pos );
|
||||
articleText = articleNewText;
|
||||
articleNewText += _articleText.mid( pos );
|
||||
_articleText = articleNewText;
|
||||
articleNewText.clear();
|
||||
}
|
||||
|
||||
// Handle links
|
||||
|
||||
pos = 0;
|
||||
it = links.globalMatch( articleText );
|
||||
it = links.globalMatch( _articleText );
|
||||
while ( it.hasNext() ) {
|
||||
QRegularExpressionMatch match = it.next();
|
||||
articleNewText += articleText.mid( pos, match.capturedStart() - pos );
|
||||
articleNewText += _articleText.mid( pos, match.capturedStart() - pos );
|
||||
pos = match.capturedEnd();
|
||||
|
||||
QString link = match.captured( 1 );
|
||||
|
@ -663,13 +700,13 @@ public:
|
|||
articleNewText += newLink;
|
||||
}
|
||||
if ( pos ) {
|
||||
articleNewText += articleText.mid( pos );
|
||||
articleText = articleNewText;
|
||||
articleNewText += _articleText.mid( pos );
|
||||
_articleText = articleNewText;
|
||||
articleNewText.clear();
|
||||
}
|
||||
}
|
||||
|
||||
articleData += string( "<div class=\"dictd_article\">" ) + articleText.toUtf8().data() + "<br></div>";
|
||||
articleData += string( "<div class=\"dictd_article\">" ) + _articleText.toUtf8().data() + "<br></div>";
|
||||
|
||||
|
||||
if ( !articleData.empty() ) {
|
||||
|
|
|
@ -877,8 +877,7 @@ QString & MdxDictionary::filterResource( QString & article )
|
|||
void MdxDictionary::replaceLinks( QString & id, QString & article )
|
||||
{
|
||||
QString articleNewText;
|
||||
qsizetype linkPos = 0;
|
||||
|
||||
int linkPos = 0;
|
||||
QRegularExpressionMatchIterator it = RX::Mdx::allLinksRe.globalMatch( article );
|
||||
while ( it.hasNext() ) {
|
||||
QRegularExpressionMatch allLinksMatch = it.next();
|
||||
|
@ -954,14 +953,13 @@ void MdxDictionary::replaceLinks( QString & id, QString & article )
|
|||
articleNewText += linkTxt;
|
||||
match = RX::Mdx::closeScriptTagRe.match( article, linkPos );
|
||||
if ( match.hasMatch() ) {
|
||||
articleNewText += QString( QStringLiteral( "gdOnReady(()=>{%1});</script>" ) )
|
||||
.arg( article.mid( linkPos, match.capturedStart() - linkPos ) );
|
||||
articleNewText += article.mid( linkPos, match.capturedEnd() - linkPos );
|
||||
linkPos = match.capturedEnd();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
//audio ,script,video ,html5 tags fall here.
|
||||
//audio ,video ,html5 tags fall here.
|
||||
match = RX::Mdx::srcRe.match( linkTxt );
|
||||
if ( match.hasMatch() ) {
|
||||
QString newText;
|
||||
|
@ -973,15 +971,9 @@ void MdxDictionary::replaceLinks( QString & id, QString & article )
|
|||
else {
|
||||
scheme = "bres://";
|
||||
}
|
||||
|
||||
newText =
|
||||
match.captured( 1 ) + match.captured( 2 ) + scheme + id + "/" + match.captured( 3 ) + match.captured( 2 );
|
||||
|
||||
//add defer to script tag
|
||||
if ( linkType.compare( "script" ) == 0 ) {
|
||||
newText = newText + " defer ";
|
||||
}
|
||||
|
||||
newLink = linkTxt.replace( match.capturedStart(), match.capturedLength(), newText );
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -275,14 +275,18 @@ quint32 LangCoder::guessId( const QString & lang )
|
|||
|
||||
std::pair< quint32, quint32 > LangCoder::findLangIdPairFromName( QString const & name )
|
||||
{
|
||||
static QRegularExpression reg( "(?=([a-z]{2,3})-([a-z]{2,3}))", QRegularExpression::CaseInsensitiveOption );
|
||||
static QRegularExpression reg( "(^|[^a-z])((?<lang1>[a-z]{2,3})-(?<lang2>[a-z]{2,3}))($|[^a-z])",
|
||||
QRegularExpression::CaseInsensitiveOption );
|
||||
|
||||
auto matches = reg.globalMatch( name );
|
||||
while ( matches.hasNext() ) {
|
||||
auto m = matches.next();
|
||||
if ( matches.hasNext() ) {
|
||||
continue; // We use only the last match, skip previous ones
|
||||
}
|
||||
|
||||
auto fromId = guessId( m.captured( 1 ).toLower() );
|
||||
auto toId = guessId( m.captured( 2 ).toLower() );
|
||||
auto fromId = guessId( m.captured( "lang1" ).toLower() );
|
||||
auto toId = guessId( m.captured( "lang2" ).toLower() );
|
||||
|
||||
if ( code2Exists( intToCode2( fromId ) ) && code2Exists( intToCode2( toId ) ) ) {
|
||||
return { fromId, toId };
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
function gdOnReady(func) {
|
||||
if (document.readyState !== "loading") {
|
||||
func();
|
||||
} else {
|
||||
document.addEventListener("DOMContentLoaded", func);
|
||||
}
|
||||
}
|
||||
|
||||
function gdMakeArticleActive(newId, noEvent) {
|
||||
const gdCurrentArticle =
|
||||
document.querySelector(".gdactivearticle").attributes.id;
|
||||
|
|
|
@ -4025,7 +4025,7 @@ void MainWindow::on_importFavorites_triggered()
|
|||
QString fileName = QFileDialog::getOpenFileName( this,
|
||||
tr( "Import Favorites from file" ),
|
||||
importPath,
|
||||
tr( "XML files (*.xml);;Txt files (*.txt);;All files (*.*)" ) );
|
||||
tr( "Text and XML files (*.txt *.xml);;All files (*.*)" ) );
|
||||
if ( fileName.size() == 0 ) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -10,9 +10,9 @@ Additionally, multiple strategies of automatic grouping are provided:
|
|||
|
||||
## Auto groups by dictionary language
|
||||
|
||||
For formats like DSL, which has embedded language from / to metadata, GoldenDict will use the dictionary's built-in metadata.
|
||||
For formats like DSL, which has embedded language from / to metadata, GD will use the dictionary's built-in metadata.
|
||||
|
||||
For other formats, GoldenDict will try to extract languages from the dictionary's name or its file name by finding `{id}-{id}` pair. The `{id}` is 2 or 3 letters ISO 639 codes. For example, if a dictionary named `some name en-zh`, it will be automatically grouped into `en-zh`.
|
||||
For other formats, GD will try finding the last `{id}-{id}` pair delimited by non-alphabets in dictionary name or main file name to extract languages. The `{id}` is 2 or 3 letters ISO 639 codes. For example, if a dictionary named `some name en-zh`, it will be automatically grouped into `en-zh`.
|
||||
|
||||
Groups created in this method also include a context menu when right-click the group name, in which you can do additional dictionaries grouping by source or target language and combine dictionaries in more large groups.
|
||||
|
||||
|
|
Loading…
Reference in a new issue