3# This script generates languages.py from intersecting each engine's supported languages.
5# The country names are obtained from http://api.geonames.org which requires registering as a user.
7# Output files (engines_languages.json and languages.py)
8# are written in current directory to avoid overwriting in case something goes wrong.
10from requests import get
11from urllib import urlencode
12from lxml.html import fromstring
13from json import loads, dumps
16path.append('../searx') # noqa
17from searx import settings
18from searx.engines import initialize_engines, engines
20# Geonames API for country names.
21geonames_user = '' # ADD USER NAME HERE
22country_names_url = 'http://api.geonames.org/countryInfoJSON?{parameters}'
25engines_languages_file = 'engines_languages.json'
26languages_file = 'languages.py'
31# To filter out invalid codes and dialects.
32def valid_code(lang_code):
33 # filter invalid codes
34 # sl-SL is technically not invalid, but still a mistake
35 invalid_codes = ['sl-SL', 'wt-WT', 'jw']
36 invalid_countries = ['UK', 'XA', 'XL']
37 if lang_code[:2] == 'xx'\
38 or lang_code in invalid_codes\
39 or lang_code[-2:] in invalid_countries\
40 or is_dialect(lang_code):
46# Language codes with any additional tags other than language and country.
47def is_dialect(lang_code):
48 lang_code = lang_code.split('-')
49 if len(lang_code) > 2 or len(lang_code[0]) > 3:
51 if len(lang_code) == 2 and len(lang_code[1]) > 2:
57# Get country name in specified language.
58def get_country_name(locale):
59 if geonames_user is '':
62 locale = locale.split('-')
66 url = country_names_url.format(parameters=urlencode({'lang': locale[0],
68 'username': geonames_user}))
70 json = loads(response.text)
71 content = json.get('geonames', None)
72 if content is None or len(content) != 1:
73 print "No country name found for " + locale[0] + "-" + locale[1]
76 return content[0].get('countryName', '')
79# Fetchs supported languages for each engine and writes json file with those.
80def fetch_supported_languages():
81 initialize_engines(settings['engines'])
82 for engine_name in engines:
83 if hasattr(engines[engine_name], 'fetch_supported_languages'):
85 engines_languages[engine_name] = engines[engine_name].fetch_supported_languages()
86 except Exception as e:
90 with io.open(engines_languages_file, "w", encoding="utf-8") as f:
91 f.write(unicode(dumps(engines_languages, ensure_ascii=False, encoding="utf-8")))
94# Join all language lists.
95# Iterate all languages supported by each engine.
96def join_language_lists():
98 # include wikipedia first for more accurate language names
99 languages = {code: lang for code, lang
100 in engines_languages['wikipedia'].iteritems()
103 for engine_name in engines_languages:
104 for locale in engines_languages[engine_name]:
105 if valid_code(locale):
106 # if language is not on list or if it has no name yet
107 if locale not in languages or not languages[locale].get('name'):
108 if isinstance(engines_languages[engine_name], dict):
109 languages[locale] = engines_languages[engine_name][locale]
111 languages[locale] = {}
113 # add to counter of engines that support given language
114 lang = locale.split('-')[0]
115 if lang in languages:
116 if 'counter' not in languages[lang]:
117 languages[lang]['counter'] = [engine_name]
118 elif engine_name not in languages[lang]['counter']:
119 languages[lang]['counter'].append(engine_name)
121 # filter list to include only languages supported by most engines
122 min_supported_engines = int(0.70 * len(engines_languages))
123 languages = {code: lang for code, lang
124 in languages.iteritems()
125 if len(lang.get('counter', [])) >= min_supported_engines or
126 len(languages.get(code.split('-')[0], {}).get('counter', [])) >= min_supported_engines}
128 # get locales that have no name or country yet
129 for locale in languages.keys():
130 # try to get language names
131 if not languages[locale].get('name'):
132 name = languages.get(locale.split('-')[0], {}).get('name', None)
134 languages[locale]['name'] = name
136 # filter out locales with no name
137 del languages[locale]
140 # try to get language name in english
141 if not languages[locale].get('english_name'):
142 languages[locale]['english_name'] = languages.get(locale.split('-')[0], {}).get('english_name', '')
144 # try to get country name
145 if locale.find('-') > 0 and not languages[locale].get('country'):
146 languages[locale]['country'] = get_country_name(locale) or ''
149# Remove countryless language if language is featured in only one country.
150def filter_single_country_languages():
153 for code in sorted(languages):
154 lang = code.split('-')[0]
155 if lang == prev_lang:
158 if prev_lang is not None and countries == 1:
159 del languages[prev_lang]
160 languages[prev_code]['country'] = ''
167def write_languages_file():
168 new_file = open(languages_file, 'w')
169 file_content = '# -*- coding: utf-8 -*-\n'\
170 + '# list of language codes\n'\
171 + '# this file is generated automatically by utils/update_search_languages.py\n'\
172 + '\nlanguage_codes = ('
173 for code in sorted(languages):
174 file_content += '\n (u"' + code + '"'\
175 + ', u"' + languages[code]['name'].split(' (')[0] + '"'\
176 + ', u"' + languages[code].get('country', '') + '"'\
177 + ', u"' + languages[code].get('english_name', '').split(' (')[0] + '"),'
179 file_content = file_content[:-1]
180 file_content += '\n)\n'
181 new_file.write(file_content.encode('utf8'))
185if __name__ == "__main__":
186 fetch_supported_languages()
187 join_language_lists()
188 filter_single_country_languages()
189 write_languages_file()
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list