diff --git a/searx/data/engine_traits.json b/searx/data/engine_traits.json
index e5f85bf38..c97134f8b 100644
--- a/searx/data/engine_traits.json
+++ b/searx/data/engine_traits.json
@@ -5121,7 +5121,116 @@
     "all_locale": null,
     "custom": {},
     "data_type": "supported_languages",
-    "languages": {},
+    "languages": {
+      "af": "af",
+      "ak": "tw",
+      "am": "am",
+      "ar": "ar",
+      "as": "as",
+      "az": "az",
+      "be": "be",
+      "bg": "bg",
+      "bn": "bn",
+      "bo": "bo",
+      "bs": "bs",
+      "ca": "ca",
+      "chr": "chr",
+      "ckb": "ckb",
+      "cs": "cs",
+      "da": "da",
+      "de": "de",
+      "dsb": "dsb",
+      "el": "el",
+      "en": "en",
+      "es": "es",
+      "et": "et",
+      "fa": "fa",
+      "fi": "fi",
+      "fil": "tl",
+      "fo": "fo",
+      "fr": "fr",
+      "fur": "fur",
+      "fy": "fy",
+      "gl": "gl",
+      "gsw": "als",
+      "gu": "gu",
+      "gv": "gv",
+      "haw": "haw",
+      "he": "he",
+      "hi": "hi",
+      "hsb": "hsb",
+      "hu": "hu",
+      "hy": "hy",
+      "id": "id",
+      "is": "is",
+      "it": "it",
+      "ja": "ja",
+      "jv": "jv",
+      "ka": "ka",
+      "km": "km",
+      "kn": "kn",
+      "ko": "ko",
+      "ks": "ks",
+      "ksh": "ksh",
+      "kw": "kw",
+      "lb": "lb",
+      "lg": "lg",
+      "ln": "ln",
+      "lo": "lo",
+      "lt": "lt",
+      "lv": "lv",
+      "mai": "mai",
+      "mk": "mk",
+      "ml": "ml",
+      "mn": "mn",
+      "mr": "mr",
+      "ms": "ms",
+      "mt": "mt",
+      "nds": "nds-nl",
+      "ne": "ne",
+      "no": "no",
+      "om": "om",
+      "or": "or",
+      "os": "os",
+      "pa": "pa",
+      "pl": "pl",
+      "ps": "ps",
+      "pt": "pt",
+      "qu": "qu",
+      "rm": "rm",
+      "ro": "ro",
+      "ru": "ru",
+      "rw": "rw",
+      "sa": "sa",
+      "sah": "sah",
+      "sd": "sd",
+      "se": "se",
+      "shi": "shi",
+      "si": "si",
+      "sk": "sk",
+      "sl": "sl",
+      "smn": "smn",
+      "so": "so",
+      "sq": "sq",
+      "sr": "sr",
+      "ta": "ta",
+      "te": "te",
+      "th": "th",
+      "tk": "tk",
+      "to": "to",
+      "tr": "tr",
+      "ug": "ug",
+      "uk": "uk",
+      "ur": "ur",
+      "uz": "uz",
+      "vi": "vi",
+      "wo": "wo",
+      "xh": "xh",
+      "yi": "yi",
+      "zh": "zh",
+      "zh_Hans": "zh",
+      "zh_Hant": "zh-classical"
+    },
     "regions": {},
     "supported_languages": {
       "ab": {
@@ -6402,7 +6511,116 @@
     "all_locale": null,
     "custom": {},
     "data_type": "supported_languages",
-    "languages": {},
+    "languages": {
+      "af": "af",
+      "ak": "tw",
+      "am": "am",
+      "ar": "ar",
+      "as": "as",
+      "az": "az",
+      "be": "be",
+      "bg": "bg",
+      "bn": "bn",
+      "bo": "bo",
+      "bs": "bs",
+      "ca": "ca",
+      "chr": "chr",
+      "ckb": "ckb",
+      "cs": "cs",
+      "da": "da",
+      "de": "de",
+      "dsb": "dsb",
+      "el": "el",
+      "en": "en",
+      "es": "es",
+      "et": "et",
+      "fa": "fa",
+      "fi": "fi",
+      "fil": "tl",
+      "fo": "fo",
+      "fr": "fr",
+      "fur": "fur",
+      "fy": "fy",
+      "gl": "gl",
+      "gsw": "als",
+      "gu": "gu",
+      "gv": "gv",
+      "haw": "haw",
+      "he": "he",
+      "hi": "hi",
+      "hsb": "hsb",
+      "hu": "hu",
+      "hy": "hy",
+      "id": "id",
+      "is": "is",
+      "it": "it",
+      "ja": "ja",
+      "jv": "jv",
+      "ka": "ka",
+      "km": "km",
+      "kn": "kn",
+      "ko": "ko",
+      "ks": "ks",
+      "ksh": "ksh",
+      "kw": "kw",
+      "lb": "lb",
+      "lg": "lg",
+      "ln": "ln",
+      "lo": "lo",
+      "lt": "lt",
+      "lv": "lv",
+      "mai": "mai",
+      "mk": "mk",
+      "ml": "ml",
+      "mn": "mn",
+      "mr": "mr",
+      "ms": "ms",
+      "mt": "mt",
+      "nds": "nds-nl",
+      "ne": "ne",
+      "no": "no",
+      "om": "om",
+      "or": "or",
+      "os": "os",
+      "pa": "pa",
+      "pl": "pl",
+      "ps": "ps",
+      "pt": "pt",
+      "qu": "qu",
+      "rm": "rm",
+      "ro": "ro",
+      "ru": "ru",
+      "rw": "rw",
+      "sa": "sa",
+      "sah": "sah",
+      "sd": "sd",
+      "se": "se",
+      "shi": "shi",
+      "si": "si",
+      "sk": "sk",
+      "sl": "sl",
+      "smn": "smn",
+      "so": "so",
+      "sq": "sq",
+      "sr": "sr",
+      "ta": "ta",
+      "te": "te",
+      "th": "th",
+      "tk": "tk",
+      "to": "to",
+      "tr": "tr",
+      "ug": "ug",
+      "uk": "uk",
+      "ur": "ur",
+      "uz": "uz",
+      "vi": "vi",
+      "wo": "wo",
+      "xh": "xh",
+      "yi": "yi",
+      "zh": "zh",
+      "zh_Hans": "zh",
+      "zh_Hant": "zh-classical"
+    },
     "regions": {},
     "supported_languages": {
       "ab": {
diff --git a/searx/engines/wikidata.py b/searx/engines/wikidata.py
index 8d3b0839a..a38600978 100644
--- a/searx/engines/wikidata.py
+++ b/searx/engines/wikidata.py
@@ -16,6 +16,7 @@ from searx.network import post, get
 from searx.utils import match_language, searx_useragent, get_string_replaces_function
 from searx.external_urls import get_external_url, get_earth_coordinates_url, area_to_osm_zoom
 from searx.engines.wikipedia import (  # pylint: disable=unused-import
+    fetch_traits,
     _fetch_supported_languages,
     supported_languages_url,
 )
diff --git a/searx/engines/wikipedia.py b/searx/engines/wikipedia.py
index ca841e8b3..4d5474e17 100644
--- a/searx/engines/wikipedia.py
+++ b/searx/engines/wikipedia.py
@@ -5,9 +5,12 @@
 
 from urllib.parse import quote
 from json import loads
-from lxml.html import fromstring
+from lxml import html
 from searx.utils import match_language, searx_useragent
-from searx.network import raise_for_httperror
+from searx import network
+from searx.enginelib.traits import EngineTraits
+
+engine_traits: EngineTraits
 
 # about
 about = {
@@ -68,7 +71,7 @@ def response(resp):
             ):
                 return []
 
-    raise_for_httperror(resp)
+    network.raise_for_httperror(resp)
 
     results = []
     api_result = loads(resp.text)
@@ -98,7 +101,7 @@ def response(resp):
 # get supported languages from their site
 def _fetch_supported_languages(resp):
     supported_languages = {}
-    dom = fromstring(resp.text)
+    dom = html.fromstring(resp.text)
     tables = dom.xpath('//table[contains(@class,"sortable")]')
     for table in tables:
         # exclude header row
@@ -114,3 +117,166 @@ def _fetch_supported_languages(resp):
                 supported_languages[code] = {"name": name, "english_name": english_name}
 
     return supported_languages
+
+
+# Nonstandard language codes
+#
+# These Wikipedias use language codes that do not conform to the ISO 639
+# standard (which is how wiki subdomains are chosen nowadays).
+
+lang_map = {
+    'be-tarask': 'bel',
+    'ak': 'aka',
+    'als': 'gsw',
+    'bat-smg': 'sgs',
+    'cbk-zam': 'cbk',
+    'fiu-vro': 'vro',
+    'map-bms': 'map',
+    'nrm': 'nrf',
+    'roa-rup': 'rup',
+    'nds-nl': 'nds',
+    #'roa-tara: – invented code used for the Tarantino Wikipedia (again, roa is the standard code for the large family of Romance languages that the Tarantino dialect falls within)
+    #'simple: – invented code used for the Simple English Wikipedia (not the official IETF code en-simple)
+    'zh-classical': 'zh_Hant',
+    'zh-min-nan': 'nan',
+    'zh-yue': 'yue',
+    'an': 'arg',
+}
+
+unknown_langs = [
+    'ab',  # Abkhazian
+    'alt',  # Southern Altai
+    'an',  # Aragonese
+    'ang',  # Anglo-Saxon
+    'arc',  # Aramaic
+    'ary',  # Moroccan Arabic
+    'av',  # Avar
+    'ba',  # Bashkir
+    'be-tarask',
+    'bar',  # Bavarian
+    'bcl',  # Central Bicolano
+    'bh',  # Bhojpuri
+    'bi',  # Bislama
+    'bjn',  # Banjar
+    'blk',  # Pa'O
+    'bpy',  # Bishnupriya Manipuri
+    'bxr',  # Buryat
+    'cbk-zam',  # Zamboanga Chavacano
+    'co',  # Corsican
+    'cu',  # Old Church Slavonic
+    'dty',  # Doteli
+    'dv',  # Divehi
+    'ext',  # Extremaduran
+    'fj',  # Fijian
+    'frp',  # Franco-Provençal
+    'gan',  # Gan
+    'gom',  # Goan Konkani
+    'hif',  # Fiji Hindi
+    'ilo',  # Ilokano
+    'inh',  # Ingush
+    'jbo',  # Lojban
+    'kaa',  # Karakalpak
+    'kbd',  # Kabardian Circassian
+    'kg',  # Kongo
+    'koi',  # Komi-Permyak
+    'krc',  # Karachay-Balkar
+    'kv',  # Komi
+    'lad',  # Ladino
+    'lbe',  # Lak
+    'lez',  # Lezgian
+    'li',  # Limburgish
+    'ltg',  # Latgalian
+    'mdf',  # Moksha
+    'mnw',  # Mon
+    'mwl',  # Mirandese
+    'myv',  # Erzya
+    'na',  # Nauruan
+    'nah',  # Nahuatl
+    'nov',  # Novial
+    'nrm',  # Norman
+    'pag',  # Pangasinan
+    'pam',  # Kapampangan
+    'pap',  # Papiamentu
+    'pdc',  # Pennsylvania German
+    'pfl',  # Palatinate German
+    'roa-rup',  # Aromanian
+    'sco',  # Scots
+    'sco',  # Scots (https://sco.wikipedia.org) is not known by babel, Scottish Gaelic (https://gd.wikipedia.org) is known by babel
+    'sh',  # Serbo-Croatian
+    'simple',  # simple english is not know as a natural language different to english (babel)
+    'sm',  # Samoan
+    'srn',  # Sranan
+    'stq',  # Saterland Frisian
+    'szy',  # Sakizaya
+    'tcy',  # Tulu
+    'tet',  # Tetum
+    'tpi',  # Tok Pisin
+    'trv',  # Seediq
+    'ty',  # Tahitian
+    'tyv',  # Tuvan
+    'udm',  # Udmurt
+    'vep',  # Vepsian
+    'vls',  # West Flemish
+    'vo',  # Volapük
+    'wa',  # Walloon
+    'xal',  # Kalmyk
+]
+
+
+def fetch_traits(engine_traits: EngineTraits):
+    """Fetch languages from Wikipedia"""
+    # pylint: disable=import-outside-toplevel
+
+    engine_traits.data_type = 'supported_languages'  # deprecated
+
+    import babel
+    from searx.locales import language_tag
+
+    resp = network.get('https://meta.wikimedia.org/wiki/List_of_Wikipedias')
+    if not resp.ok:
+        print("ERROR: response from Wikipedia is not OK.")
+
+    dom = html.fromstring(resp.text)
+    for row in dom.xpath('//table[contains(@class,"sortable")]//tbody/tr'):
+
+        cols = row.xpath('./td')
+        if not cols:
+            continue
+
+        cols = [c.text_content().strip() for c in cols]
+        articles = int(cols[4].replace(',', '').replace('-', '0'))
+        users = int(cols[8].replace(',', '').replace('-', '0'))
+        depth = cols[11].strip('-')
+
+        if articles < 1000:
+            # exclude languages with too few articles
+            continue
+
+        # depth: rough indicator of a Wikipedia’s quality, showing how
+        #        frequently its articles are updated.
+        if depth == '':
+            if users < 1000:
+                # depth is not calculated --> at least 1000 user should registered
+                continue
+        elif int(depth) < 20:
+            continue
+
+        eng_tag = cols[3]
+
+        if eng_tag in unknown_langs:
+            continue
+
+        try:
+            sxng_tag = language_tag(babel.Locale.parse(lang_map.get(eng_tag, eng_tag)))
+        except babel.UnknownLocaleError:
+            print("ERROR: %s -> %s is unknown by babel" % (cols[1], eng_tag))
+            continue
+
+        conflict = engine_traits.languages.get(sxng_tag)
+        if conflict:
+            if conflict != eng_tag:
+                print("CONFLICT: babel %s --> %s, %s" % (sxng_tag, conflict, eng_tag))
+            continue
+        engine_traits.languages[sxng_tag] = eng_tag
+
+    engine_traits.languages['zh_Hans'] = 'zh'