feat: customize dictionary's fullindex option with metadata.toml (#1000)

* feat: customize dictionary's fullindex option with metadata.toml

* [autofix.ci] apply automated fixes

* feat: display fulltext status in the dictionary info dialog

* [autofix.ci] apply automated fixes

* doc: add document about how to enable dictionary's fullindex feature

* Update src/metadata.cc

Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>

* Update src/ui/dictinfo.ui

Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>

* Update website/mkdocs.yml

Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>

* Update website/docs/custom_dictionary.md

Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>

* Update website/docs/custom_dictionary.md

Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>

* Update website/docs/custom_dictionary.md

Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>

* Update website/docs/custom_dictionary.md

Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>

* Update website/docs/custom_dictionary.md

Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>

* Update website/docs/custom_dictionary.md

Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>

* add images

* feat: show fulltext search status in dictionary info dialog

* Update dictinfo.cc

* [autofix.ci] apply automated fixes

* ui: change layout

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: YiFang Xiao <yifang.xiao@noreply.com>
Co-authored-by: shenleban tongying <shenlebantongying@gmail.com>
This commit is contained in:
xiaoyifang 2023-07-26 10:03:20 +08:00 committed by GitHub
parent d3e6018401
commit 17cd445607
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 273 additions and 85 deletions

63
icons/fts_disabled.svg Normal file
View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="6.3500009mm"
height="6.3484006mm"
viewBox="0 0 6.3500009 6.3484008"
version="1.1"
id="svg384"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="fts_disabled.svg">
<metadata
id="metadata827">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
id="namedview386"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="0.71980919"
inkscape:cx="278.04436"
inkscape:cy="-81.638345"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs381" />
<g
inkscape:label="图层 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-77.276611,-133.65252)">
<path
id="path505"
style="fill:#ff5555;stroke:#000000;stroke-width:0.01366357"
d="m 82.917815,133.66249 -2.512215,2.25622 -1.94873,-2.14187 -0.722718,0.68025 c 1e-5,7e-5 1.5e-5,1.6e-4 2.6e-5,2.7e-4 8.47e-4,0.006 0.0013,0.0115 0.0019,0.0173 2.91e-4,0.003 5.56e-4,0.006 8.47e-4,0.008 l 1.942459,2.08806 -1.770682,1.59025 -0.623782,0.93407 0.396943,0.55282 2.70347,-2.31826 2.475782,2.66138 0.642703,-0.6672 -2.385907,-2.62239 2.4993,-2.14321 z"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.2 KiB

63
icons/fts_enabled.svg Normal file
View file

@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="6.349782mm"
height="6.3508086mm"
viewBox="0 0 6.3497821 6.3508086"
version="1.1"
id="svg5"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="fts_enabled.svg">
<metadata
id="metadata841">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="5.7584736"
inkscape:cx="14.46914"
inkscape:cy="-5.2492094"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs2" />
<g
inkscape:label="图层 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-95.083595,-117.75641)">
<path
id="path309"
style="fill:#008000;stroke:#000000;stroke-width:0.0159395"
d="m 100.9701,117.76957 -3.584216,4.90523 -1.792095,-1.99198 -0.501764,0.76135 c 0.0017,0.009 0.0029,0.0187 0.0038,0.0289 l 2.053789,2.62099 4.273476,-5.77669 -0.15756,-0.1743 z"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -92,5 +92,7 @@
<file>icons/old-downarrow.png</file> <file>icons/old-downarrow.png</file>
<file>icons/custom_trans.svg</file> <file>icons/custom_trans.svg</file>
<file>icons/splash.png</file> <file>icons/splash.png</file>
<file>icons/fts_disabled.svg</file>
<file>icons/fts_enabled.svg</file>
</qresource> </qresource>
</RCC> </RCC>

View file

