Compare commits

...

8 Commits

Author SHA1 Message Date
Grant Lanham Jr ed9c5f48e7
Merge 27aa9c4cb1 into b8f1a329d3 2024-11-23 09:41:54 +01:00
searxng-bot b8f1a329d3 [l10n] update translations from Weblate
6581d89b3 - 2024-11-21 - return42 <return42@users.noreply.translate.codeberg.org>
a342903eb - 2024-11-21 - return42 <return42@users.noreply.translate.codeberg.org>
61d3236b9 - 2024-11-21 - return42 <return42@users.noreply.translate.codeberg.org>
cd03e8cc5 - 2024-11-21 - return42 <return42@users.noreply.translate.codeberg.org>
a2399e23a - 2024-11-20 - tentsbet <tentsbet@users.noreply.translate.codeberg.org>
9a5bcc06d - 2024-11-17 - cherrad <cherrad@users.noreply.translate.codeberg.org>
4364e5ef8 - 2024-11-16 - DiamondBrain113 <DiamondBrain113@users.noreply.translate.codeberg.org>
e3a127ec8 - 2024-11-15 - KinoCineaste <KinoCineaste@users.noreply.translate.codeberg.org>
2024-11-22 10:02:42 +01:00
dependabot[bot] 67f7548573 [upd] pypi: Bump typer-slim from 0.13.0 to 0.13.1
Bumps [typer-slim](https://github.com/fastapi/typer) from 0.13.0 to 0.13.1.
- [Release notes](https://github.com/fastapi/typer/releases)
- [Changelog](https://github.com/fastapi/typer/blob/master/docs/release-notes.md)
- [Commits](https://github.com/fastapi/typer/compare/0.13.0...0.13.1)

---
updated-dependencies:
- dependency-name: typer-slim
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-22 09:59:26 +01:00
dependabot[bot] f40fc2dd4f [upd] pypi: Bump setproctitle from 1.3.3 to 1.3.4
Bumps [setproctitle](https://github.com/dvarrazzo/py-setproctitle) from 1.3.3 to 1.3.4.
- [Changelog](https://github.com/dvarrazzo/py-setproctitle/blob/master/HISTORY.rst)
- [Commits](https://github.com/dvarrazzo/py-setproctitle/compare/version-1.3.3...version-1.3.4)

---
updated-dependencies:
- dependency-name: setproctitle
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-22 09:58:19 +01:00
Markus Heiser 10d3af84b8 [fix] engine: duckduckgo - don't quote query string
The query string send to DDG must not be qouted.

The query string was URL-qouted in #4011, but the URL-qouted query string result
in unexpected *URL decoded* and other garbish results as reported in #4019
and #4020.  To test compare the results of a query like::

    !ddg Häuser und Straßen :de
    !ddg Häuser und Straßen :all
    !ddg 房屋和街道 :all
    !ddg 房屋和街道 :zh

Closed:

- [#4019] https://github.com/searxng/searxng/issues/4019
- [#4020] https://github.com/searxng/searxng/issues/4020

Related:

- [#4011] https://github.com/searxng/searxng/pull/4011

Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2024-11-17 18:14:22 +01:00
Grant Lanham 27aa9c4cb1 Updates to naming, pylint fixing 2024-08-25 16:34:10 -04:00
Grant Lanham 118a748fba Inject log_level into error_recorder
format
2024-08-25 01:03:38 -04:00
Grant Lanham 9f7244d6f1 Implement "engine_exc_info" to allow removing exception logging in Checker 2024-08-25 00:32:37 -04:00
22 changed files with 149 additions and 114 deletions

View File

@ -11,11 +11,11 @@ httpx[http2]==0.24.1
Brotli==1.1.0 Brotli==1.1.0
uvloop==0.21.0 uvloop==0.21.0
httpx-socks[asyncio]==0.7.7 httpx-socks[asyncio]==0.7.7
setproctitle==1.3.3 setproctitle==1.3.4
redis==5.0.8 redis==5.0.8
markdown-it-py==3.0.0 markdown-it-py==3.0.0
fasttext-predict==0.9.2.2 fasttext-predict==0.9.2.2
tomli==2.0.2; python_version < '3.11' tomli==2.0.2; python_version < '3.11'
msgspec==0.18.6 msgspec==0.18.6
eval_type_backport; python_version < '3.9' eval_type_backport; python_version < '3.9'
typer-slim==0.13.0 typer-slim==0.13.1

View File

@ -6,7 +6,7 @@ DuckDuckGo Lite
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
import re import re
from urllib.parse import urlencode, quote_plus from urllib.parse import urlencode
import json import json
import babel import babel
import lxml.html import lxml.html
@ -263,7 +263,7 @@ def request(query, params):
params['url'] = url params['url'] = url
params['method'] = 'POST' params['method'] = 'POST'
params['data']['q'] = quote_plus(query) params['data']['q'] = query
# The API is not documented, so we do some reverse engineering and emulate # The API is not documented, so we do some reverse engineering and emulate
# what https://html.duckduckgo.com/html does when you press "next Page" link # what https://html.duckduckgo.com/html does when you press "next Page" link
@ -381,7 +381,11 @@ def response(resp):
zero_click_info_xpath = '//div[@id="zero_click_abstract"]' zero_click_info_xpath = '//div[@id="zero_click_abstract"]'
zero_click = extract_text(eval_xpath(doc, zero_click_info_xpath)).strip() zero_click = extract_text(eval_xpath(doc, zero_click_info_xpath)).strip()
if zero_click and "Your IP address is" not in zero_click and "Your user agent:" not in zero_click: if zero_click and (
"Your IP address is" not in zero_click
and "Your user agent:" not in zero_click
and "URL Decoded:" not in zero_click
):
current_query = resp.search_params["data"].get("q") current_query = resp.search_params["data"].get("q")
results.append( results.append(

View File

@ -3,6 +3,7 @@
import typing import typing
import inspect import inspect
import logging
from json import JSONDecodeError from json import JSONDecodeError
from urllib.parse import urlparse from urllib.parse import urlparse
from httpx import HTTPError, HTTPStatusError from httpx import HTTPError, HTTPStatusError
@ -30,10 +31,20 @@ class ErrorContext: # pylint: disable=missing-class-docstring
'log_message', 'log_message',
'log_parameters', 'log_parameters',
'secondary', 'secondary',
'log_level',
) )
def __init__( # pylint: disable=too-many-arguments def __init__( # pylint: disable=too-many-arguments
self, filename, function, line_no, code, exception_classname, log_message, log_parameters, secondary self,
filename,
function,
line_no,
code,
exception_classname,
log_message,
log_parameters,
secondary,
log_level=logging.WARN,
): ):
self.filename = filename self.filename = filename
self.function = function self.function = function
@ -43,6 +54,7 @@ class ErrorContext: # pylint: disable=missing-class-docstring
self.log_message = log_message self.log_message = log_message
self.log_parameters = log_parameters self.log_parameters = log_parameters
self.secondary = secondary self.secondary = secondary
self.log_level: int = log_level
def __eq__(self, o) -> bool: # pylint: disable=invalid-name def __eq__(self, o) -> bool: # pylint: disable=invalid-name
if not isinstance(o, ErrorContext): if not isinstance(o, ErrorContext):
@ -56,6 +68,7 @@ class ErrorContext: # pylint: disable=missing-class-docstring
and self.log_message == o.log_message and self.log_message == o.log_message
and self.log_parameters == o.log_parameters and self.log_parameters == o.log_parameters
and self.secondary == o.secondary and self.secondary == o.secondary
and self.log_level == o.log_level
) )
def __hash__(self): def __hash__(self):
@ -69,11 +82,12 @@ class ErrorContext: # pylint: disable=missing-class-docstring
self.log_message, self.log_message,
self.log_parameters, self.log_parameters,
self.secondary, self.secondary,
self.log_level,
) )
) )
def __repr__(self): def __repr__(self):
return "ErrorContext({!r}, {!r}, {!r}, {!r}, {!r}, {!r}) {!r}".format( return "ErrorContext({!r}, {!r}, {!r}, {!r}, {!r}, {!r}), {!r}, {!r}".format(
self.filename, self.filename,
self.line_no, self.line_no,
self.code, self.code,
@ -81,13 +95,14 @@ class ErrorContext: # pylint: disable=missing-class-docstring
self.log_message, self.log_message,
self.log_parameters, self.log_parameters,
self.secondary, self.secondary,
self.log_level,
) )
def add_error_context(engine_name: str, error_context: ErrorContext) -> None: def add_error_context(engine_name: str, error_context: ErrorContext) -> None:
errors_for_engine = errors_per_engines.setdefault(engine_name, {}) errors_for_engine = errors_per_engines.setdefault(engine_name, {})
errors_for_engine[error_context] = errors_for_engine.get(error_context, 0) + 1 errors_for_engine[error_context] = errors_for_engine.get(error_context, 0) + 1
engines[engine_name].logger.warning('%s', str(error_context)) engines[engine_name].logger.log(error_context.log_level, '%s', str(error_context))
def get_trace(traces): def get_trace(traces):
@ -157,7 +172,9 @@ def get_exception_classname(exc: Exception) -> str:
return exc_module + '.' + exc_name return exc_module + '.' + exc_name
def get_error_context(framerecords, exception_classname, log_message, log_parameters, secondary) -> ErrorContext: def get_error_context(
framerecords, exception_classname, log_message, log_parameters, secondary, log_level: int
) -> ErrorContext:
searx_frame = get_trace(framerecords) searx_frame = get_trace(framerecords)
filename = searx_frame.filename filename = searx_frame.filename
if filename.startswith(searx_parent_dir): if filename.startswith(searx_parent_dir):
@ -166,30 +183,36 @@ def get_error_context(framerecords, exception_classname, log_message, log_parame
line_no = searx_frame.lineno line_no = searx_frame.lineno
code = searx_frame.code_context[0].strip() code = searx_frame.code_context[0].strip()
del framerecords del framerecords
return ErrorContext(filename, function, line_no, code, exception_classname, log_message, log_parameters, secondary) return ErrorContext(
filename, function, line_no, code, exception_classname, log_message, log_parameters, secondary, log_level
)
def count_exception(engine_name: str, exc: Exception, secondary: bool = False) -> None: def count_exception(engine_name: str, exc: Exception, secondary: bool = False, log_level=logging.WARN) -> None:
if not settings['general']['enable_metrics']: if not settings['general']['enable_metrics']:
return return
framerecords = inspect.trace() framerecords = inspect.trace()
try: try:
exception_classname = get_exception_classname(exc) exception_classname = get_exception_classname(exc)
log_parameters = get_messages(exc, framerecords[-1][1]) log_parameters = get_messages(exc, framerecords[-1][1])
error_context = get_error_context(framerecords, exception_classname, None, log_parameters, secondary) error_context = get_error_context(framerecords, exception_classname, None, log_parameters, secondary, log_level)
add_error_context(engine_name, error_context) add_error_context(engine_name, error_context)
finally: finally:
del framerecords del framerecords
def count_error( def count_error(
engine_name: str, log_message: str, log_parameters: typing.Optional[typing.Tuple] = None, secondary: bool = False engine_name: str,
log_message: str,
log_parameters: typing.Optional[typing.Tuple] = None,
secondary: bool = False,
log_level: int = logging.WARN,
) -> None: ) -> None:
if not settings['general']['enable_metrics']: if not settings['general']['enable_metrics']:
return return
framerecords = list(reversed(inspect.stack()[1:])) framerecords = list(reversed(inspect.stack()[1:]))
try: try:
error_context = get_error_context(framerecords, None, log_message, log_parameters or (), secondary) error_context = get_error_context(framerecords, None, log_message, log_parameters or (), secondary, log_level)
add_error_context(engine_name, error_context) add_error_context(engine_name, error_context)
finally: finally:
del framerecords del framerecords

View File

@ -357,6 +357,7 @@ class Checker: # pylint: disable=missing-class-docstring
def __init__(self, processor: EngineProcessor): def __init__(self, processor: EngineProcessor):
self.processor = processor self.processor = processor
self.processor.log_engine_exc_info = False # Remove exception information from errors to reduce verbosity
self.tests = self.processor.get_tests() self.tests = self.processor.get_tests()
self.test_results = TestResults() self.test_results = TestResults()
@ -418,8 +419,10 @@ class Checker: # pylint: disable=missing-class-docstring
result_container_check.check_basic() result_container_check.check_basic()
return result_container_check return result_container_check
def run_test(self, test_name): def run_test(self, test_name: str):
test_parameters = self.tests[test_name] test_parameters = self.tests[test_name]
# Not really a warning, but an info log will not appear
logger.warning('---%s---', test_name)
search_query_list = list(Checker.search_query_matrix_iterator(self.engineref_list, test_parameters['matrix'])) search_query_list = list(Checker.search_query_matrix_iterator(self.engineref_list, test_parameters['matrix']))
rct_list = [self.get_result_container_tests(test_name, search_query) for search_query in search_query_list] rct_list = [self.get_result_container_tests(test_name, search_query) for search_query in search_query_list]
stop_test = False stop_test = False

View File

@ -3,6 +3,8 @@
""" """
import logging
from logging import Logger
import threading import threading
from abc import abstractmethod, ABC from abc import abstractmethod, ABC
from timeit import default_timer from timeit import default_timer
@ -58,12 +60,13 @@ class SuspendedStatus:
class EngineProcessor(ABC): class EngineProcessor(ABC):
"""Base classes used for all types of request processors.""" """Base classes used for all types of request processors."""
__slots__ = 'engine', 'engine_name', 'lock', 'suspended_status', 'logger' __slots__ = 'engine', 'engine_name', 'lock', 'suspended_status', 'logger', 'log_engine_exc_info'
def __init__(self, engine, engine_name: str): def __init__(self, engine, engine_name: str):
self.engine = engine self.engine = engine
self.engine_name = engine_name self.engine_name = engine_name
self.logger = engines[engine_name].logger self.logger: Logger = engines[engine_name].logger
self.log_engine_exc_info = True
key = get_network(self.engine_name) key = get_network(self.engine_name)
key = id(key) if key else self.engine_name key = id(key) if key else self.engine_name
self.suspended_status = SUSPENDED_STATUS.setdefault(key, SuspendedStatus()) self.suspended_status = SUSPENDED_STATUS.setdefault(key, SuspendedStatus())
@ -82,6 +85,10 @@ class EngineProcessor(ABC):
def has_initialize_function(self): def has_initialize_function(self):
return hasattr(self.engine, 'init') return hasattr(self.engine, 'init')
@property
def metrics_log_level(self) -> int:
return logging.WARN if self.log_engine_exc_info else logging.NOTSET
def handle_exception(self, result_container, exception_or_message, suspend=False): def handle_exception(self, result_container, exception_or_message, suspend=False):
# update result_container # update result_container
if isinstance(exception_or_message, BaseException): if isinstance(exception_or_message, BaseException):
@ -95,9 +102,9 @@ class EngineProcessor(ABC):
# metrics # metrics
counter_inc('engine', self.engine_name, 'search', 'count', 'error') counter_inc('engine', self.engine_name, 'search', 'count', 'error')
if isinstance(exception_or_message, BaseException): if isinstance(exception_or_message, BaseException):
count_exception(self.engine_name, exception_or_message) count_exception(self.engine_name, exception_or_message, log_level=self.metrics_log_level)
else: else:
count_error(self.engine_name, exception_or_message) count_error(self.engine_name, exception_or_message, log_level=self.metrics_log_level)
# suspend the engine ? # suspend the engine ?
if suspend: if suspend:
suspended_time = None suspended_time = None

View File

@ -127,6 +127,7 @@ class OnlineProcessor(EngineProcessor):
'{} redirects, maximum: {}'.format(len(response.history), soft_max_redirects), '{} redirects, maximum: {}'.format(len(response.history), soft_max_redirects),
(status_code, reason, hostname), (status_code, reason, hostname),
secondary=True, secondary=True,
log_level=self.metrics_log_level,
) )
return response return response
@ -180,20 +181,21 @@ class OnlineProcessor(EngineProcessor):
self.logger.exception( self.logger.exception(
"requests exception (search duration : {0} s, timeout: {1} s) : {2}".format( "requests exception (search duration : {0} s, timeout: {1} s) : {2}".format(
default_timer() - start_time, timeout_limit, e default_timer() - start_time, timeout_limit, e
) ),
exc_info=self.log_engine_exc_info,
) )
except SearxEngineCaptchaException as e: except SearxEngineCaptchaException as e:
self.handle_exception(result_container, e, suspend=True) self.handle_exception(result_container, e, suspend=True)
self.logger.exception('CAPTCHA') self.logger.exception('CAPTCHA', exc_info=self.log_engine_exc_info)
except SearxEngineTooManyRequestsException as e: except SearxEngineTooManyRequestsException as e:
self.handle_exception(result_container, e, suspend=True) self.handle_exception(result_container, e, suspend=True)
self.logger.exception('Too many requests') self.logger.exception('Too many requests', exc_info=self.log_engine_exc_info)
except SearxEngineAccessDeniedException as e: except SearxEngineAccessDeniedException as e:
self.handle_exception(result_container, e, suspend=True) self.handle_exception(result_container, e, suspend=True)
self.logger.exception('SearXNG is blocked') self.logger.exception('SearXNG is blocked', exc_info=self.log_engine_exc_info)
except Exception as e: # pylint: disable=broad-except except Exception as e: # pylint: disable=broad-except
self.handle_exception(result_container, e) self.handle_exception(result_container, e)
self.logger.exception('exception : {0}'.format(e)) self.logger.exception('exception : {0}'.format(e), exc_info=self.log_engine_exc_info)
def get_default_tests(self): def get_default_tests(self):
tests = {} tests = {}

View File

@ -18,22 +18,23 @@
# Yahya-Lando <Yahya-Lando@users.noreply.translate.codeberg.org>, 2024. # Yahya-Lando <Yahya-Lando@users.noreply.translate.codeberg.org>, 2024.
# nebras <nebras@users.noreply.translate.codeberg.org>, 2024. # nebras <nebras@users.noreply.translate.codeberg.org>, 2024.
# geekom13 <geekom13@users.noreply.translate.codeberg.org>, 2024. # geekom13 <geekom13@users.noreply.translate.codeberg.org>, 2024.
# cherrad <cherrad@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-10-04 07:09+0000\n" "PO-Revision-Date: 2024-11-17 23:56+0000\n"
"Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>" "Last-Translator: cherrad <cherrad@users.noreply.translate.codeberg.org>\n"
"\n" "Language-Team: Arabic <https://translate.codeberg.org/projects/searxng/"
"searxng/ar/>\n"
"Language: ar\n" "Language: ar\n"
"Language-Team: Arabic "
"<https://translate.codeberg.org/projects/searxng/searxng/ar/>\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : "
"n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
"X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -461,7 +462,7 @@ msgstr "حوسبة معطيات ال{functions}"
#: searx/engines/mozhi.py:57 #: searx/engines/mozhi.py:57
msgid "Synonyms" msgid "Synonyms"
msgstr "" msgstr "مرادفات"
#: searx/engines/openstreetmap.py:159 #: searx/engines/openstreetmap.py:159
msgid "Get directions" msgid "Get directions"
@ -1224,11 +1225,11 @@ msgstr "أقصى مدّة"
#: searx/templates/simple/preferences/favicon.html:2 #: searx/templates/simple/preferences/favicon.html:2
msgid "Favicon Resolver" msgid "Favicon Resolver"
msgstr "" msgstr "محلل أيقونة المفضلة"
#: searx/templates/simple/preferences/favicon.html:15 #: searx/templates/simple/preferences/favicon.html:15
msgid "Display favicons near search results" msgid "Display favicons near search results"
msgstr "" msgstr "عرض المفضلات قرب نتائج البحث"
#: searx/templates/simple/preferences/footer.html:2 #: searx/templates/simple/preferences/footer.html:2
msgid "" msgid ""
@ -1973,4 +1974,3 @@ msgstr "إخفاء الفيديو"
#~ msgid "Engines cannot retrieve results" #~ msgid "Engines cannot retrieve results"
#~ msgstr "لم تتمكن محركات البحث من العثور على أية نتيجة" #~ msgstr "لم تتمكن محركات البحث من العثور على أية نتيجة"

View File

@ -18,9 +18,8 @@ msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-10-13 03:30+0000\n" "PO-Revision-Date: 2024-11-21 08:13+0000\n"
"Last-Translator: stoychevww <stoychevww@users.noreply.translate.codeberg.org>" "Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>\n"
"\n"
"Language-Team: Bulgarian <https://translate.codeberg.org/projects/searxng/" "Language-Team: Bulgarian <https://translate.codeberg.org/projects/searxng/"
"searxng/bg/>\n" "searxng/bg/>\n"
"Language: bg\n" "Language: bg\n"
@ -28,7 +27,7 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.7.2\n" "X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -59,7 +58,7 @@ msgstr "музика"
#. CATEGORY_NAMES['SOCIAL_MEDIA'] #. CATEGORY_NAMES['SOCIAL_MEDIA']
#: searx/searxng.msg #: searx/searxng.msg
msgid "social media" msgid "social media"
msgstr "социална мрежа" msgstr "социална медия"
#. CATEGORY_NAMES['IMAGES'] #. CATEGORY_NAMES['IMAGES']
#: searx/searxng.msg #: searx/searxng.msg
@ -159,12 +158,12 @@ msgstr "автоматичен"
#. STYLE_NAMES['LIGHT'] #. STYLE_NAMES['LIGHT']
#: searx/searxng.msg #: searx/searxng.msg
msgid "light" msgid "light"
msgstr "светъл" msgstr "светло"
#. STYLE_NAMES['DARK'] #. STYLE_NAMES['DARK']
#: searx/searxng.msg #: searx/searxng.msg
msgid "dark" msgid "dark"
msgstr "тъмен" msgstr "тъмно"
#. STYLE_NAMES['BLACK'] #. STYLE_NAMES['BLACK']
#: searx/searxng.msg #: searx/searxng.msg
@ -364,7 +363,7 @@ msgstr "Грешка при зареждането на следващата с
#: searx/webapp.py:495 searx/webapp.py:898 #: searx/webapp.py:495 searx/webapp.py:898
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Неправилни настройки, моля проверете предпочитанията си" msgstr "Неправилни настройки, моля редактирайте предпочитанията си"
#: searx/webapp.py:511 #: searx/webapp.py:511
msgid "Invalid settings" msgid "Invalid settings"
@ -412,11 +411,11 @@ msgstr "прокси грешка"
#: searx/webutils.py:57 #: searx/webutils.py:57
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "Кепча" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:58
msgid "too many requests" msgid "too many requests"
msgstr "твърде много искания" msgstr "твърде много повиквания"
#: searx/webutils.py:59 #: searx/webutils.py:59
msgid "access denied" msgid "access denied"
@ -520,7 +519,7 @@ msgstr ""
#: searx/engines/tineye.py:57 #: searx/engines/tineye.py:57
msgid "The image could not be downloaded." msgid "The image could not be downloaded."
msgstr "Снимката не може да бъде смъкната." msgstr "Снимката не може да бъде свалена."
#: searx/engines/zlibrary.py:138 #: searx/engines/zlibrary.py:138
msgid "Book rating" msgid "Book rating"

View File

@ -13,21 +13,23 @@
# RTRedreovic <RTRedreovic@users.noreply.translate.codeberg.org>, 2023. # RTRedreovic <RTRedreovic@users.noreply.translate.codeberg.org>, 2023.
# Azharjan <alexander.um.edu@gmail.com>, 2023. # Azharjan <alexander.um.edu@gmail.com>, 2023.
# return42 <return42@users.noreply.translate.codeberg.org>, 2024. # return42 <return42@users.noreply.translate.codeberg.org>, 2024.
# KinoCineaste <KinoCineaste@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-09-05 06:18+0000\n" "PO-Revision-Date: 2024-11-16 08:04+0000\n"
"Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>" "Last-Translator: KinoCineaste <KinoCineaste@users.noreply.translate.codeberg."
"\n" "org>\n"
"Language-Team: Esperanto <https://translate.codeberg.org/projects/searxng/"
"searxng/eo/>\n"
"Language: eo\n" "Language: eo\n"
"Language-Team: Esperanto "
"<https://translate.codeberg.org/projects/searxng/searxng/eo/>\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -78,7 +80,7 @@ msgstr "radio"
#. CATEGORY_NAMES['TV'] #. CATEGORY_NAMES['TV']
#: searx/searxng.msg #: searx/searxng.msg
msgid "tv" msgid "tv"
msgstr "" msgstr "televido"
#. CATEGORY_NAMES['IT'] #. CATEGORY_NAMES['IT']
#: searx/searxng.msg #: searx/searxng.msg
@ -168,7 +170,7 @@ msgstr "malhela"
#. STYLE_NAMES['BLACK'] #. STYLE_NAMES['BLACK']
#: searx/searxng.msg #: searx/searxng.msg
msgid "black" msgid "black"
msgstr "" msgstr "nigra"
#. BRAND_CUSTOM_LINKS['UPTIME'] #. BRAND_CUSTOM_LINKS['UPTIME']
#: searx/searxng.msg #: searx/searxng.msg
@ -1961,4 +1963,3 @@ msgstr "kaŝi videojn"
#~ msgid "Engines cannot retrieve results" #~ msgid "Engines cannot retrieve results"
#~ msgstr "Serĉiloj ne povas retrovi rezultojn" #~ msgstr "Serĉiloj ne povas retrovi rezultojn"

View File

@ -23,19 +23,19 @@
# return42 <return42@users.noreply.translate.codeberg.org>, 2024. # return42 <return42@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-09-23 01:18+0000\n" "PO-Revision-Date: 2024-11-21 05:07+0000\n"
"Last-Translator: tentsbet <tentsbet@users.noreply.translate.codeberg.org>" "Last-Translator: tentsbet <tentsbet@users.noreply.translate.codeberg.org>\n"
"\n" "Language-Team: Japanese <https://translate.codeberg.org/projects/searxng/"
"searxng/ja/>\n"
"Language: ja\n" "Language: ja\n"
"Language-Team: Japanese "
"<https://translate.codeberg.org/projects/searxng/searxng/ja/>\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -176,7 +176,7 @@ msgstr "ダーク"
#. STYLE_NAMES['BLACK'] #. STYLE_NAMES['BLACK']
#: searx/searxng.msg #: searx/searxng.msg
msgid "black" msgid "black"
msgstr "" msgstr "ブラック"
#. BRAND_CUSTOM_LINKS['UPTIME'] #. BRAND_CUSTOM_LINKS['UPTIME']
#: searx/searxng.msg #: searx/searxng.msg
@ -463,7 +463,7 @@ msgstr "変数の {functions} を計算する"
#: searx/engines/mozhi.py:57 #: searx/engines/mozhi.py:57
msgid "Synonyms" msgid "Synonyms"
msgstr "" msgstr "類義語"
#: searx/engines/openstreetmap.py:159 #: searx/engines/openstreetmap.py:159
msgid "Get directions" msgid "Get directions"
@ -1202,11 +1202,11 @@ msgstr "最大時間"
#: searx/templates/simple/preferences/favicon.html:2 #: searx/templates/simple/preferences/favicon.html:2
msgid "Favicon Resolver" msgid "Favicon Resolver"
msgstr "" msgstr "Favicon Resolver"
#: searx/templates/simple/preferences/favicon.html:15 #: searx/templates/simple/preferences/favicon.html:15
msgid "Display favicons near search results" msgid "Display favicons near search results"
msgstr "" msgstr "検索結果でfaviconに合いそうなものを表示する"
#: searx/templates/simple/preferences/footer.html:2 #: searx/templates/simple/preferences/footer.html:2
msgid "" msgid ""
@ -1917,4 +1917,3 @@ msgstr "動画を隠す"
#~ msgid "Engines cannot retrieve results" #~ msgid "Engines cannot retrieve results"
#~ msgstr "エンジンは結果を取得できません" #~ msgstr "エンジンは結果を取得できません"

View File

@ -16,16 +16,16 @@ msgstr ""
"Project-Id-Version: PROJECT VERSION\n" "Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-07-19 07:09+0000\n" "PO-Revision-Date: 2024-11-21 08:13+0000\n"
"Last-Translator: wazhanudin " "Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>\n"
"<wazhanudin@users.noreply.translate.codeberg.org>\n" "Language-Team: Malay <https://translate.codeberg.org/projects/searxng/"
"searxng/ms/>\n"
"Language: ms\n" "Language: ms\n"
"Language-Team: Malay "
"<https://translate.codeberg.org/projects/searxng/searxng/ms/>\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -166,7 +166,7 @@ msgstr "gelap"
#. STYLE_NAMES['BLACK'] #. STYLE_NAMES['BLACK']
#: searx/searxng.msg #: searx/searxng.msg
msgid "black" msgid "black"
msgstr "" msgstr "Hitam"
#. BRAND_CUSTOM_LINKS['UPTIME'] #. BRAND_CUSTOM_LINKS['UPTIME']
#: searx/searxng.msg #: searx/searxng.msg
@ -1690,4 +1690,3 @@ msgstr "sembunyikkan video"
#~ msgid "Engines cannot retrieve results" #~ msgid "Engines cannot retrieve results"
#~ msgstr "Enjin tidak dapat mendapatkan keputusan" #~ msgstr "Enjin tidak dapat mendapatkan keputusan"

View File

@ -18,20 +18,20 @@
# UnD37970UnD <UnD37970UnD@users.noreply.translate.codeberg.org>, 2024. # UnD37970UnD <UnD37970UnD@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-09-28 15:23+0000\n" "PO-Revision-Date: 2024-11-21 08:13+0000\n"
"Last-Translator: UnD37970UnD " "Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>\n"
"<UnD37970UnD@users.noreply.translate.codeberg.org>\n" "Language-Team: Romanian <https://translate.codeberg.org/projects/searxng/"
"searxng/ro/>\n"
"Language: ro\n" "Language: ro\n"
"Language-Team: Romanian "
"<https://translate.codeberg.org/projects/searxng/searxng/ro/>\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 "
"< 20)) ? 1 : 2;\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < "
"20)) ? 1 : 2;\n"
"X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -172,7 +172,7 @@ msgstr "întunecat"
#. STYLE_NAMES['BLACK'] #. STYLE_NAMES['BLACK']
#: searx/searxng.msg #: searx/searxng.msg
msgid "black" msgid "black"
msgstr "" msgstr "negru"
#. BRAND_CUSTOM_LINKS['UPTIME'] #. BRAND_CUSTOM_LINKS['UPTIME']
#: searx/searxng.msg #: searx/searxng.msg
@ -1998,4 +1998,3 @@ msgstr "ascunde video"
#~ msgid "Engines cannot retrieve results" #~ msgid "Engines cannot retrieve results"
#~ msgstr "Motoarele nu pot obține rezultate" #~ msgstr "Motoarele nu pot obține rezultate"

View File

@ -13,20 +13,20 @@
# crnobog <crnobog@users.noreply.translate.codeberg.org>, 2024. # crnobog <crnobog@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-09-05 06:18+0000\n" "PO-Revision-Date: 2024-11-21 08:13+0000\n"
"Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>" "Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>\n"
"\n" "Language-Team: Serbian <https://translate.codeberg.org/projects/searxng/"
"searxng/sr/>\n"
"Language: sr\n" "Language: sr\n"
"Language-Team: Serbian "
"<https://translate.codeberg.org/projects/searxng/searxng/sr/>\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
"X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -252,7 +252,7 @@ msgstr "Подне"
#. WEATHER_TERMS['PRESSURE'] #. WEATHER_TERMS['PRESSURE']
#: searx/engines/open_meteo.py:95 searx/searxng.msg #: searx/engines/open_meteo.py:95 searx/searxng.msg
msgid "Pressure" msgid "Pressure"
msgstr "" msgstr "Притисак"
#. WEATHER_TERMS['SUNRISE'] #. WEATHER_TERMS['SUNRISE']
#: searx/engines/duckduckgo_weather.py:81 searx/engines/wttr.py:36 #: searx/engines/duckduckgo_weather.py:81 searx/engines/wttr.py:36
@ -1972,4 +1972,3 @@ msgstr "сакриј видео"
#~ msgid "Engines cannot retrieve results" #~ msgid "Engines cannot retrieve results"
#~ msgstr "Не може повратити резултате" #~ msgstr "Не може повратити резултате"

View File

@ -11,13 +11,15 @@
# vducong <vducong@users.noreply.translate.codeberg.org>, 2024. # vducong <vducong@users.noreply.translate.codeberg.org>, 2024.
# tvminh19 <tvminh19@users.noreply.translate.codeberg.org>, 2024. # tvminh19 <tvminh19@users.noreply.translate.codeberg.org>, 2024.
# KhietVo <KhietVo@users.noreply.translate.codeberg.org>, 2024. # KhietVo <KhietVo@users.noreply.translate.codeberg.org>, 2024.
# DiamondBrain113 <DiamondBrain113@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-11-14 14:07+0000\n" "PO-Revision-Date: 2024-11-16 20:44+0000\n"
"Last-Translator: KhietVo <KhietVo@users.noreply.translate.codeberg.org>\n" "Last-Translator: DiamondBrain113 <DiamondBrain113@users.noreply.translate."
"codeberg.org>\n"
"Language-Team: Vietnamese <https://translate.codeberg.org/projects/searxng/" "Language-Team: Vietnamese <https://translate.codeberg.org/projects/searxng/"
"searxng/vi/>\n" "searxng/vi/>\n"
"Language: vi\n" "Language: vi\n"
@ -299,13 +301,13 @@ msgstr "những bài đăng"
#. SOCIAL_MEDIA_TERMS['ACTIVE USERS'] #. SOCIAL_MEDIA_TERMS['ACTIVE USERS']
#: searx/engines/lemmy.py:87 searx/searxng.msg #: searx/engines/lemmy.py:87 searx/searxng.msg
msgid "active users" msgid "active users"
msgstr "" msgstr "Người dùng hoạt động"
#. SOCIAL_MEDIA_TERMS['COMMENTS'] #. SOCIAL_MEDIA_TERMS['COMMENTS']
#: searx/engines/discourse.py:157 searx/engines/hackernews.py:78 #: searx/engines/discourse.py:157 searx/engines/hackernews.py:78
#: searx/engines/lemmy.py:130 searx/searxng.msg #: searx/engines/lemmy.py:130 searx/searxng.msg
msgid "comments" msgid "comments"
msgstr "" msgstr "Bình luận"
#. SOCIAL_MEDIA_TERMS['USER'] #. SOCIAL_MEDIA_TERMS['USER']
#: searx/engines/lemmy.py:129 searx/engines/lemmy.py:164 searx/searxng.msg #: searx/engines/lemmy.py:129 searx/engines/lemmy.py:164 searx/searxng.msg
@ -454,7 +456,7 @@ msgstr "Tính toán {functions} của các đối số"
#: searx/engines/mozhi.py:57 #: searx/engines/mozhi.py:57
msgid "Synonyms" msgid "Synonyms"
msgstr "" msgstr "Đồng nghĩa"
#: searx/engines/openstreetmap.py:159 #: searx/engines/openstreetmap.py:159
msgid "Get directions" msgid "Get directions"
@ -541,9 +543,8 @@ msgid "hash digest"
msgstr "hash băm" msgstr "hash băm"
#: searx/plugins/hostnames.py:103 #: searx/plugins/hostnames.py:103
#, fuzzy
msgid "Hostnames plugin" msgid "Hostnames plugin"
msgstr "Mấy chủ bổ trợ" msgstr "Bổ trợ tên máy chủ"
#: searx/plugins/hostnames.py:104 #: searx/plugins/hostnames.py:104
msgid "Rewrite hostnames, remove results or prioritize them based on the hostname" msgid "Rewrite hostnames, remove results or prioritize them based on the hostname"
@ -578,7 +579,7 @@ msgstr "Địa chỉ IP của bạn: "
#: searx/plugins/self_info.py:31 #: searx/plugins/self_info.py:31
msgid "Your user-agent is: " msgid "Your user-agent is: "
msgstr "" msgstr "Tác nhân người dùng của bạn là: "
#: searx/plugins/tor_check.py:24 #: searx/plugins/tor_check.py:24
msgid "Tor check plugin" msgid "Tor check plugin"
@ -623,7 +624,7 @@ msgstr "Loại bỏ các đối số theo dõi từ URL trả về"
#: searx/plugins/unit_converter.py:29 #: searx/plugins/unit_converter.py:29
msgid "Convert between units" msgid "Convert between units"
msgstr "" msgstr "Chuyển đổi giữa các đại lượng"
#: searx/templates/simple/404.html:4 #: searx/templates/simple/404.html:4
msgid "Page not found" msgid "Page not found"
@ -690,7 +691,7 @@ msgstr "Độ dài"
#: searx/templates/simple/macros.html:41 #: searx/templates/simple/macros.html:41
msgid "Views" msgid "Views"
msgstr "" msgstr "Lượt xem"
#: searx/templates/simple/macros.html:42 #: searx/templates/simple/macros.html:42
#: searx/templates/simple/result_templates/files.html:34 #: searx/templates/simple/result_templates/files.html:34
@ -933,9 +934,8 @@ msgid "Checker"
msgstr "Người kiểm duyệt" msgstr "Người kiểm duyệt"
#: searx/templates/simple/stats.html:131 #: searx/templates/simple/stats.html:131
#, fuzzy
msgid "Failed test" msgid "Failed test"
msgstr "Bản kiểm thử không đạt" msgstr "Bài kiểm tra không đạt"
#: searx/templates/simple/stats.html:132 #: searx/templates/simple/stats.html:132
msgid "Comment(s)" msgid "Comment(s)"
@ -951,7 +951,7 @@ msgstr "Tin nhắn từ công cụ tìm kiếm"
#: searx/templates/simple/elements/engines_msg.html:7 #: searx/templates/simple/elements/engines_msg.html:7
msgid "seconds" msgid "seconds"
msgstr "" msgstr "giây"
#: searx/templates/simple/elements/search_url.html:3 #: searx/templates/simple/elements/search_url.html:3
msgid "Search URL" msgid "Search URL"
@ -1208,11 +1208,11 @@ msgstr ""
#: searx/templates/simple/preferences/engines.html:15 #: searx/templates/simple/preferences/engines.html:15
msgid "Enable all" msgid "Enable all"
msgstr "" msgstr "Bật tất cả"
#: searx/templates/simple/preferences/engines.html:16 #: searx/templates/simple/preferences/engines.html:16
msgid "Disable all" msgid "Disable all"
msgstr "" msgstr "Tắt tất cả"
#: searx/templates/simple/preferences/engines.html:25 #: searx/templates/simple/preferences/engines.html:25
msgid "!bang" msgid "!bang"
@ -1232,11 +1232,11 @@ msgstr "Thời gian tối đa"
#: searx/templates/simple/preferences/favicon.html:2 #: searx/templates/simple/preferences/favicon.html:2
msgid "Favicon Resolver" msgid "Favicon Resolver"
msgstr "" msgstr "Bộ phân giải biểu tượng web"
#: searx/templates/simple/preferences/favicon.html:15 #: searx/templates/simple/preferences/favicon.html:15
msgid "Display favicons near search results" msgid "Display favicons near search results"
msgstr "" msgstr "Hiển thị biểu tượng web gần kết quả tìm kiếm"
#: searx/templates/simple/preferences/footer.html:2 #: searx/templates/simple/preferences/footer.html:2
msgid "" msgid ""