| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 | # -*- coding: utf-8 -*-# This script generates languages.py from intersecting each engine's supported languages.## Output files (engines_languages.json and languages.py)# are written in current directory to avoid overwriting in case something goes wrong.from json import dumpimport iofrom sys import pathfrom babel import Locale, UnknownLocaleErrorfrom babel.languages import get_globalpath.append('../searx')  # noqafrom searx import settingsfrom searx.engines import initialize_engines, engines# Output files.engines_languages_file = 'engines_languages.json'languages_file = 'languages.py'# Fetchs supported languages for each engine and writes json file with those.def fetch_supported_languages():    engines_languages = {}    for engine_name in engines:        if hasattr(engines[engine_name], 'fetch_supported_languages'):            try:                engines_languages[engine_name] = engines[engine_name].fetch_supported_languages()                if type(engines_languages[engine_name]) == list:                    engines_languages[engine_name] = sorted(engines_languages[engine_name])            except Exception as e:                print(e)    # write json file    with io.open(engines_languages_file, "w", encoding="utf-8") as f:        dump(engines_languages, f, ensure_ascii=False, indent=4, separators=(',', ': '))    return engines_languages# Get babel Locale object from lang_code if possible.def get_locale(lang_code):    try:        locale = Locale.parse(lang_code, sep='-')        return locale    except (UnknownLocaleError, ValueError):        return None# Append engine_name to list of engines that support locale.def add_engine_counter(lang_code, engine_name, languages):    if lang_code in languages:        if 'counter' not in languages[lang_code]:            languages[lang_code]['counter'] = [engine_name]        elif engine_name not in languages[lang_code]['counter']:            languages[lang_code]['counter'].append(engine_name)# Join all language lists.# TODO: Add language names from engine's language list if name not known by babel.def join_language_lists(engines_languages):    language_list = {}    for engine_name in engines_languages:        for lang_code in engines_languages[engine_name]:            # apply custom fixes if necessary            if lang_code in getattr(engines[engine_name], 'language_aliases', {}).values():                lang_code = next(lc for lc, alias in engines[engine_name].language_aliases.items()                                 if lang_code == alias)            locale = get_locale(lang_code)            # ensure that lang_code uses standard language and country codes            if locale and locale.territory:                lang_code = locale.language + '-' + locale.territory            # add locale if it's not in list            if lang_code not in language_list:                if locale:                    language_list[lang_code] = {'name': locale.get_language_name().title(),                                                'english_name': locale.english_name,                                                'country': locale.get_territory_name() or ''}                    # also add language without country                    if locale.language not in language_list:                        language_list[locale.language] = {'name': locale.get_language_name().title(),                                                          'english_name': locale.english_name}                else:                    language_list[lang_code] = {}            # count engine for both language_country combination and language alone            add_engine_counter(lang_code, engine_name, language_list)            add_engine_counter(lang_code.split('-')[0], engine_name, language_list)    return language_list# Filter language list so it only includes the most supported languages and countries.def filter_language_list(all_languages):    min_supported_engines = 10    main_engines = [engine_name for engine_name in engines.keys()                    if 'general' in engines[engine_name].categories and                       engines[engine_name].supported_languages and                       not engines[engine_name].disabled]    # filter list to include only languages supported by most engines or all default general engines    filtered_languages = {code: lang for code, lang                          in all_languages.items()                          if (len(lang.get('counter', [])) >= min_supported_engines or                              all(main_engine in lang.get('counter', [])                                  for main_engine in main_engines))}    return filtered_languages# Add country codes to languages without one and filter out language codes.def assign_country_codes(filtered_languages, all_languages):    sorted_languages = sorted(all_languages,                              key=lambda lang: len(all_languages[lang].get('counter', [])),                              reverse=True)    previous_lang = None    previous_code = None    countries = 0    for current_code in sorted(filtered_languages):        current_lang = current_code.split('-')[0]        # count country codes per language        if current_lang == previous_lang:            countries += 1        else:            if previous_lang is not None:                # if language has no single country code                if countries == 0:                    # try to get country code with most supported engines                    for l in sorted_languages:                        l_parts = l.split('-')                        if len(l_parts) == 2 and l_parts[0] == previous_lang:                            filtered_languages[l] = all_languages[l]                            filtered_languages[l]['country'] = ''                            countries = 1                            break                    if countries == 0:                        # get most likely country code from babel                        subtags = get_global('likely_subtags').get(previous_lang)                        if subtags:                            subtag_parts = subtags.split('_')                            new_code = subtag_parts[0] + '-' + subtag_parts[-1]                            filtered_languages[new_code] = all_languages[previous_lang]                            countries = 1                if countries == 1:                    # remove countryless version of language if there's only one country                    del filtered_languages[previous_lang]                    if previous_code in filtered_languages:                        filtered_languages[previous_code]['country'] = ''            countries = 0            previous_lang = current_lang        previous_code = current_code# Write languages.py.def write_languages_file(languages):    new_file = open(languages_file, 'wb')    file_content = '# -*- coding: utf-8 -*-\n'\                   + '# list of language codes\n'\                   + '# this file is generated automatically by utils/update_search_languages.py\n'\                   + '\nlanguage_codes = ('    for code in sorted(languages):        file_content += '\n    (u"' + code + '"'\                        + ', u"' + languages[code]['name'].split(' (')[0] + '"'\                        + ', u"' + languages[code].get('country', '') + '"'\                        + ', u"' + languages[code].get('english_name', '').split(' (')[0] + '"),'    # remove last comma    file_content = file_content[:-1]    file_content += '\n)\n'    new_file.write(file_content.encode('utf8'))    new_file.close()if __name__ == "__main__":    initialize_engines(settings['engines'])    engines_languages = fetch_supported_languages()    all_languages = join_language_lists(engines_languages)    filtered_languages = filter_language_list(all_languages)    assign_country_codes(filtered_languages, all_languages)    write_languages_file(filtered_languages)
 |