@ -263,7 +263,7 @@ public:
void setFTSParameters( Config::FullTextSearch const & fts ) override void setFTSParameters( Config::FullTextSearch const & fts ) override
{ {
can_FTS = fts.enabled && !fts.disabledTypes.contains( "AARD", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "AARD", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -225,7 +225,7 @@ public:
void setFTSParameters( Config::FullTextSearch const & fts ) override void setFTSParameters( Config::FullTextSearch const & fts ) override
{ {
can_FTS = fts.enabled && !fts.disabledTypes.contains( "BGL", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "BGL", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -140,7 +140,7 @@ public:
void setFTSParameters( Config::FullTextSearch const & fts ) override void setFTSParameters( Config::FullTextSearch const & fts ) override
{ {
can_FTS = fts.enabled && !fts.disabledTypes.contains( "DICTD", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "DICTD", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }
}; };

View file

@ -312,6 +312,8 @@ protected:
QAtomicInt FTS_index_completed; QAtomicInt FTS_index_completed;
bool synonymSearchEnabled; bool synonymSearchEnabled;
string dictionaryName; string dictionaryName;
//default to true;
bool enable_FTS = true;
// Load user icon if it exist // Load user icon if it exist
// By default set icon to empty // By default set icon to empty
@ -369,6 +371,11 @@ public:
dictionaryName = _dictionaryName; dictionaryName = _dictionaryName;
} }
void setFtsEnable( bool _enable_FTS )
{
enable_FTS = _enable_FTS;
}
/// Returns all the available properties, like the author's name, copyright, /// Returns all the available properties, like the author's name, copyright,
/// description etc. All strings are in utf8. /// description etc. All strings are in utf8.
virtual map< Property, string > getProperties() noexcept = 0; virtual map< Property, string > getProperties() noexcept = 0;

View file

@ -240,7 +240,7 @@ public:
if ( ensureInitDone().size() ) if ( ensureInitDone().size() )
return; return;
can_FTS = fts.enabled && !fts.disabledTypes.contains( "DSL", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "DSL", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -155,7 +155,7 @@ public:
if ( ensureInitDone().size() ) if ( ensureInitDone().size() )
return; return;
can_FTS = fts.enabled && !fts.disabledTypes.contains( "EPWING", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "EPWING", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -408,7 +408,7 @@ public:
void setFTSParameters( Config::FullTextSearch const & fts ) override void setFTSParameters( Config::FullTextSearch const & fts ) override
{ {
can_FTS = fts.enabled && !fts.disabledTypes.contains( "GLS", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "GLS", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -177,6 +177,9 @@ void LoadDictionaries::handlePath( Config::Path const & path )
if ( dictMetaData && dictMetaData->name ) { if ( dictMetaData && dictMetaData->name ) {
dict->setName( dictMetaData->name.value() ); dict->setName( dictMetaData->name.value() );
} }
if ( dictMetaData && dictMetaData->fullindex ) {
dict->setFtsEnable( dictMetaData->fullindex.value() );
}
} }
} }

View file

@ -261,7 +261,7 @@ public:
if ( !ensureInitDone().empty() ) if ( !ensureInitDone().empty() )
return; return;
can_FTS = fts.enabled && !fts.disabledTypes.contains( "MDICT", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "MDICT", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -177,7 +177,7 @@ public:
void setFTSParameters( Config::FullTextSearch const & fts ) override void setFTSParameters( Config::FullTextSearch const & fts ) override
{ {
can_FTS = fts.enabled && !fts.disabledTypes.contains( "SDICT", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "SDICT", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -640,7 +640,7 @@ public:
void setFTSParameters( Config::FullTextSearch const & fts ) override void setFTSParameters( Config::FullTextSearch const & fts ) override
{ {
can_FTS = fts.enabled && !fts.disabledTypes.contains( "SLOB", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "SLOB", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -205,7 +205,7 @@ public:
void setFTSParameters( Config::FullTextSearch const & fts ) override void setFTSParameters( Config::FullTextSearch const & fts ) override
{ {
can_FTS = fts.enabled && !fts.disabledTypes.contains( "STARDICT", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "STARDICT", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -203,7 +203,7 @@ public:
void setFTSParameters( Config::FullTextSearch const & fts ) override void setFTSParameters( Config::FullTextSearch const & fts ) override
{ {
can_FTS = fts.enabled && !fts.disabledTypes.contains( "XDXF", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "XDXF", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -221,7 +221,7 @@ public:
void setFTSParameters( Config::FullTextSearch const & fts ) override void setFTSParameters( Config::FullTextSearch const & fts ) override
{ {
can_FTS = fts.enabled && !fts.disabledTypes.contains( "ZIM", Qt::CaseInsensitive ) can_FTS = enable_FTS && fts.enabled && !fts.disabledTypes.contains( "ZIM", Qt::CaseInsensitive )
&& ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize ); && ( fts.maxDictionarySize == 0 || getArticleCount() <= fts.maxDictionarySize );
} }

View file

@ -34,5 +34,19 @@ std::optional< Metadata::result > Metadata::load( std::string_view filepath )
} }
result.name = tbl[ "metadata" ][ "name" ].value_exact< std::string >(); result.name = tbl[ "metadata" ][ "name" ].value_exact< std::string >();
const auto fullindex = tbl[ "fts" ];
if ( fullindex.as_string() ) {
const auto value = fullindex.as_string()->get();
result.fullindex = value == "1" || value == "on" || value == "true";
}
else if ( fullindex.as_boolean() ) {
auto value = fullindex.as_boolean()->get();
result.fullindex = value;
}
else if ( fullindex.as_integer() ) {
const auto value = fullindex.as_integer()->get();
result.fullindex = value > 0;
}
return result; return result;
} }

View file

@ -12,6 +12,7 @@ struct result
{ {
std::optional< std::vector< std::string > > categories; std::optional< std::vector< std::string > > categories;
std::optional< std::string > name; std::optional< std::string > name;
std::optional< bool > fullindex;
}; };
[[nodiscard]] std::optional< Metadata::result > load( std::string_view filepath ); [[nodiscard]] std::optional< Metadata::result > load( std::string_view filepath );

View file

@ -20,6 +20,7 @@ void DictInfo::showInfo( sptr< Dictionary::Class > dict )
setWindowTitle( QString::fromUtf8( dict->getName().data(), dict->getName().size() ) ); setWindowTitle( QString::fromUtf8( dict->getName().data(), dict->getName().size() ) );
ui.dictionaryId->setText( QString::fromStdString( dict->getId() ) ); ui.dictionaryId->setText( QString::fromStdString( dict->getId() ) );
ui.enableFullindex->setText( dict->canFTS() ? tr( "Full-text search enabled" ) : tr( "Full-text search disabled" ) );
ui.dictionaryTotalArticles->setText( QString::number( dict->getArticleCount() ) ); ui.dictionaryTotalArticles->setText( QString::number( dict->getArticleCount() ) );
ui.dictionaryTotalWords->setText( QString::number( dict->getWordCount() ) ); ui.dictionaryTotalWords->setText( QString::number( dict->getWordCount() ) );
ui.dictionaryTranslatesFrom->setText( Language::localizedStringForId( dict->getLangFrom() ) ); ui.dictionaryTranslatesFrom->setText( Language::localizedStringForId( dict->getLangFrom() ) );

View file

@ -23,68 +23,6 @@
<string/> <string/>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QLabel" name="dictionaryTotalArticles">
<property name="text">
<string notr="true"/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Total words:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Translates from:</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="dictionaryTranslatesTo">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="dictionaryTotalWords">
<property name="text">
<string notr="true"/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="dictionaryTranslatesFrom">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Total articles:</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="openFolder">
<property name="text">
<string>Open folder</string>
</property>
</widget>
</item>
<item row="1" column="4"> <item row="1" column="4">
<widget class="QPushButton" name="editDictionary"> <widget class="QPushButton" name="editDictionary">
<property name="enabled"> <property name="enabled">
@ -95,17 +33,24 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="2"> <item row="1" column="3">
<widget class="QLabel" name="label_8"> <widget class="QLabel" name="dictionaryTranslatesTo">
<property name="text"> <property name="text">
<string>Translates to:</string> <string notr="true"/>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="3" column="0">
<widget class="QLabel" name="label_3"> <widget class="QLabel" name="enableFullindex">
<property name="text"> <property name="text">
<string>Index filename:</string> <string/>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QPushButton" name="openIndexFolder">
<property name="text">
<string>Open index folder</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -119,10 +64,72 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="4"> <item row="1" column="1">
<widget class="QPushButton" name="openIndexFolder"> <widget class="QLabel" name="dictionaryTotalWords">
<property name="text"> <property name="text">
<string>Open index folder</string> <string notr="true"/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Total articles:</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>Index filename:</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Total words:</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QPushButton" name="openFolder">
<property name="text">
<string>Open folder</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="dictionaryTotalArticles">
<property name="text">
<string notr="true"/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Translates from:</string>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="dictionaryTranslatesFrom">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Translates to:</string>
</property> </property>
</widget> </widget>
</item> </item>

View file

@ -1,7 +1,13 @@
You can customize the dictionary name by the metadata.toml which is also used in [metadata grouping](manage_groups.md) You can customize the dictionary by the metadata.toml which is also used in [metadata grouping](manage_groups.md)
## About the configuration of metadata.toml ## About the configuration of metadata.toml
the metadata.toml use toml format for configuration.
## Customize the name of the dictionary
```toml ```toml
[metadata] [metadata]
name = "New Name" name = "New Name"
@ -32,3 +38,24 @@ For example,
``` ```
## Disable full-text search for certain dictionary
```toml
fts=false
[metadata]
name="New Name"
```
this `fts` field's value can be on/off, 1/0 ,true/false etc.
```
fts=false
```
will disable the current dictionary's full-text search.
you can check the full-text search on each dictionary's info dialog.
![](img/dictionary-info-fullindex.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -42,7 +42,7 @@ nav:
- Custom Stylesheet & JavaScript: topic_userstyle.md - Custom Stylesheet & JavaScript: topic_userstyle.md
- Portable Mode: topic_portablemode.md - Portable Mode: topic_portablemode.md
- Custom transliteration: topic_transliteration.md - Custom transliteration: topic_transliteration.md
- Customize Dictionary Name: custom_dictionary_name.md - Customize Dictionary: custom_dictionary.md
- OCR Integration: howto/ocr.md - OCR Integration: howto/ocr.md
- Report Bugs & Feedbacks: feedbacks.md - Report Bugs & Feedbacks: feedbacks.md
- Contributor Guides: - Contributor Guides: