Merge pull request 'master' (#2) from Icycoide/searxng:master into master

Reviewed-on: #2
This commit is contained in:
kevadesu 2025-05-31 13:31:47 +02:00
commit 7182190057
186 changed files with 4107 additions and 3923 deletions

View file

@ -5,7 +5,7 @@ name: Cleanup
on: on:
workflow_dispatch: workflow_dispatch:
schedule: schedule:
- cron: "4 4 * * 0" - cron: "4 4 * * *"
concurrency: concurrency:
group: ${{ github.workflow }} group: ${{ github.workflow }}
@ -16,6 +16,8 @@ permissions:
jobs: jobs:
container-cache: container-cache:
# FIXME: On forks it fails with "Failed to fetch packages: missing field `id` at line 1 column 141"
if: github.repository_owner == 'searxng' || github.event_name == 'workflow_dispatch'
name: Container cache name: Container cache
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
permissions: permissions:
@ -28,7 +30,7 @@ jobs:
with: with:
account: "${{ github.repository_owner }}" account: "${{ github.repository_owner }}"
token: "${{ secrets.GITHUB_TOKEN }}" token: "${{ secrets.GITHUB_TOKEN }}"
image-names: "cache" image-names: "cache base"
image-tags: "!searxng-*" image-tags: "!searxng*"
cut-off: "1w" cut-off: "1d"
keep-n-most-recent: "100" keep-n-most-recent: "100"

View file

@ -25,10 +25,83 @@ env:
PYTHON_VERSION: "3.13" PYTHON_VERSION: "3.13"
jobs: jobs:
build-base:
if: |
(github.repository_owner == 'searxng' && github.event.workflow_run.conclusion == 'success')
|| github.event_name == 'workflow_dispatch'
name: Build base
runs-on: ubuntu-24.04
permissions:
# Organization GHCR
packages: write
steps:
- if: github.repository_owner == 'searxng'
name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: "false"
- if: github.repository_owner == 'searxng'
name: Get date
id: date
run: echo "date=$(date +'%Y%m%d')" >>$GITHUB_OUTPUT
- if: github.repository_owner == 'searxng'
name: Check cache apko
id: cache-apko
uses: actions/cache/restore@v4
with:
# yamllint disable-line rule:line-length
key: "apko-${{ steps.date.outputs.date }}-${{ hashFiles('./container/base.yml', './container/base-builder.yml') }}"
path: "/tmp/.apko/"
lookup-only: true
- if: github.repository_owner == 'searxng' && steps.cache-apko.outputs.cache-hit != 'true'
name: Setup cache apko
uses: actions/cache@v4
with:
# yamllint disable-line rule:line-length
key: "apko-${{ steps.date.outputs.date }}-${{ hashFiles('./container/base.yml', './container/base-builder.yml') }}"
restore-keys: "apko-${{ steps.date.outputs.date }}-"
path: "/tmp/.apko/"
- if: github.repository_owner == 'searxng' && steps.cache-apko.outputs.cache-hit != 'true'
name: Setup apko
run: |
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
brew install apko
- if: github.repository_owner == 'searxng' && steps.cache-apko.outputs.cache-hit != 'true'
name: Login to GHCR
uses: docker/login-action@v3
with:
registry: "ghcr.io"
username: "${{ github.repository_owner }}"
password: "${{ secrets.GITHUB_TOKEN }}"
- if: github.repository_owner == 'searxng' && steps.cache-apko.outputs.cache-hit != 'true'
name: Build
run: |
eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
apko publish ./container/base.yml ghcr.io/${{ github.repository_owner }}/base:searxng \
--cache-dir=/tmp/.apko/ \
--sbom=false \
--vcs=false \
--log-level=debug
apko publish ./container/base-builder.yml ghcr.io/${{ github.repository_owner }}/base:searxng-builder \
--cache-dir=/tmp/.apko/ \
--sbom=false \
--vcs=false \
--log-level=debug
build: build:
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' if: github.repository_owner == 'searxng' || github.event_name == 'workflow_dispatch'
name: Build (${{ matrix.arch }}) name: Build (${{ matrix.arch }})
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
needs: build-base
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:

View file

@ -16,6 +16,7 @@ permissions:
jobs: jobs:
container: container:
if: github.repository_owner == 'searxng'
name: Container name: Container
runs-on: ubuntu-24.04-arm runs-on: ubuntu-24.04-arm
permissions: permissions:
@ -30,7 +31,7 @@ jobs:
- name: Run Trivy scanner - name: Run Trivy scanner
uses: aquasecurity/trivy-action@0.30.0 uses: aquasecurity/trivy-action@0.30.0
with: with:
image-ref: "docker.io/searxng/searxng:latest" image-ref: "ghcr.io/searxng/searxng:latest"
vuln-type: "os,library" vuln-type: "os,library"
severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL" severity: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL"
ignore-unfixed: "false" ignore-unfixed: "false"

View file

@ -54,7 +54,7 @@ ci.test: test.yamllint test.black test.types.ci test.pylint test.unit test.robo
test: test.yamllint test.black test.types.dev test.pylint test.unit test.robot test.rst test.shell test: test.yamllint test.black test.types.dev test.pylint test.unit test.robot test.rst test.shell
test.shell: test.shell:
$(Q)shellcheck -x -s dash \ $(Q)shellcheck -x -s dash \
container/docker-entrypoint.sh container/entrypoint.sh
$(Q)shellcheck -x -s bash \ $(Q)shellcheck -x -s bash \
utils/brand.sh \ utils/brand.sh \
$(MTOOLS) \ $(MTOOLS) \

File diff suppressed because it is too large Load diff

View file

@ -9,33 +9,30 @@
"icons.html": "node theme_icons.js" "icons.html": "node theme_icons.js"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.26.0", "@eslint/js": "^9.27.0",
"copy-webpack-plugin": "^13.0.0", "copy-webpack-plugin": "^13.0.0",
"css-loader": "^7.1.2", "css-loader": "^7.1.2",
"edge.js": "^6.2.1", "edge.js": "^6.2.1",
"eslint": "^9.26.0", "eslint": "^9.27.0",
"filemanager-webpack-plugin": "^8.0.0", "filemanager-webpack-plugin": "^8.0.0",
"globals": "^16.1.0", "globals": "^16.2.0",
"ionicons": "^8.0.8", "ionicons": "^8.0.8",
"leaflet": "^1.9.4", "leaflet": "^1.9.4",
"less": "^4.3.0", "less": "^4.3.0",
"less-loader": "^12.3.0", "less-loader": "^12.3.0",
"normalize.css": "^8.0.1", "normalize.css": "^8.0.1",
"sharp": "^0.34.1", "sharp": "^0.34.2",
"style-loader": "^4.0.0", "style-loader": "^4.0.0",
"stylelint": "^16.19.1", "stylelint": "^16.20.0",
"stylelint-config-standard": "^38.0.0", "stylelint-config-standard": "^38.0.0",
"stylelint-config-standard-less": "^3.0.1", "stylelint-config-standard-less": "^3.0.1",
"stylelint-prettier": "^5.0.3", "stylelint-prettier": "^5.0.3",
"svgo": "^3.3.2", "svgo": "^3.3.2",
"swiped-events": "^1.2.0", "swiped-events": "^1.2.0",
"vite": "^6.3.5", "vite": "^6.3.5",
"vite-plugin-static-copy": "^2.3.1", "vite-plugin-static-copy": "^3.0.0",
"vite-plugin-stylelint": "^6.0.0", "vite-plugin-stylelint": "^6.0.0",
"webpack": "^5.99.8", "webpack": "^5.99.9",
"webpack-cli": "^6.0.1" "webpack-cli": "^6.0.1"
},
"dependencies": {
"autocomplete-js": "^2.7.1"
} }
} }

View file

@ -1,14 +1,13 @@
/* SPDX-License-Identifier: AGPL-3.0-or-later */ /* SPDX-License-Identifier: AGPL-3.0-or-later */
/* exported AutoComplete */ /* exported AutoComplete */
import AutoComplete from "../../../node_modules/autocomplete-js/dist/autocomplete.js";
(function (w, d, searxng) { (function (w, d, searxng) {
'use strict'; 'use strict';
var qinput_id = "q", qinput; var qinput_id = "q", qinput;
const isMobile = window.matchMedia("only screen and (max-width: 50em)").matches; const isMobile = window.matchMedia("only screen and (max-width: 50em)").matches;
const isResultsPage = document.querySelector("main").id == "main_results";
function submitIfQuery () { function submitIfQuery () {
if (qinput.value.length > 0) { if (qinput.value.length > 0) {
@ -38,8 +37,62 @@ import AutoComplete from "../../../node_modules/autocomplete-js/dist/autocomple
qinput.addEventListener('input', updateClearButton, false); qinput.addEventListener('input', updateClearButton, false);
} }
const fetchResults = async (query) => {
let request;
if (searxng.settings.method === 'GET') {
const reqParams = new URLSearchParams();
reqParams.append("q", query);
request = fetch("./autocompleter?" + reqParams.toString());
} else {
const formData = new FormData();
formData.append("q", query);
request = fetch("./autocompleter", {
method: 'POST',
body: formData,
});
}
request.then(async function (response) {
const results = await response.json();
if (!results) return;
const autocomplete = d.querySelector(".autocomplete");
const autocompleteList = d.querySelector(".autocomplete ul");
autocomplete.classList.add("open");
autocompleteList.innerHTML = "";
// show an error message that no result was found
if (!results[1] || results[1].length == 0) {
const noItemFoundMessage = document.createElement("li");
noItemFoundMessage.classList.add('no-item-found');
noItemFoundMessage.innerHTML = searxng.settings.translations.no_item_found;
autocompleteList.appendChild(noItemFoundMessage);
return;
}
for (let result of results[1]) {
const li = document.createElement("li");
li.innerText = result;
searxng.on(li, 'mousedown', () => {
qinput.value = result;
const form = d.querySelector("#search");
form.submit();
autocomplete.classList.remove('open');
});
autocompleteList.appendChild(li);
}
});
};
searxng.ready(function () { searxng.ready(function () {
// focus search input on large screens
if (!isMobile && !isResultsPage) document.getElementById("q").focus();
qinput = d.getElementById(qinput_id); qinput = d.getElementById(qinput_id);
const autocomplete = d.querySelector(".autocomplete");
const autocompleteList = d.querySelector(".autocomplete ul");
if (qinput !== null) { if (qinput !== null) {
// clear button // clear button
@ -47,109 +100,45 @@ import AutoComplete from "../../../node_modules/autocomplete-js/dist/autocomple
// autocompleter // autocompleter
if (searxng.settings.autocomplete) { if (searxng.settings.autocomplete) {
searxng.autocomplete = AutoComplete.call(w, { searxng.on(qinput, 'input', () => {
Url: "./autocompleter", const query = qinput.value;
EmptyMessage: searxng.settings.translations.no_item_found, if (query.length < searxng.settings.autocomplete_min) return;
HttpMethod: searxng.settings.method,
HttpHeaders: { setTimeout(() => {
"Content-type": "application/x-www-form-urlencoded", if (query == qinput.value) fetchResults(query);
"X-Requested-With": "XMLHttpRequest" }, 300);
}, });
MinChars: searxng.settings.autocomplete_min,
Delay: 300, searxng.on(qinput, 'keyup', (e) => {
_Position: function () {}, let currentIndex = -1;
_Open: function () { const listItems = autocompleteList.children;
var params = this; for (let i = 0; i < listItems.length; i++) {
Array.prototype.forEach.call(this.DOMResults.getElementsByTagName("li"), function (li) { if (listItems[i].classList.contains('active')) {
if (li.getAttribute("class") != "locked") { currentIndex = i;
li.onmousedown = function () { break;
params._Select(li);
};
}
});
},
_Select: function (item) {
AutoComplete.defaults._Select.call(this, item);
var form = item.closest('form');
if (form) {
form.submit();
} }
},
_MinChars: function () {
if (this.Input.value.indexOf('!') > -1) {
return 0;
} else {
return AutoComplete.defaults._MinChars.call(this);
}
},
KeyboardMappings: Object.assign({}, AutoComplete.defaults.KeyboardMappings, {
"KeyUpAndDown_up": Object.assign({}, AutoComplete.defaults.KeyboardMappings.KeyUpAndDown_up, {
Callback: function (event) {
AutoComplete.defaults.KeyboardMappings.KeyUpAndDown_up.Callback.call(this, event);
var liActive = this.DOMResults.querySelector("li.active");
if (liActive) {
AutoComplete.defaults._Select.call(this, liActive);
}
},
}),
"Tab": Object.assign({}, AutoComplete.defaults.KeyboardMappings.Enter, {
Conditions: [{
Is: 9,
Not: false
}],
Callback: function (event) {
if (this.DOMResults.getAttribute("class").indexOf("open") != -1) {
var liActive = this.DOMResults.querySelector("li.active");
if (liActive !== null) {
AutoComplete.defaults._Select.call(this, liActive);
event.preventDefault();
}
}
},
})
}),
}, "#" + qinput_id);
}
/*
Monkey patch autocomplete.js to fix a bug
With the POST method, the values are not URL encoded: query like "1 + 1" are sent as "1 1" since space are URL encoded as plus.
See HTML specifications:
* HTML5: https://url.spec.whatwg.org/#concept-urlencoded-serializer
* HTML4: https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1
autocomplete.js does not URL encode the name and values:
https://github.com/autocompletejs/autocomplete.js/blob/87069524f3b95e68f1b54d8976868e0eac1b2c83/src/autocomplete.ts#L665
The monkey patch overrides the compiled version of the ajax function.
See https://github.com/autocompletejs/autocomplete.js/blob/87069524f3b95e68f1b54d8976868e0eac1b2c83/dist/autocomplete.js#L143-L158
The patch changes only the line 156 from
params.Request.send(params._QueryArg() + "=" + params._Pre());
to
params.Request.send(encodeURIComponent(params._QueryArg()) + "=" + encodeURIComponent(params._Pre()));
Related to:
* https://github.com/autocompletejs/autocomplete.js/issues/78
* https://github.com/searxng/searxng/issues/1695
*/
AutoComplete.prototype.ajax = function (params, request, timeout) {
if (timeout === void 0) { timeout = true; }
if (params.$AjaxTimer) {
window.clearTimeout(params.$AjaxTimer);
}
if (timeout === true) {
params.$AjaxTimer = window.setTimeout(AutoComplete.prototype.ajax.bind(null, params, request, false), params.Delay);
} else {
if (params.Request) {
params.Request.abort();
} }
params.Request = request;
params.Request.send(encodeURIComponent(params._QueryArg()) + "=" + encodeURIComponent(params._Pre()));
}
};
if (!isMobile && document.querySelector('.index_endpoint')) { let newCurrentIndex = -1;
qinput.focus(); if (e.key === "ArrowUp") {
if (currentIndex >= 0) listItems[currentIndex].classList.remove('active');
// we need to add listItems.length to the index calculation here because the JavaScript modulos
// operator doesn't work with negative numbers
newCurrentIndex = (currentIndex - 1 + listItems.length) % listItems.length;
} else if (e.key === "ArrowDown") {
if (currentIndex >= 0) listItems[currentIndex].classList.remove('active');
newCurrentIndex = (currentIndex + 1) % listItems.length;
} else if (e.key === "Tab" || e.key === "Enter") {
autocomplete.classList.remove('open');
}
if (newCurrentIndex != -1) {
const selectedItem = listItems[newCurrentIndex];
selectedItem.classList.add('active');
if (!selectedItem.classList.contains('no-item-found')) qinput.value = selectedItem.innerText;
}
});
} }
} }
@ -184,7 +173,7 @@ import AutoComplete from "../../../node_modules/autocomplete-js/dist/autocomple
categoryButton.classList.remove("selected"); categoryButton.classList.remove("selected");
} }
button.classList.add("selected"); button.classList.add("selected");
}) });
} }
// override form submit action to update the actually selected categories // override form submit action to update the actually selected categories

View file

@ -3,6 +3,7 @@
.autocomplete { .autocomplete {
position: absolute; position: absolute;
width: @search-width; width: @search-width;
max-width: calc(100% - 2 * @search-padding-horizontal);
max-height: 0; max-height: 0;
overflow-y: hidden; overflow-y: hidden;
.ltr-text-align-left(); .ltr-text-align-left();
@ -65,8 +66,6 @@
@media screen and (max-width: @phone) { @media screen and (max-width: @phone) {
.autocomplete { .autocomplete {
width: 100%;
> ul > li { > ul > li {
padding: 1rem; padding: 1rem;
} }

View file

@ -287,8 +287,9 @@
@results-image-row-height: 12rem; @results-image-row-height: 12rem;
@results-image-row-height-phone: 10rem; @results-image-row-height-phone: 10rem;
@search-width: 44rem; @search-width: 44rem;
// heigh of #search, see detail.less // height of #search, see detail.less
@search-height: 13rem; @search-height: 13rem;
@search-padding-horizontal: 0.5rem;
/// Device Size /// Device Size
/// @desktop > @tablet /// @desktop > @tablet

View file

@ -131,7 +131,7 @@ button.category_button {
} }
#search_view { #search_view {
padding: 0.5rem 0.3rem 0 0.5rem; padding: 0.5rem @search-padding-horizontal 0 @search-padding-horizontal;
grid-area: search; grid-area: search;
body.results_endpoint & { body.results_endpoint & {
@ -141,7 +141,8 @@ button.category_button {
.search_box { .search_box {
border-radius: 0.8rem; border-radius: 0.8rem;
width: @search-width; width: 100%;
max-width: @search-width;
display: inline-flex; display: inline-flex;
flex-direction: row; flex-direction: row;
white-space: nowrap; white-space: nowrap;
@ -291,8 +292,7 @@ html.no-js #clear_search.hide_if_nojs {
} }
.search_box { .search_box {
width: 98%; width: 100%;
display: flex;
} }
#q { #q {

View file

@ -1,14 +1,4 @@
FROM docker.io/library/python:3.13-slim AS builder FROM ghcr.io/searxng/base:searxng-builder AS builder
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
build-essential \
brotli \
# uwsgi
libpcre3-dev \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /usr/local/searxng/
COPY ./requirements.txt ./requirements.txt COPY ./requirements.txt ./requirements.txt
@ -19,38 +9,15 @@ RUN --mount=type=cache,id=pip,target=/root/.cache/pip python -m venv ./venv \
COPY ./searx/ ./searx/ COPY ./searx/ ./searx/
ARG TIMESTAMP_SETTINGS=0 ARG TIMESTAMP_SETTINGS="0"
ARG TIMESTAMP_UWSGI=0
RUN python -m compileall -q searx \ RUN python -m compileall -q searx \
&& touch -c --date=@$TIMESTAMP_SETTINGS ./searx/settings.yml \ && touch -c --date=@$TIMESTAMP_SETTINGS ./searx/settings.yml \
&& touch -c --date=@$TIMESTAMP_UWSGI ./container/uwsgi.ini \ && find ./searx/static \
&& find /usr/local/searxng/searx/static \ \( -name "*.html" -o -name "*.css" -o -name "*.js" -o -name "*.svg" -o -name "*.ttf" -o -name "*.eot" \) \
\( -name '*.html' -o -name '*.css' -o -name '*.js' -o -name '*.svg' -o -name '*.ttf' -o -name '*.eot' \) \
-type f -exec gzip -9 -k {} + -exec brotli --best {} + -type f -exec gzip -9 -k {} + -exec brotli --best {} +
ARG SEARXNG_UID=977 FROM ghcr.io/searxng/base:searxng AS dist
ARG SEARXNG_GID=977
RUN grep -m1 root /etc/group > /tmp/.searxng.group \
&& grep -m1 root /etc/passwd > /tmp/.searxng.passwd \
&& echo "searxng:x:$SEARXNG_GID:" >> /tmp/.searxng.group \
&& echo "searxng:x:$SEARXNG_UID:$SEARXNG_GID:searxng:/usr/local/searxng:/bin/bash" >> /tmp/.searxng.passwd
FROM docker.io/library/python:3.13-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
# healthcheck
wget \
# uwsgi
libpcre3 \
libxml2 \
mailcap \
&& rm -rf /var/lib/apt/lists/*
COPY --chown=root:root --from=builder /tmp/.searxng.passwd /etc/passwd
COPY --chown=root:root --from=builder /tmp/.searxng.group /etc/group
ARG LABEL_DATE="0001-01-01T00:00:00Z" ARG LABEL_DATE="0001-01-01T00:00:00Z"
ARG GIT_URL="unspecified" ARG GIT_URL="unspecified"
@ -58,37 +25,35 @@ ARG SEARXNG_GIT_VERSION="unspecified"
ARG LABEL_VCS_REF="unspecified" ARG LABEL_VCS_REF="unspecified"
ARG LABEL_VCS_URL="unspecified" ARG LABEL_VCS_URL="unspecified"
WORKDIR /usr/local/searxng/
COPY --chown=searxng:searxng --from=builder /usr/local/searxng/venv/ ./venv/ COPY --chown=searxng:searxng --from=builder /usr/local/searxng/venv/ ./venv/
COPY --chown=searxng:searxng --from=builder /usr/local/searxng/searx/ ./searx/ COPY --chown=searxng:searxng --from=builder /usr/local/searxng/searx/ ./searx/
COPY --chown=searxng:searxng ./container/ ./container/ COPY --chown=searxng:searxng ./container/config/ ./.template/
COPY --chown=searxng:searxng ./container/entrypoint.sh ./entrypoint.sh
ARG TIMESTAMP_UWSGI="0"
RUN touch -c --date=@$TIMESTAMP_UWSGI ./.template/uwsgi.ini
LABEL org.opencontainers.image.authors="searxng <$GIT_URL>" \ LABEL org.opencontainers.image.authors="searxng <$GIT_URL>" \
org.opencontainers.image.created=$LABEL_DATE \ org.opencontainers.image.created="$LABEL_DATE" \
org.opencontainers.image.description="A privacy-respecting, hackable metasearch engine" \ org.opencontainers.image.description="A privacy-respecting, hackable metasearch engine" \
org.opencontainers.image.documentation="https://github.com/searxng/searxng-docker" \ org.opencontainers.image.documentation="https://github.com/searxng/searxng-docker" \
org.opencontainers.image.licenses="AGPL-3.0-or-later" \ org.opencontainers.image.licenses="AGPL-3.0-or-later" \
org.opencontainers.image.revision=$LABEL_VCS_REF \ org.opencontainers.image.revision="$LABEL_VCS_REF" \
org.opencontainers.image.source=$LABEL_VCS_URL \ org.opencontainers.image.source="$LABEL_VCS_URL" \
org.opencontainers.image.title="searxng" \ org.opencontainers.image.title="searxng" \
org.opencontainers.image.url=$LABEL_VCS_URL \ org.opencontainers.image.url="$LABEL_VCS_URL" \
org.opencontainers.image.version=$SEARXNG_GIT_VERSION org.opencontainers.image.version="$SEARXNG_GIT_VERSION"
ENV CONFIG_PATH=/etc/searxng \ ENV SEARXNG_VERSION="$SEARXNG_GIT_VERSION" \
DATA_PATH=/var/cache/searxng INSTANCE_NAME="SearXNG" \
ENV SEARXNG_VERSION=$SEARXNG_GIT_VERSION \
INSTANCE_NAME=searxng \
AUTOCOMPLETE="" \ AUTOCOMPLETE="" \
BASE_URL="" \ BASE_URL="" \
BIND_ADDRESS=[::]:8080 \ BIND_ADDRESS="[::]:8080" \
MORTY_KEY="" \ SEARXNG_SETTINGS_PATH="$CONFIG_PATH/settings.yml" \
MORTY_URL="" \ UWSGI_SETTINGS_PATH="$CONFIG_PATH/uwsgi.ini" \
SEARXNG_SETTINGS_PATH=$CONFIG_PATH/settings.yml \ UWSGI_WORKERS="%k" \
UWSGI_SETTINGS_PATH=$CONFIG_PATH/uwsgi.ini \ UWSGI_THREADS="4"
UWSGI_WORKERS=%k \
UWSGI_THREADS=4
VOLUME $CONFIG_PATH VOLUME $CONFIG_PATH
VOLUME $DATA_PATH VOLUME $DATA_PATH
@ -97,4 +62,4 @@ EXPOSE 8080
HEALTHCHECK CMD wget --quiet --tries=1 --spider http://localhost:8080/healthz || exit 1 HEALTHCHECK CMD wget --quiet --tries=1 --spider http://localhost:8080/healthz || exit 1
ENTRYPOINT ["/usr/local/searxng/container/docker-entrypoint.sh"] ENTRYPOINT ["/usr/local/searxng/entrypoint.sh"]

View file

@ -0,0 +1,25 @@
contents:
keyring:
- https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
repositories:
- https://packages.wolfi.dev/os
packages:
- wolfi-base
- build-base
- python-3.13-dev
- py3-pip
- brotli
entrypoint:
command: /bin/sh -l
work-dir: /usr/local/searxng/
environment:
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt
HISTFILE: /dev/null
archs:
- x86_64
- aarch64

61
container/base.yml Normal file
View file

@ -0,0 +1,61 @@
contents:
keyring:
- https://packages.wolfi.dev/os/wolfi-signing.rsa.pub
repositories:
- https://packages.wolfi.dev/os
packages:
- wolfi-baselayout
- ca-certificates-bundle
- busybox
- python-3.13
# healthcheck
- wget
# uwsgi
- mailcap
entrypoint:
command: /bin/sh -l
work-dir: /usr/local/searxng/
accounts:
groups:
- groupname: searxng
gid: 977
users:
- username: searxng
uid: 977
shell: /bin/ash
environment:
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt
HISTFILE: /dev/null
CONFIG_PATH: /etc/searxng
DATA_PATH: /var/cache/searxng
paths:
# Workdir
- path: /usr/local/searxng/
type: directory
uid: 977
gid: 977
permissions: 0o755
# Config volume
- path: /etc/searxng/
type: directory
uid: 977
gid: 977
permissions: 0o755
# Data volume
- path: /var/cache/searxng/
type: directory
uid: 977
gid: 977
permissions: 0o755
archs:
- x86_64
- aarch64

View file

@ -1,126 +0,0 @@
#!/bin/sh
help() {
cat <<EOF
Command line:
-h Display this help
-d Dry run to update the configuration files.
-f Always update on the configuration files (existing files are renamed with
the .old suffix). Without this option, the new configuration files are
copied with the .new suffix
Environment variables:
INSTANCE_NAME settings.yml : general.instance_name
AUTOCOMPLETE settings.yml : search.autocomplete
BASE_URL settings.yml : server.base_url
Volume:
/etc/searxng the docker entry point copies settings.yml and uwsgi.ini in
this directory (see the -f command line option)"
EOF
}
# Parse command line
FORCE_CONF_UPDATE=0
DRY_RUN=0
while getopts "fdh" option
do
case $option in
f) FORCE_CONF_UPDATE=1 ;;
d) DRY_RUN=1 ;;
h)
help
exit 0
;;
*)
echo "unknow option ${option}"
exit 42
;;
esac
done
echo "SearXNG version $SEARXNG_VERSION"
# helpers to update the configuration files
patch_uwsgi_settings() {
CONF="$1"
# update uwsg.ini
sed -i \
-e "s|workers = .*|workers = ${UWSGI_WORKERS:-%k}|g" \
-e "s|threads = .*|threads = ${UWSGI_THREADS:-4}|g" \
"${CONF}"
}
patch_searxng_settings() {
CONF="$1"
# Make sure that there is trailing slash at the end of BASE_URL
# see https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameter-Expansion
export BASE_URL="${BASE_URL%/}/"
# update settings.yml
sed -i \
-e "s|base_url: false|base_url: ${BASE_URL}|g" \
-e "s/instance_name: \"SearXNG\"/instance_name: \"${INSTANCE_NAME}\"/g" \
-e "s/autocomplete: \"\"/autocomplete: \"${AUTOCOMPLETE}\"/g" \
-e "s/ultrasecretkey/$(head -c 24 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9')/g" \
"${CONF}"
}
update_conf() {
FORCE_CONF_UPDATE=$1
CONF="$2"
NEW_CONF="${2}.new"
OLD_CONF="${2}.old"
REF_CONF="$3"
PATCH_REF_CONF="$4"
if [ -f "${CONF}" ]; then
if [ "${REF_CONF}" -nt "${CONF}" ]; then
# There is a new version
if [ "$FORCE_CONF_UPDATE" -ne 0 ]; then
# Replace the current configuration
printf '⚠️ Automatically update %s to the new version\n' "${CONF}"
if [ ! -f "${OLD_CONF}" ]; then
printf 'The previous configuration is saved to %s\n' "${OLD_CONF}"
mv "${CONF}" "${OLD_CONF}"
fi
cp "${REF_CONF}" "${CONF}"
$PATCH_REF_CONF "${CONF}"
else
# Keep the current configuration
printf '⚠️ Check new version %s to make sure SearXNG is working properly\n' "${NEW_CONF}"
cp "${REF_CONF}" "${NEW_CONF}"
$PATCH_REF_CONF "${NEW_CONF}"
fi
else
printf 'Use existing %s\n' "${CONF}"
fi
else
printf 'Create %s\n' "${CONF}"
cp "${REF_CONF}" "${CONF}"
$PATCH_REF_CONF "${CONF}"
fi
}
# make sure there are uwsgi settings
update_conf "${FORCE_CONF_UPDATE}" "${UWSGI_SETTINGS_PATH}" "/usr/local/searxng/container/uwsgi.ini" "patch_uwsgi_settings"
# make sure there are searxng settings
update_conf "${FORCE_CONF_UPDATE}" "${SEARXNG_SETTINGS_PATH}" "/usr/local/searxng/searx/settings.yml" "patch_searxng_settings"
# dry run (to update configuration files, then inspect them)
if [ $DRY_RUN -eq 1 ]; then
printf 'Dry run\n'
exit
fi
printf 'Listen on %s\n' "${BIND_ADDRESS}"
# Start uwsgi
# TODO: "--http-socket" will be removed in the future (see uwsgi.ini.new config file): https://github.com/searxng/searxng/pull/4578
exec /usr/local/searxng/venv/bin/uwsgi --http-socket "${BIND_ADDRESS}" "${UWSGI_SETTINGS_PATH}"

166
container/entrypoint.sh Executable file
View file

@ -0,0 +1,166 @@
#!/bin/sh
# shellcheck shell=dash
set -u
check_file() {
local target="$1"
if [ ! -f "$target" ]; then
cat <<EOF
!!!
!!! ERROR
!!! "$target" is not a valid file, exiting...
!!!
EOF
exit 127
fi
}
check_directory() {
local target="$1"
if [ ! -d "$target" ]; then
cat <<EOF
!!!
!!! ERROR
!!! "$target" is not a valid directory, exiting...
!!!
EOF
exit 127
fi
}
setup_ownership() {
local target="$1"
local type="$2"
case "$type" in
file | directory) ;;
*)
cat <<EOF
!!!
!!! ERROR
!!! "$type" is not a valid type, exiting...
!!!
EOF
exit 1
;;
esac
if [ "$(stat -c %U:%G "$target")" != "searxng:searxng" ]; then
if [ "$(id -u)" -eq 0 ]; then
chown -R searxng:searxng "$target"
else
cat <<EOF
!!!
!!! WARNING
!!! "$target" $type is not owned by "searxng"
!!! This may cause issues when running SearXNG
!!!
!!! Run the container as root to fix this issue automatically
!!! Alternatively, you can chown the $type manually:
!!! $ chown -R searxng:searxng "$target"
!!!
EOF
fi
fi
}
# Apply envs to uwsgi.ini
setup_uwsgi() {
local timestamp
timestamp=$(stat -c %Y "$UWSGI_SETTINGS_PATH")
sed -i \
-e "s|workers = .*|workers = ${UWSGI_WORKERS:-%k}|g" \
-e "s|threads = .*|threads = ${UWSGI_THREADS:-4}|g" \
"$UWSGI_SETTINGS_PATH"
# Restore timestamp
touch -c -d "@$timestamp" "$UWSGI_SETTINGS_PATH"
}
# Apply envs to settings.yml
setup_searxng() {
local timestamp
timestamp=$(stat -c %Y "$SEARXNG_SETTINGS_PATH")
# Ensure trailing slash in BASE_URL
# https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameter-Expansion
export BASE_URL="${BASE_URL%/}/"
sed -i \
-e "s|base_url: false|base_url: ${BASE_URL:-false}|g" \
-e "s/instance_name: \"SearXNG\"/instance_name: \"${INSTANCE_NAME:-SearXNG}\"/g" \
-e "s/autocomplete: \"\"/autocomplete: \"${AUTOCOMPLETE:-}\"/g" \
-e "s/ultrasecretkey/$(head -c 24 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9')/g" \
"$SEARXNG_SETTINGS_PATH"
# Restore timestamp
touch -c -d "@$timestamp" "$SEARXNG_SETTINGS_PATH"
}
# Handle volume mounts
volume_handler() {
local target="$1"
# Check if it's a valid directory
check_directory "$target"
setup_ownership "$target" "directory"
}
# Handle configuration file updates
config_handler() {
local target="$1"
local template="$2"
local new_template_target="$target.new"
# Create/Update the configuration file
if [ -f "$target" ]; then
setup_ownership "$target" "file"
if [ "$template" -nt "$target" ]; then
cp -pfT "$template" "$new_template_target"
cat <<EOF
...
... INFORMATION
... Update available for "$target"
... It is recommended to update the configuration file to ensure proper functionality
...
... New version placed at "$new_template_target"
... Please review and merge changes
...
EOF
fi
else
cat <<EOF
...
... INFORMATION
... "$target" does not exist, creating from template...
...
EOF
cp -pfT "$template" "$target"
fi
# Check if it's a valid file
check_file "$target"
}
echo "SearXNG $SEARXNG_VERSION"
# Check for volume mounts
volume_handler "$CONFIG_PATH"
volume_handler "$DATA_PATH"
# Check for updates in files
config_handler "$UWSGI_SETTINGS_PATH" "/usr/local/searxng/.template/uwsgi.ini"
config_handler "$SEARXNG_SETTINGS_PATH" "/usr/local/searxng/searx/settings.yml"
# Update files
setup_uwsgi
setup_searxng
exec /usr/local/searxng/venv/bin/uwsgi --http-socket "$BIND_ADDRESS" "$UWSGI_SETTINGS_PATH"

View file

@ -1,5 +1,3 @@
# For armv7 architecture
FROM docker.io/library/python:3.13-slim AS builder FROM docker.io/library/python:3.13-slim AS builder
RUN apt-get update \ RUN apt-get update \
@ -26,11 +24,9 @@ RUN --mount=type=cache,id=pip,target=/root/.cache/pip python -m venv ./venv \
COPY ./searx/ ./searx/ COPY ./searx/ ./searx/
ARG TIMESTAMP_SETTINGS=0 ARG TIMESTAMP_SETTINGS=0
ARG TIMESTAMP_UWSGI=0
RUN python -m compileall -q searx \ RUN python -m compileall -q searx \
&& touch -c --date=@$TIMESTAMP_SETTINGS ./searx/settings.yml \ && touch -c --date=@$TIMESTAMP_SETTINGS ./searx/settings.yml \
&& touch -c --date=@$TIMESTAMP_UWSGI ./container/uwsgi.ini \
&& find /usr/local/searxng/searx/static \ && find /usr/local/searxng/searx/static \
\( -name '*.html' -o -name '*.css' -o -name '*.js' -o -name '*.svg' -o -name '*.ttf' -o -name '*.eot' \) \ \( -name '*.html' -o -name '*.css' -o -name '*.js' -o -name '*.svg' -o -name '*.ttf' -o -name '*.eot' \) \
-type f -exec gzip -9 -k {} + -exec brotli --best {} + -type f -exec gzip -9 -k {} + -exec brotli --best {} +
@ -70,7 +66,12 @@ WORKDIR /usr/local/searxng/
COPY --chown=searxng:searxng --from=builder /usr/local/searxng/venv/ ./venv/ COPY --chown=searxng:searxng --from=builder /usr/local/searxng/venv/ ./venv/
COPY --chown=searxng:searxng --from=builder /usr/local/searxng/searx/ ./searx/ COPY --chown=searxng:searxng --from=builder /usr/local/searxng/searx/ ./searx/
COPY --chown=searxng:searxng ./container/ ./container/ COPY --chown=searxng:searxng ./container/config/ ./.template/
COPY --chown=searxng:searxng ./container/entrypoint.sh ./entrypoint.sh
ARG TIMESTAMP_UWSGI="0"
RUN touch -c --date=@$TIMESTAMP_UWSGI ./.template/uwsgi.ini
LABEL org.opencontainers.image.authors="searxng <$GIT_URL>" \ LABEL org.opencontainers.image.authors="searxng <$GIT_URL>" \
org.opencontainers.image.created=$LABEL_DATE \ org.opencontainers.image.created=$LABEL_DATE \
@ -103,4 +104,4 @@ EXPOSE 8080
HEALTHCHECK CMD wget --quiet --tries=1 --spider http://localhost:8080/healthz || exit 1 HEALTHCHECK CMD wget --quiet --tries=1 --spider http://localhost:8080/healthz || exit 1
ENTRYPOINT ["/usr/local/searxng/container/docker-entrypoint.sh"] ENTRYPOINT ["/usr/local/searxng/entrypoint.sh"]

View file

@ -181,10 +181,10 @@ Command line
<https://docs.docker.com/engine/reference/run/#foreground>`__. <https://docs.docker.com/engine/reference/run/#foreground>`__.
In the :origin:`Dockerfile` the ENTRYPOINT_ is defined as In the :origin:`Dockerfile` the ENTRYPOINT_ is defined as
:origin:`container/docker-entrypoint.sh` :origin:`container/entrypoint.sh`
.. code:: sh .. code:: sh
docker run --rm -it searxng/searxng -h docker run --rm -it searxng/searxng -h
.. program-output:: ../container/docker-entrypoint.sh -h .. program-output:: ../container/entrypoint.sh -h

View file

@ -41,6 +41,7 @@
- ``duckduckgo`` - ``duckduckgo``
- ``google`` - ``google``
- ``mwmbl`` - ``mwmbl``
- ``naver``
- ``quark`` - ``quark``
- ``qwant`` - ``qwant``
- ``seznam`` - ``seznam``

View file

@ -4,7 +4,7 @@ cov-core==1.15.0
black==24.3.0 black==24.3.0
pylint==3.3.7 pylint==3.3.7
splinter==0.21.0 splinter==0.21.0
selenium==4.32.0 selenium==4.33.0
Pallets-Sphinx-Themes==2.3.0 Pallets-Sphinx-Themes==2.3.0
Sphinx==7.4.7 Sphinx==7.4.7
sphinx-issues==5.0.1 sphinx-issues==5.0.1

View file

@ -7,15 +7,15 @@ lxml==5.4.0
pygments==2.19.1 pygments==2.19.1
python-dateutil==2.9.0.post0 python-dateutil==2.9.0.post0
pyyaml==6.0.2 pyyaml==6.0.2
httpx[http2]==0.24.1 httpx[http2]==0.28.1
httpx-socks[asyncio]==0.10.0
Brotli==1.1.0 Brotli==1.1.0
uvloop==0.21.0 uvloop==0.21.0
httpx-socks[asyncio]==0.7.7
setproctitle==1.3.6 setproctitle==1.3.6
redis==5.2.1 redis==5.2.1
markdown-it-py==3.0.0 markdown-it-py==3.0.0
fasttext-predict==0.9.2.4 fasttext-predict==0.9.2.4
tomli==2.2.1; python_version < '3.11' tomli==2.2.1; python_version < '3.11'
msgspec==0.19.0 msgspec==0.19.0
typer-slim==0.15.3 typer-slim==0.16.0
isodate==0.7.2 isodate==0.7.2

View file

@ -21,7 +21,7 @@ log: logging.Logger = logging.getLogger("searx.answerers")
@dataclass @dataclass
class AnswererInfo: class AnswererInfo:
"""Object that holds informations about an answerer, these infos are shown """Object that holds information about an answerer, these infos are shown
to the user in the Preferences menu. to the user in the Preferences menu.
To be able to translate the information into other languages, the text must To be able to translate the information into other languages, the text must
@ -53,7 +53,7 @@ class Answerer(abc.ABC):
@abc.abstractmethod @abc.abstractmethod
def info(self) -> AnswererInfo: def info(self) -> AnswererInfo:
"""Informations about the *answerer*, see :py:obj:`AnswererInfo`.""" """Information about the *answerer*, see :py:obj:`AnswererInfo`."""
class ModuleAnswerer(Answerer): class ModuleAnswerer(Answerer):

View file

@ -149,6 +149,21 @@ def mwmbl(query, _lang):
return [result for result in results if not result.startswith("go: ") and not result.startswith("search: ")] return [result for result in results if not result.startswith("go: ") and not result.startswith("search: ")]
def naver(query, _lang):
# Naver search autocompleter
url = f"https://ac.search.naver.com/nx/ac?{urlencode({'q': query, 'r_format': 'json', 'st': 0})}"
response = get(url)
results = []
if response.ok:
data = response.json()
if data.get('items'):
for item in data['items'][0]:
results.append(item[0])
return results
def qihu360search(query, _lang): def qihu360search(query, _lang):
# 360Search search autocompleter # 360Search search autocompleter
url = f"https://sug.so.360.cn/suggest?{urlencode({'format': 'json', 'word': query})}" url = f"https://sug.so.360.cn/suggest?{urlencode({'format': 'json', 'word': query})}"
@ -300,6 +315,7 @@ backends = {
'duckduckgo': duckduckgo, 'duckduckgo': duckduckgo,
'google': google_complete, 'google': google_complete,
'mwmbl': mwmbl, 'mwmbl': mwmbl,
'naver': naver,
'quark': quark, 'quark': quark,
'qwant': qwant, 'qwant': qwant,
'seznam': seznam, 'seznam': seznam,

View file

@ -319,9 +319,9 @@ def dict_deepupdate(base_dict: dict, upd_dict: dict, names=None):
""" """
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
if not isinstance(base_dict, dict): if not isinstance(base_dict, dict):
raise TypeError("argument 'base_dict' is not a ditionary type") raise TypeError("argument 'base_dict' is not a dictionary type")
if not isinstance(upd_dict, dict): if not isinstance(upd_dict, dict):
raise TypeError("argument 'upd_dict' is not a ditionary type") raise TypeError("argument 'upd_dict' is not a dictionary type")
if names is None: if names is None:
names = [] names = []

View file

@ -42,7 +42,7 @@ class ExpireCacheCfg(msgspec.Struct): # pylint: disable=too-few-public-methods
DB will be created in `/tmp/sxng_cache_{self.name}.db`""" DB will be created in `/tmp/sxng_cache_{self.name}.db`"""
MAX_VALUE_LEN: int = 1024 * 10 MAX_VALUE_LEN: int = 1024 * 10
"""Max lenght of a *serialized* value.""" """Max length of a *serialized* value."""
MAXHOLD_TIME: int = 60 * 60 * 24 * 7 # 7 days MAXHOLD_TIME: int = 60 * 60 * 24 * 7 # 7 days
"""Hold time (default in sec.), after which a value is removed from the cache.""" """Hold time (default in sec.), after which a value is removed from the cache."""
@ -80,7 +80,7 @@ class ExpireCacheCfg(msgspec.Struct): # pylint: disable=too-few-public-methods
@dataclasses.dataclass @dataclasses.dataclass
class ExpireCacheStats: class ExpireCacheStats:
"""Dataclass wich provides information on the status of the cache.""" """Dataclass which provides information on the status of the cache."""
cached_items: dict[str, list[tuple[str, typing.Any, int]]] cached_items: dict[str, list[tuple[str, typing.Any, int]]]
"""Values in the cache mapped by context name. """Values in the cache mapped by context name.

View file

@ -4,29 +4,65 @@
make data.all make data.all
""" """
from __future__ import annotations
__all__ = [ __all__ = ["ahmia_blacklist_loader"]
'ENGINE_TRAITS',
'CURRENCIES',
'USER_AGENTS',
'EXTERNAL_URLS',
'WIKIDATA_UNITS',
'EXTERNAL_BANGS',
'OSM_KEYS_TAGS',
'ENGINE_DESCRIPTIONS',
'LOCALES',
'ahmia_blacklist_loader',
]
import json import json
from pathlib import Path import typing
data_dir = Path(__file__).parent from .core import log, data_dir
from .currencies import CurrenciesDB
CURRENCIES: CurrenciesDB
USER_AGENTS: dict[str, typing.Any]
EXTERNAL_URLS: dict[str, typing.Any]
WIKIDATA_UNITS: dict[str, typing.Any]
EXTERNAL_BANGS: dict[str, typing.Any]
OSM_KEYS_TAGS: dict[str, typing.Any]
ENGINE_DESCRIPTIONS: dict[str, typing.Any]
ENGINE_TRAITS: dict[str, typing.Any]
LOCALES: dict[str, typing.Any]
lazy_globals = {
"CURRENCIES": CurrenciesDB(),
"USER_AGENTS": None,
"EXTERNAL_URLS": None,
"WIKIDATA_UNITS": None,
"EXTERNAL_BANGS": None,
"OSM_KEYS_TAGS": None,
"ENGINE_DESCRIPTIONS": None,
"ENGINE_TRAITS": None,
"LOCALES": None,
}
data_json_files = {
"USER_AGENTS": "useragents.json",
"EXTERNAL_URLS": "external_urls.json",
"WIKIDATA_UNITS": "wikidata_units.json",
"EXTERNAL_BANGS": "external_bangs.json",
"OSM_KEYS_TAGS": "osm_keys_tags.json",
"ENGINE_DESCRIPTIONS": "engine_descriptions.json",
"ENGINE_TRAITS": "engine_traits.json",
"LOCALES": "locales.json",
}
def _load(filename): def __getattr__(name):
with open(data_dir / filename, encoding='utf-8') as f: # lazy init of the global objects
return json.load(f) if name not in lazy_globals:
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
data = lazy_globals[name]
if data is not None:
return data
log.debug("init searx.data.%s", name)
with open(data_dir / data_json_files[name], encoding='utf-8') as f:
lazy_globals[name] = json.load(f)
return lazy_globals[name]
def ahmia_blacklist_loader(): def ahmia_blacklist_loader():
@ -40,14 +76,3 @@ def ahmia_blacklist_loader():
""" """
with open(data_dir / 'ahmia_blacklist.txt', encoding='utf-8') as f: with open(data_dir / 'ahmia_blacklist.txt', encoding='utf-8') as f:
return f.read().split() return f.read().split()
CURRENCIES = _load('currencies.json')
USER_AGENTS = _load('useragents.json')
EXTERNAL_URLS = _load('external_urls.json')
WIKIDATA_UNITS = _load('wikidata_units.json')
EXTERNAL_BANGS = _load('external_bangs.json')
OSM_KEYS_TAGS = _load('osm_keys_tags.json')
ENGINE_DESCRIPTIONS = _load('engine_descriptions.json')
ENGINE_TRAITS = _load('engine_traits.json')
LOCALES = _load('locales.json')

File diff suppressed because it is too large Load diff

29
searx/data/core.py Normal file
View file

@ -0,0 +1,29 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# pylint: disable=missing-module-docstring
from __future__ import annotations
import pathlib
from searx import logger
from searx.cache import ExpireCacheCfg, ExpireCacheSQLite
log = logger.getChild("data")
data_dir = pathlib.Path(__file__).parent
_DATA_CACHE: ExpireCacheSQLite = None # type: ignore
def get_cache():
global _DATA_CACHE # pylint: disable=global-statement
if _DATA_CACHE is None:
_DATA_CACHE = ExpireCacheSQLite.build_cache(
ExpireCacheCfg(
name="DATA_CACHE",
# MAX_VALUE_LEN=1024 * 200, # max. 200kB length for a *serialized* value.
# MAXHOLD_TIME=60 * 60 * 24 * 7 * 4, # 4 weeks
)
)
return _DATA_CACHE

View file

@ -1428,7 +1428,7 @@
}, },
"CZK": { "CZK": {
"ar": "كرونة تشيكية", "ar": "كرونة تشيكية",
"bg": "крони", "bg": "Чешка крона",
"bn": "চেক কোরুনা", "bn": "চেক কোরুনা",
"ca": "corona txeca", "ca": "corona txeca",
"cs": "koruna česká", "cs": "koruna česká",
@ -2687,7 +2687,7 @@
"uk": "Йорданський динар" "uk": "Йорданський динар"
}, },
"JPY": { "JPY": {
"af": "Jen", "af": "jen",
"ar": "ين ياباني", "ar": "ين ياباني",
"bg": "японска йена", "bg": "японска йена",
"bn": "জাপানি ইয়েন", "bn": "জাপানি ইয়েন",
@ -4329,7 +4329,7 @@
"PLN": { "PLN": {
"af": "Złoty", "af": "Złoty",
"ar": "زواتي بولندي", "ar": "زواتي بولندي",
"bg": "Полска злотаПолска злота", "bg": "Полска злота",
"ca": "złoty", "ca": "złoty",
"cs": "zlotý", "cs": "zlotý",
"da": "zloty", "da": "zloty",
@ -4375,7 +4375,7 @@
"PLZ": { "PLZ": {
"af": "Złoty", "af": "Złoty",
"ar": "زواتي بولندي", "ar": "زواتي بولندي",
"bg": "Полска злотаПолска злота", "bg": "Полска злота",
"ca": "złoty", "ca": "złoty",
"cs": "zlotý", "cs": "zlotý",
"da": "zloty", "da": "zloty",
@ -5881,6 +5881,10 @@
"tt": "самоа таласы", "tt": "самоа таласы",
"uk": "Самоанська тала" "uk": "Самоанська тала"
}, },
"XAD": {
"en": "Arab accounting dinar",
"fr": "dinar arabe"
},
"XAF": { "XAF": {
"ar": "فرنك وسط إفريقي", "ar": "فرنك وسط إفريقي",
"bg": "Централноафрикански CFA франк", "bg": "Централноафрикански CFA франк",
@ -6375,6 +6379,7 @@
"$usd": "USD", "$usd": "USD",
"1000 lira": "LBP", "1000 lira": "LBP",
"100ドル紙幣": "NIO", "100ドル紙幣": "NIO",
"1億ベネズエラ・ボリバル": "VES",
"2019 zimbabwean dollar": "ZWL", "2019 zimbabwean dollar": "ZWL",
"5th zimbabwean dollar": "ZWL", "5th zimbabwean dollar": "ZWL",
"A$": "AUD", "A$": "AUD",
@ -6511,6 +6516,7 @@
"Z$": "ZWL", "Z$": "ZWL",
"ZK": "ZMW", "ZK": "ZMW",
"a$": "AUD", "a$": "AUD",
"aad": "XAD",
"abd doları": "USD", "abd doları": "USD",
"adb unit of account": "XUA", "adb unit of account": "XUA",
"ae92 0530 0000 1514 1185 002": "AED", "ae92 0530 0000 1514 1185 002": "AED",
@ -6610,6 +6616,7 @@
"aoa": "AOA", "aoa": "AOA",
"apvienotās karalistes sterliņu mārciņa": "GBP", "apvienotās karalistes sterliņu mārciņa": "GBP",
"ar": "MGA", "ar": "MGA",
"arab accounting dinar": "XAD",
"arabiemiraattien dirhami": "AED", "arabiemiraattien dirhami": "AED",
"arany mint befektetés": "XAU", "arany mint befektetés": "XAU",
"arg$": "ARS", "arg$": "ARS",
@ -7438,6 +7445,7 @@
"dinar algierski": "DZD", "dinar algierski": "DZD",
"dinar aljazair": "DZD", "dinar aljazair": "DZD",
"dinar alxeriano": "DZD", "dinar alxeriano": "DZD",
"dinar arabe": "XAD",
"dinar argelino": "DZD", "dinar argelino": "DZD",
"dinar bahrain": "BHD", "dinar bahrain": "BHD",
"dinar bahraini": "BHD", "dinar bahraini": "BHD",
@ -7458,6 +7466,7 @@
"dinar bhairéin": "BHD", "dinar bhairéin": "BHD",
"dinar chuáit": "KWD", "dinar chuáit": "KWD",
"dinar coaitiano": "KWD", "dinar coaitiano": "KWD",
"dinar comptable arabe": "XAD",
"dinar couaitiano": "KWD", "dinar couaitiano": "KWD",
"dinar covaitiano": "KWD", "dinar covaitiano": "KWD",
"dinar coveiteano": "KWD", "dinar coveiteano": "KWD",
@ -9162,7 +9171,6 @@
"jordán dinár": "JOD", "jordán dinár": "JOD",
"jordánsky dinár": "JOD", "jordánsky dinár": "JOD",
"jordánský dinár": "JOD", "jordánský dinár": "JOD",
"jpy": "JPY",
"juan": "CNY", "juan": "CNY",
"juanis": "CNY", "juanis": "CNY",
"juaņa": "CNY", "juaņa": "CNY",
@ -9813,7 +9821,6 @@
"livre de sainte hélène": "SHP", "livre de sainte hélène": "SHP",
"livre des îles falkland": "FKP", "livre des îles falkland": "FKP",
"livre des îles malouines": "FKP", "livre des îles malouines": "FKP",
"livre egyptienne": "EGP",
"livre égyptienne": "EGP", "livre égyptienne": "EGP",
"livre libanaise": "LBP", "livre libanaise": "LBP",
"livre soudanaise": "SDG", "livre soudanaise": "SDG",
@ -13367,7 +13374,6 @@
], ],
"крона чеська": "CZK", "крона чеська": "CZK",
"крона швеции": "SEK", "крона швеции": "SEK",
"крони": "CZK",
"куба писысы": "CUP", "куба писысы": "CUP",
"кубански пезос": "CUP", "кубански пезос": "CUP",
"кубански песо": "CUP", "кубански песо": "CUP",
@ -13645,10 +13651,6 @@
"PLZ", "PLZ",
"PLN" "PLN"
], ],
"полска злотаполска злота": [
"PLZ",
"PLN"
],
"польский злотый": [ "польский злотый": [
"PLZ", "PLZ",
"PLN" "PLN"

55
searx/data/currencies.py Normal file
View file

@ -0,0 +1,55 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""Simple implementation to store currencies data in a SQL database."""
from __future__ import annotations
__all__ = ["CurrenciesDB"]
import json
import pathlib
from .core import get_cache, log
class CurrenciesDB:
# pylint: disable=missing-class-docstring
ctx_names = "data_currencies_names"
ctx_iso4217 = "data_currencies_iso4217"
json_file = pathlib.Path(__file__).parent / "currencies.json"
def __init__(self):
self.cache = get_cache()
def init(self):
if self.cache.properties("currencies loaded") != "OK":
self.load()
self.cache.properties.set("currencies loaded", "OK")
# F I X M E:
# do we need a maintenance .. rember: database is stored
# in /tmp and will be rebuild during the reboot anyway
def load(self):
log.debug("init searx.data.CURRENCIES")
with open(self.json_file, encoding="utf-8") as f:
data_dict = json.load(f)
for key, value in data_dict["names"].items():
self.cache.set(key=key, value=value, ctx=self.ctx_names, expire=None)
for key, value in data_dict["iso4217"].items():
self.cache.set(key=key, value=value, ctx=self.ctx_iso4217, expire=None)
def name_to_iso4217(self, name):
self.init()
ret_val = self.cache.get(key=name, default=name, ctx=self.ctx_names)
if isinstance(ret_val, list):
# if more alternatives, use the last in the list
ret_val = ret_val[-1]
return ret_val
def iso4217_to_name(self, iso4217, language):
self.init()
iso4217_languages: dict = self.cache.get(key=iso4217, default={}, ctx=self.ctx_iso4217)
return iso4217_languages.get(language, iso4217)

File diff suppressed because one or more lines are too long

View file

@ -7381,7 +7381,6 @@
"ko": "korean", "ko": "korean",
"ks": "kashmiri", "ks": "kashmiri",
"ku": "kurdish", "ku": "kurdish",
"kw": "cornish",
"la": "latin", "la": "latin",
"lb": "luxembourgish", "lb": "luxembourgish",
"ln": "lingala", "ln": "lingala",

View file

@ -5,7 +5,7 @@
], ],
"ua": "Mozilla/5.0 ({os}; rv:{version}) Gecko/20100101 Firefox/{version}", "ua": "Mozilla/5.0 ({os}; rv:{version}) Gecko/20100101 Firefox/{version}",
"versions": [ "versions": [
"138.0", "139.0",
"137.0" "138.0"
] ]
} }

View file

@ -4199,11 +4199,6 @@
"symbol": "St", "symbol": "St",
"to_si_factor": 13450.0 "to_si_factor": 13450.0
}, },
"Q235729": {
"si_name": "Q11574",
"symbol": "y (365 days)",
"to_si_factor": 31536000.0
},
"Q23823681": { "Q23823681": {
"si_name": "Q25236", "si_name": "Q25236",
"symbol": "TW", "symbol": "TW",

View file

@ -79,7 +79,7 @@ class EngineCache:
<searx.cache.ExpireCacheSQLite>`). <searx.cache.ExpireCacheSQLite>`).
In the :origin:`searx/engines/demo_offline.py` engine you can find an In the :origin:`searx/engines/demo_offline.py` engine you can find an
exemplary implementation of such a cache other exaples are implemeted exemplary implementation of such a cache other examples are implemented
in: in:
- :origin:`searx/engines/radio_browser.py` - :origin:`searx/engines/radio_browser.py`

View file

@ -156,7 +156,7 @@ def parse_image_item(item):
def parse_video_item(item): def parse_video_item(item):
# in video items, the title is more or less a "content description", we try # in video items, the title is more or less a "content description", we try
# to reduce the lenght of the title .. # to reduce the length of the title ..
title = item["title"] title = item["title"]
content = "" content = ""

View file

@ -3,6 +3,7 @@
""" """
import json import json
from searx.result_types import EngineResults
# about # about
about = { about = {
@ -28,13 +29,15 @@ def request(_query, params):
return params return params
def response(resp): def response(resp) -> EngineResults:
res = EngineResults()
# remove first and last lines to get only json # remove first and last lines to get only json
json_resp = resp.text[resp.text.find('\n') + 1 : resp.text.rfind('\n') - 2] json_resp = resp.text[resp.text.find('\n') + 1 : resp.text.rfind('\n') - 2]
try: try:
conversion_rate = float(json.loads(json_resp)["to"][0]["mid"]) conversion_rate = float(json.loads(json_resp)["to"][0]["mid"])
except IndexError: except IndexError:
return [] return res
answer = '{0} {1} = {2} {3}, 1 {1} ({5}) = {4} {3} ({6})'.format( answer = '{0} {1} = {2} {3}, 1 {1} ({5}) = {4} {3} ({6})'.format(
resp.search_params['amount'], resp.search_params['amount'],
resp.search_params['from'], resp.search_params['from'],
@ -46,5 +49,5 @@ def response(resp):
) )
url = f"https://duckduckgo.com/?q={resp.search_params['from']}+to+{resp.search_params['to']}" url = f"https://duckduckgo.com/?q={resp.search_params['from']}+to+{resp.search_params['to']}"
res.add(res.types.Answer(answer=answer, url=url))
return [{"answer": answer, "url": url}] return res

View file

@ -58,19 +58,21 @@ paging = True
time_range_support = True time_range_support = True
safesearch = True # user can't select but the results are filtered safesearch = True # user can't select but the results are filtered
url = "https://html.duckduckgo.com/html" url = "https://html.duckduckgo.com/html/"
time_range_dict = {'day': 'd', 'week': 'w', 'month': 'm', 'year': 'y'} time_range_dict = {'day': 'd', 'week': 'w', 'month': 'm', 'year': 'y'}
form_data = {'v': 'l', 'api': 'd.js', 'o': 'json'} form_data = {'v': 'l', 'api': 'd.js', 'o': 'json'}
CACHE: EngineCache _CACHE: EngineCache = None # type: ignore
"""Persistent (SQLite) key/value cache that deletes its values after ``expire`` """Persistent (SQLite) key/value cache that deletes its values after ``expire``
seconds.""" seconds."""
def init(_): # pylint: disable=unused-argument def get_cache():
global CACHE # pylint: disable=global-statement global _CACHE # pylint: disable=global-statement
CACHE = EngineCache("duckduckgo") # type:ignore if _CACHE is None:
_CACHE = EngineCache("duckduckgo") # type:ignore
return _CACHE
def get_vqd(query: str, region: str, force_request: bool = False) -> str: def get_vqd(query: str, region: str, force_request: bool = False) -> str:
@ -105,8 +107,9 @@ def get_vqd(query: str, region: str, force_request: bool = False) -> str:
seems the block list is a sliding window: to get my IP rid from the bot list seems the block list is a sliding window: to get my IP rid from the bot list
I had to cool down my IP for 1h (send no requests from that IP to DDG). I had to cool down my IP for 1h (send no requests from that IP to DDG).
""" """
key = CACHE.secret_hash(f"{query}//{region}") cache = get_cache()
value = CACHE.get(key=key) key = cache.secret_hash(f"{query}//{region}")
value = cache.get(key=key)
if value is not None and not force_request: if value is not None and not force_request:
logger.debug("vqd: re-use cached value: %s", value) logger.debug("vqd: re-use cached value: %s", value)
return value return value
@ -124,15 +127,16 @@ def get_vqd(query: str, region: str, force_request: bool = False) -> str:
logger.error("vqd: got HTTP %s from duckduckgo.com", resp.status_code) logger.error("vqd: got HTTP %s from duckduckgo.com", resp.status_code)
if value: if value:
CACHE.set(key=key, value=value) cache.set(key=key, value=value)
else: else:
logger.error("vqd value from duckduckgo.com ", resp.status_code) logger.error("vqd value from duckduckgo.com ", resp.status_code)
return value return value
def set_vqd(query: str, region: str, value: str): def set_vqd(query: str, region: str, value: str):
key = CACHE.secret_hash(f"{query}//{region}") cache = get_cache()
CACHE.set(key=key, value=value, expire=3600) key = cache.secret_hash(f"{query}//{region}")
cache.set(key=key, value=value, expire=3600)
def get_ddg_lang(eng_traits: EngineTraits, sxng_locale, default='en_US'): def get_ddg_lang(eng_traits: EngineTraits, sxng_locale, default='en_US'):
@ -244,7 +248,6 @@ def quote_ddg_bangs(query):
def request(query, params): def request(query, params):
query = quote_ddg_bangs(query) query = quote_ddg_bangs(query)
if len(query) >= 500: if len(query) >= 500:
@ -252,93 +255,79 @@ def request(query, params):
params["url"] = None params["url"] = None
return return
# Advanced search syntax ends in CAPTCHA
# https://duckduckgo.com/duckduckgo-help-pages/results/syntax/
query = " ".join(
[
x.removeprefix("site:").removeprefix("intitle:").removeprefix("inurl:").removeprefix("filetype:")
for x in query.split()
]
)
eng_region: str = traits.get_region(params['searxng_locale'], traits.all_locale) # type: ignore eng_region: str = traits.get_region(params['searxng_locale'], traits.all_locale) # type: ignore
if eng_region == "wt-wt":
# https://html.duckduckgo.com/html sets an empty value for "all".
eng_region = ""
params['data']['kl'] = eng_region # Note: The API is reverse-engineered from DuckDuckGo's HTML webpage
params['cookies']['kl'] = eng_region # (https://html.duckduckgo.com/html/) and may be subject to additional bot detection mechanisms
# and breaking changes in the future.
#
# The params['data'] dictionary can have the following key parameters, in this order:
# - q (str): Search query string
# - b (str): Beginning parameter - empty string for first page requests
# - s (int): Search offset for pagination
# - nextParams (str): Continuation parameters from previous page response, typically empty
# - v (str): Typically 'l' for subsequent pages
# - o (str): Output format, typically 'json'
# - dc (int): Display count - value equal to offset (s) + 1
# - api (str): API endpoint identifier, typically 'd.js'
# - vqd (str): Validation query digest
# - kl (str): Keyboard language/region code (e.g., 'en-us')
# - df (str): Time filter, maps to values like 'd' (day), 'w' (week), 'm' (month), 'y' (year)
# eng_lang = get_ddg_lang(traits, params['searxng_locale'])
params['url'] = url
params['method'] = 'POST'
params['data']['q'] = query params['data']['q'] = query
# 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
# again and again ..
params['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
params['headers']['Sec-Fetch-Dest'] = "document"
params['headers']['Sec-Fetch-Mode'] = "navigate" # at least this one is used by ddg's bot detection
params['headers']['Sec-Fetch-Site'] = "same-origin"
params['headers']['Sec-Fetch-User'] = "?1"
# Form of the initial search page does have empty values in the form
if params['pageno'] == 1: if params['pageno'] == 1:
params['data']['b'] = "" params['data']['b'] = ""
elif params['pageno'] >= 2:
params['data']['df'] = '' offset = 10 + (params['pageno'] - 2) * 15 # Page 2 = 10, Page 3+ = 10 + n*15
if params['time_range'] in time_range_dict:
params['data']['df'] = time_range_dict[params['time_range']]
params['cookies']['df'] = time_range_dict[params['time_range']]
if params['pageno'] == 2:
# second page does have an offset of 20
offset = (params['pageno'] - 1) * 20
params['data']['s'] = offset params['data']['s'] = offset
params['data']['dc'] = offset + 1
elif params['pageno'] > 2:
# third and following pages do have an offset of 20 + n*50
offset = 20 + (params['pageno'] - 2) * 50
params['data']['s'] = offset
params['data']['dc'] = offset + 1
if params['pageno'] > 1:
# initial page does not have these additional data in the input form
params['data']['o'] = form_data.get('o', 'json')
params['data']['api'] = form_data.get('api', 'd.js')
params['data']['nextParams'] = form_data.get('nextParams', '') params['data']['nextParams'] = form_data.get('nextParams', '')
params['data']['v'] = form_data.get('v', 'l') params['data']['v'] = form_data.get('v', 'l')
params['headers']['Referer'] = url params['data']['o'] = form_data.get('o', 'json')
params['data']['dc'] = offset + 1
params['data']['api'] = form_data.get('api', 'd.js')
# vqd is required to request other pages after the first one
vqd = get_vqd(query, eng_region, force_request=False) vqd = get_vqd(query, eng_region, force_request=False)
# Certain conditions must be met in order to call up one of the
# following pages ...
if vqd: if vqd:
params['data']['vqd'] = vqd # follow up pages / requests needs a vqd argument params['data']['vqd'] = vqd
else: else:
# Don't try to call follow up pages without a vqd value. DDG # Don't try to call follow up pages without a vqd value.
# recognizes this as a request from a bot. This lowers the # DDG recognizes this as a request from a bot. This lowers the
# reputation of the SearXNG IP and DDG starts to activate CAPTCHAs. # reputation of the SearXNG IP and DDG starts to activate CAPTCHAs.
params["url"] = None params["url"] = None
return return
if params['searxng_locale'].startswith("zh"): if params['searxng_locale'].startswith("zh"):
# Some locales (at least China) do not have a "next page" button and ddg # Some locales (at least China) do not have a "next page" button and DDG
# will return a HTTP/2 403 Forbidden for a request of such a page. # will return a HTTP/2 403 Forbidden for a request of such a page.
params["url"] = None params["url"] = None
return return
# Put empty kl in form data if language/region set to all
if eng_region == "wt-wt":
params['data']['kl'] = ""
else:
params['data']['kl'] = eng_region
params['data']['df'] = ''
if params['time_range'] in time_range_dict:
params['data']['df'] = time_range_dict[params['time_range']]
params['cookies']['df'] = time_range_dict[params['time_range']]
params['cookies']['kl'] = eng_region
params['url'] = url
params['method'] = 'POST'
params['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
params['headers']['Referer'] = url
params['headers']['Sec-Fetch-Dest'] = "document"
params['headers']['Sec-Fetch-Mode'] = "navigate" # at least this one is used by ddg's bot detection
params['headers']['Sec-Fetch-Site'] = "same-origin"
params['headers']['Sec-Fetch-User'] = "?1"
logger.debug("param headers: %s", params['headers'])
logger.debug("param data: %s", params['data']) logger.debug("param data: %s", params['data'])
logger.debug("param cookies: %s", params['cookies']) logger.debug("param cookies: %s", params['cookies'])
@ -383,8 +372,9 @@ def response(resp) -> EngineResults:
continue continue
item["title"] = extract_text(title) item["title"] = extract_text(title)
item["url"] = eval_xpath(div_result, './/h2/a/@href')[0] item["url"] = eval_xpath(div_result, './/h2/a/@href')[0]
item["content"] = extract_text(eval_xpath(div_result, './/a[contains(@class, "result__snippet")]')[0]) item["content"] = extract_text(
eval_xpath_getindex(div_result, './/a[contains(@class, "result__snippet")]', 0, [])
)
results.append(item) results.append(item)
zero_click_info_xpath = '//div[@id="zero_click_abstract"]' zero_click_info_xpath = '//div[@id="zero_click_abstract"]'

View file

@ -1,6 +1,13 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
"""Invidious (Videos) """Invidious (Videos)
If you want to use invidious with SearXNG you should setup one locally.
No public instance offer a public API now
- https://github.com/searxng/searxng/issues/2722#issuecomment-2884993248
""" """
from __future__ import annotations
import time import time
import random import random
@ -13,7 +20,7 @@ from searx.utils import humanize_number
about = { about = {
"website": 'https://api.invidious.io/', "website": 'https://api.invidious.io/',
"wikidata_id": 'Q79343316', "wikidata_id": 'Q79343316',
"official_api_documentation": 'https://github.com/iv-org/documentation/blob/master/API.md', "official_api_documentation": 'https://docs.invidious.io/api/',
"use_official_api": True, "use_official_api": True,
"require_api_key": False, "require_api_key": False,
"results": 'JSON', "results": 'JSON',
@ -25,7 +32,12 @@ paging = True
time_range_support = True time_range_support = True
# base_url can be overwritten by a list of URLs in the settings.yml # base_url can be overwritten by a list of URLs in the settings.yml
base_url = 'https://vid.puffyan.us' base_url: list | str = []
def init(_):
if not base_url:
raise ValueError("missing invidious base_url")
def request(query, params): def request(query, params):

View file

@ -1,7 +1,5 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
"""Material Icons (images) """Material Icons (icons)"""
"""
import re import re
from json import loads from json import loads
@ -14,6 +12,8 @@ about = {
"require_api_key": False, "require_api_key": False,
"results": 'JSON', "results": 'JSON',
} }
categories = ['images', 'icons']
search_url = "https://fonts.google.com/metadata/icons?key=material_symbols&incomplete=true" search_url = "https://fonts.google.com/metadata/icons?key=material_symbols&incomplete=true"
result_url = "https://fonts.google.com/icons?icon.query={query}&selected=Material+Symbols+Outlined:{icon_name}:FILL@0{fill};wght@400;GRAD@0;opsz@24" # pylint: disable=line-too-long result_url = "https://fonts.google.com/icons?icon.query={query}&selected=Material+Symbols+Outlined:{icon_name}:FILL@0{fill};wght@400;GRAD@0;opsz@24" # pylint: disable=line-too-long
img_src_url = "https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsoutlined/{icon_name}/{svg_type}/24px.svg" img_src_url = "https://fonts.gstatic.com/s/i/short-term/release/materialsymbolsoutlined/{icon_name}/{svg_type}/24px.svg"
@ -46,7 +46,7 @@ def response(resp):
continue continue
tags = [tag.title() for tag in result["tags"]] tags = [tag.title() for tag in result["tags"]]
categories = [category.title() for category in result["categories"]] icon_categories = [category.title() for category in result["categories"]]
results.append( results.append(
{ {
@ -54,7 +54,7 @@ def response(resp):
'url': result_url.format(icon_name=result["name"], query=result["name"], fill=0 if outlined else 1), 'url': result_url.format(icon_name=result["name"], query=result["name"], fill=0 if outlined else 1),
'img_src': img_src_url.format(icon_name=result["name"], svg_type=svg_type), 'img_src': img_src_url.format(icon_name=result["name"], svg_type=svg_type),
'title': result["name"].replace("_", "").title(), 'title': result["name"].replace("_", "").title(),
'content': ", ".join(tags) + " / " + ", ".join(categories), 'content': ", ".join(tags) + " / " + ", ".join(icon_categories),
} }
) )

210
searx/engines/naver.py Normal file
View file

@ -0,0 +1,210 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
# pylint: disable=line-too-long
"""Naver for SearXNG"""
from urllib.parse import urlencode
from lxml import html
from searx.exceptions import SearxEngineAPIException, SearxEngineXPathException
from searx.result_types import EngineResults, MainResult
from searx.utils import (
eval_xpath_getindex,
eval_xpath_list,
eval_xpath,
extract_text,
extr,
html_to_text,
parse_duration_string,
js_variable_to_python,
)
# engine metadata
about = {
"website": "https://search.naver.com",
"wikidata_id": "Q485639",
"use_official_api": False,
"require_api_key": False,
"results": "HTML",
"language": "ko",
}
categories = []
paging = True
time_range_support = True
time_range_dict = {"day": "1d", "week": "1w", "month": "1m", "year": "1y"}
base_url = "https://search.naver.com"
naver_category = "general"
"""Naver supports general, images, news, videos search.
- ``general``: search for general
- ``images``: search for images
- ``news``: search for news
- ``videos``: search for videos
"""
# Naver cannot set the number of results on one page, set default value for paging
naver_category_dict = {
"general": {
"start": 15,
"where": "web",
},
"images": {
"start": 50,
"where": "image",
},
"news": {
"start": 10,
"where": "news",
},
"videos": {
"start": 48,
"where": "video",
},
}
def init(_):
if naver_category not in ('general', 'images', 'news', 'videos'):
raise SearxEngineAPIException(f"Unsupported category: {naver_category}")
def request(query, params):
query_params = {
"query": query,
}
if naver_category in naver_category_dict:
query_params["start"] = (params["pageno"] - 1) * naver_category_dict[naver_category]["start"] + 1
query_params["where"] = naver_category_dict[naver_category]["where"]
if params["time_range"] in time_range_dict:
query_params["nso"] = f"p:{time_range_dict[params['time_range']]}"
params["url"] = f"{base_url}/search.naver?{urlencode(query_params)}"
return params
def response(resp) -> EngineResults:
parsers = {'general': parse_general, 'images': parse_images, 'news': parse_news, 'videos': parse_videos}
return parsers[naver_category](resp.text)
def parse_general(data):
results = EngineResults()
dom = html.fromstring(data)
for item in eval_xpath_list(dom, "//ul[contains(@class, 'lst_total')]/li[contains(@class, 'bx')]"):
thumbnail = None
try:
thumbnail = eval_xpath_getindex(item, ".//div[contains(@class, 'thumb_single')]//img/@data-lazysrc", 0)
except (ValueError, TypeError, SearxEngineXPathException):
pass
results.add(
MainResult(
title=extract_text(eval_xpath(item, ".//a[contains(@class, 'link_tit')]")),
url=eval_xpath_getindex(item, ".//a[contains(@class, 'link_tit')]/@href", 0),
content=extract_text(
eval_xpath(item, ".//div[contains(@class, 'total_dsc_wrap')]//a[contains(@class, 'api_txt_lines')]")
),
thumbnail=thumbnail,
)
)
return results
def parse_images(data):
results = []
match = extr(data, '<script>var imageSearchTabData=', '</script>')
if match:
json = js_variable_to_python(match.strip())
items = json.get('content', {}).get('items', [])
for item in items:
results.append(
{
"template": "images.html",
"url": item.get('link'),
"thumbnail_src": item.get('thumb'),
"img_src": item.get('originalUrl'),
"title": html_to_text(item.get('title')),
"source": item.get('source'),
"resolution": f"{item.get('orgWidth')} x {item.get('orgHeight')}",
}
)
return results
def parse_news(data):
results = EngineResults()
dom = html.fromstring(data)
for item in eval_xpath_list(
dom, "//div[contains(@class, 'sds-comps-base-layout') and contains(@class, 'sds-comps-full-layout')]"
):
title = extract_text(eval_xpath(item, ".//span[contains(@class, 'sds-comps-text-type-headline1')]/text()"))
url = eval_xpath_getindex(item, ".//a[@href and @nocr='1']/@href", 0)
content = extract_text(eval_xpath(item, ".//span[contains(@class, 'sds-comps-text-type-body1')]"))
thumbnail = None
try:
thumbnail = eval_xpath_getindex(
item,
".//div[contains(@class, 'sds-comps-image') and contains(@class, 'sds-rego-thumb-overlay')]//img[@src]/@src",
0,
)
except (ValueError, TypeError, SearxEngineXPathException):
pass
if title and content and url:
results.add(
MainResult(
title=title,
url=url,
content=content,
thumbnail=thumbnail,
)
)
return results
def parse_videos(data):
results = []
dom = html.fromstring(data)
for item in eval_xpath_list(dom, "//li[contains(@class, 'video_item')]"):
thumbnail = None
try:
thumbnail = eval_xpath_getindex(item, ".//img[contains(@class, 'thumb')]/@src", 0)
except (ValueError, TypeError, SearxEngineXPathException):
pass
length = None
try:
length = parse_duration_string(extract_text(eval_xpath(item, ".//span[contains(@class, 'time')]")))
except (ValueError, TypeError):
pass
results.append(
{
"template": "videos.html",
"title": extract_text(eval_xpath(item, ".//a[contains(@class, 'info_title')]")),
"url": eval_xpath_getindex(item, ".//a[contains(@class, 'info_title')]/@href", 0),
"thumbnail": thumbnail,
'length': length,
}
)
return results

View file

@ -1,6 +1,5 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
"""Pinterest (images) """Pinterest (images)"""
"""
from json import dumps from json import dumps
@ -28,6 +27,11 @@ def request(query, params):
'context': {}, 'context': {},
} }
params['url'] = f"{base_url}/resource/BaseSearchResource/get/?data={dumps(args)}" params['url'] = f"{base_url}/resource/BaseSearchResource/get/?data={dumps(args)}"
params['headers'] = {
'X-Pinterest-AppState': 'active',
'X-Pinterest-Source-Url': '/ideas/',
'X-Pinterest-PWS-Handler': 'www/ideas.js',
}
return params return params

View file

@ -137,19 +137,20 @@ def _get_request_id(query, params):
if l.territory: if l.territory:
headers['Accept-Language'] = f"{l.language}-{l.territory},{l.language};" "q=0.9,*;" "q=0.5" headers['Accept-Language'] = f"{l.language}-{l.territory},{l.language};" "q=0.9,*;" "q=0.5"
resp_text = get(url, headers=headers).text # type: ignore resp = get(url, headers=headers)
for line in resp_text.split("\n"): for line in resp.text.split("\n"):
if "window.searchId = " in line: if "window.searchId = " in line:
return line.split("= ")[1][:-1].replace('"', "") return line.split("= ")[1][:-1].replace('"', ""), resp.cookies
return None raise RuntimeError("Couldn't find any request id for presearch")
def request(query, params): def request(query, params):
request_id = _get_request_id(query, params) request_id, cookies = _get_request_id(query, params)
params["headers"]["Accept"] = "application/json" params["headers"]["Accept"] = "application/json"
params["url"] = f"{base_url}/results?id={request_id}" params["url"] = f"{base_url}/results?id={request_id}"
params["cookies"] = cookies
return params return params

View file

@ -11,7 +11,7 @@ about = {
"require_api_key": False, "require_api_key": False,
"results": 'JSON', "results": 'JSON',
} }
categories = ['images'] categories = ['images', 'icons']
icons_list_url = 'https://cdn.selfh.st/directory/icons.json' icons_list_url = 'https://cdn.selfh.st/directory/icons.json'

View file

@ -1,5 +1,5 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
"""Svgrepo (images) """Svgrepo (icons)
""" """
from lxml import html from lxml import html
@ -14,7 +14,7 @@ about = {
} }
paging = True paging = True
categories = ['images'] categories = ['images', 'icons']
base_url = "https://www.svgrepo.com" base_url = "https://www.svgrepo.com"
results_xpath = "//div[@class='style_nodeListing__7Nmro']/div" results_xpath = "//div[@class='style_nodeListing__7Nmro']/div"

View file

@ -77,7 +77,7 @@ def response(resp):
elif item_type == 'video': elif item_type == 'video':
results.append(_video(item)) results.append(_video(item))
else: else:
logger.error("unknow result type: %s", item_type) logger.error("unknown result type: %s", item_type)
return results return results

50
searx/engines/uxwing.py Normal file
View file

@ -0,0 +1,50 @@
# SPDX-License-Identifier: AGPL-3.0-or-later
"""UXwing (images)"""
from urllib.parse import quote_plus
from lxml import html
from searx.utils import eval_xpath, eval_xpath_list, extract_text
about = {
"website": 'https://uxwing.com',
"wikidata_id": None,
"official_api_documentation": None,
"use_official_api": False,
"require_api_key": False,
"results": 'HTML',
}
categories = ['images', 'icons']
base_url = "https://uxwing.com"
def request(query, params):
params['url'] = f"{base_url}/?s={quote_plus(query)}"
return params
def response(resp):
results = []
doc = html.fromstring(resp.text)
for result in eval_xpath_list(doc, "//article[starts-with(@id, 'post')]"):
classes = extract_text(eval_xpath(result, "./@class")).split(" ")
tags = []
for css_class in classes:
for prefix in ("category", "tag"):
if css_class.startswith(prefix):
tag = css_class.removeprefix(prefix)
tags.append(tag.replace("-", " ").title())
results.append(
{
'template': 'images.html',
'url': extract_text(eval_xpath(result, "./a/@href")),
'img_src': extract_text(eval_xpath(result, ".//img/@src")),
'title': extract_text(eval_xpath(result, ".//img/@alt")),
'content': ', '.join(tags),
}
)
return results

View file

@ -44,6 +44,29 @@ time_range_dict = {
'month': ('1m', 'm'), 'month': ('1m', 'm'),
} }
region2domain = {
"CO": "co.search.yahoo.com", # Colombia
"TH": "th.search.yahoo.com", # Thailand
"VE": "ve.search.yahoo.com", # Venezuela
"CL": "cl.search.yahoo.com", # Chile
"HK": "hk.search.yahoo.com", # Hong Kong
"PE": "pe.search.yahoo.com", # Peru
"CA": "ca.search.yahoo.com", # Canada
"DE": "de.search.yahoo.com", # Germany
"FR": "fr.search.yahoo.com", # France
"TW": "tw.search.yahoo.com", # Taiwan
"GB": "uk.search.yahoo.com", # United Kingdom
"UK": "uk.search.yahoo.com",
"BR": "br.search.yahoo.com", # Brazil
"IN": "in.search.yahoo.com", # India
"ES": "espanol.search.yahoo.com", # Espanol
"PH": "ph.search.yahoo.com", # Philippines
"AR": "ar.search.yahoo.com", # Argentina
"MX": "mx.search.yahoo.com", # Mexico
"SG": "sg.search.yahoo.com", # Singapore
}
"""Map regions to domain"""
lang2domain = { lang2domain = {
'zh_chs': 'hk.search.yahoo.com', 'zh_chs': 'hk.search.yahoo.com',
'zh_cht': 'tw.search.yahoo.com', 'zh_cht': 'tw.search.yahoo.com',
@ -65,40 +88,40 @@ lang2domain = {
yahoo_languages = { yahoo_languages = {
"all": "any", "all": "any",
"ar": "ar", "ar": "ar", # Arabic
"bg": "bg", "bg": "bg", # Bulgarian
"cs": "cs", "cs": "cs", # Czech
"da": "da", "da": "da", # Danish
"de": "de", "de": "de", # German
"el": "el", "el": "el", # Greek
"en": "en", "en": "en", # English
"es": "es", "es": "es", # Spanish
"et": "et", "et": "et", # Estonian
"fi": "fi", "fi": "fi", # Finnish
"fr": "fr", "fr": "fr", # French
"he": "he", "he": "he", # Hebrew
"hr": "hr", "hr": "hr", # Croatian
"hu": "hu", "hu": "hu", # Hungarian
"it": "it", "it": "it", # Italian
"ja": "ja", "ja": "ja", # Japanese
"ko": "ko", "ko": "ko", # Korean
"lt": "lt", "lt": "lt", # Lithuanian
"lv": "lv", "lv": "lv", # Latvian
"nl": "nl", "nl": "nl", # Dutch
"no": "no", "no": "no", # Norwegian
"pl": "pl", "pl": "pl", # Polish
"pt": "pt", "pt": "pt", # Portuguese
"ro": "ro", "ro": "ro", # Romanian
"ru": "ru", "ru": "ru", # Russian
"sk": "sk", "sk": "sk", # Slovak
"sl": "sl", "sl": "sl", # Slovenian
"sv": "sv", "sv": "sv", # Swedish
"th": "th", "th": "th", # Thai
"tr": "tr", "tr": "tr", # Turkish
"zh": "zh_chs", "zh": "zh_chs", # Chinese (Simplified)
"zh_Hans": "zh_chs", "zh_Hans": "zh_chs",
'zh-CN': "zh_chs", 'zh-CN': "zh_chs",
"zh_Hant": "zh_cht", "zh_Hant": "zh_cht", # Chinese (Traditional)
"zh-HK": "zh_cht", "zh-HK": "zh_cht",
'zh-TW': "zh_cht", 'zh-TW': "zh_cht",
} }
@ -107,7 +130,7 @@ yahoo_languages = {
def request(query, params): def request(query, params):
"""build request""" """build request"""
lang = params["language"].split("-")[0] lang, region = (params["language"].split("-") + [None])[:2]
lang = yahoo_languages.get(lang, "any") lang = yahoo_languages.get(lang, "any")
offset = (params['pageno'] - 1) * 7 + 1 offset = (params['pageno'] - 1) * 7 + 1
@ -127,9 +150,11 @@ def request(query, params):
} }
) )
domain = lang2domain.get(lang, '%s.search.yahoo.com' % lang) domain = region2domain.get(region)
if not domain:
domain = lang2domain.get(lang, '%s.search.yahoo.com' % lang)
params['url'] = 'https://%s/search?%s' % (domain, args) params['url'] = 'https://%s/search?%s' % (domain, args)
return params params['domain'] = domain
def parse_url(url_string): def parse_url(url_string):
@ -157,14 +182,22 @@ def response(resp):
results = [] results = []
dom = html.fromstring(resp.text) dom = html.fromstring(resp.text)
url_xpath = './/div[contains(@class,"compTitle")]/h3/a/@href'
title_xpath = './/h3//a/@aria-label'
domain = resp.search_params['domain']
if domain == "search.yahoo.com":
url_xpath = './/div[contains(@class,"compTitle")]/a/@href'
title_xpath = './/div[contains(@class,"compTitle")]/a/h3/span'
# parse results # parse results
for result in eval_xpath_list(dom, '//div[contains(@class,"algo-sr")]'): for result in eval_xpath_list(dom, '//div[contains(@class,"algo-sr")]'):
url = eval_xpath_getindex(result, './/h3/a/@href', 0, default=None) url = eval_xpath_getindex(result, url_xpath, 0, default=None)
if url is None: if url is None:
continue continue
url = parse_url(url) url = parse_url(url)
title = eval_xpath_getindex(result, './/h3//a/@aria-label', 0, default='') title = eval_xpath_getindex(result, title_xpath, 0, default='')
title: str = extract_text(title) title: str = extract_text(title)
content = eval_xpath_getindex(result, './/div[contains(@class, "compText")]', 0, default='') content = eval_xpath_getindex(result, './/div[contains(@class, "compText")]', 0, default='')
content: str = extract_text(content, allow_none=True) content: str = extract_text(content, allow_none=True)

View file

@ -180,6 +180,8 @@ def fetch_traits(engine_traits: EngineTraits) -> None:
# pylint: disable=import-outside-toplevel, too-many-branches # pylint: disable=import-outside-toplevel, too-many-branches
import babel import babel
import httpx
from searx.network import get # see https://github.com/searxng/searxng/issues/762 from searx.network import get # see https://github.com/searxng/searxng/issues/762
from searx.locales import language_tag from searx.locales import language_tag
@ -191,7 +193,7 @@ def fetch_traits(engine_traits: EngineTraits) -> None:
try: try:
resp = get(base_url, verify=False) resp = get(base_url, verify=False)
except SearxException as exc: except (SearxException, httpx.ConnectError) as exc:
print(f"ERROR: zlibrary domain '{base_url}' is seized?") print(f"ERROR: zlibrary domain '{base_url}' is seized?")
print(f" --> {exc}") print(f" --> {exc}")
_use_old_values() _use_old_values()

View file

@ -42,7 +42,7 @@ class SXNG_Request(flask.Request):
"""list of searx.plugins.Plugin.id (the id of the plugins)""" """list of searx.plugins.Plugin.id (the id of the plugins)"""
preferences: "searx.preferences.Preferences" preferences: "searx.preferences.Preferences"
"""The prefernces of the request.""" """The preferences of the request."""
errors: list[str] errors: list[str]
"""A list of errors (translated text) added by :py:obj:`searx.webapp` in """A list of errors (translated text) added by :py:obj:`searx.webapp` in

View file

@ -140,7 +140,7 @@ class FaviconCacheConfig(msgspec.Struct): # pylint: disable=too-few-public-meth
@dataclasses.dataclass @dataclasses.dataclass
class FaviconCacheStats: class FaviconCacheStats:
"""Dataclass wich provides information on the status of the cache.""" """Dataclass which provides information on the status of the cache."""
favicons: int | None = None favicons: int | None = None
bytes: int | None = None bytes: int | None = None
@ -387,7 +387,7 @@ CREATE TABLE IF NOT EXISTS blob_map (
self.properties.set("LAST_MAINTENANCE", "") # hint: this (also) sets the m_time of the property! self.properties.set("LAST_MAINTENANCE", "") # hint: this (also) sets the m_time of the property!
# Do maintenance tasks. This can be take a little more time, to avoid # Do maintenance tasks. This can be take a little more time, to avoid
# DB locks, etablish a new DB connecton. # DB locks, establish a new DB connection.
with self.connect() as conn: with self.connect() as conn:

View file

@ -24,7 +24,7 @@ LOOP = None
SSLCONTEXTS: Dict[Any, SSLContext] = {} SSLCONTEXTS: Dict[Any, SSLContext] = {}
def shuffle_ciphers(ssl_context): def shuffle_ciphers(ssl_context: SSLContext):
"""Shuffle httpx's default ciphers of a SSL context randomly. """Shuffle httpx's default ciphers of a SSL context randomly.
From `What Is TLS Fingerprint and How to Bypass It`_ From `What Is TLS Fingerprint and How to Bypass It`_
@ -41,16 +41,16 @@ def shuffle_ciphers(ssl_context):
https://www.zenrows.com/blog/what-is-tls-fingerprint#how-to-bypass-tls-fingerprinting https://www.zenrows.com/blog/what-is-tls-fingerprint#how-to-bypass-tls-fingerprinting
""" """
c_list = httpx._config.DEFAULT_CIPHERS.split(':') # pylint: disable=protected-access c_list = [cipher["name"] for cipher in ssl_context.get_ciphers()]
sc_list, c_list = c_list[:3], c_list[3:] sc_list, c_list = c_list[:3], c_list[3:]
random.shuffle(c_list) random.shuffle(c_list)
ssl_context.set_ciphers(":".join(sc_list + c_list)) ssl_context.set_ciphers(":".join(sc_list + c_list))
def get_sslcontexts(proxy_url=None, cert=None, verify=True, trust_env=True, http2=False): def get_sslcontexts(proxy_url=None, cert=None, verify=True, trust_env=True):
key = (proxy_url, cert, verify, trust_env, http2) key = (proxy_url, cert, verify, trust_env)
if key not in SSLCONTEXTS: if key not in SSLCONTEXTS:
SSLCONTEXTS[key] = httpx.create_ssl_context(cert, verify, trust_env, http2) SSLCONTEXTS[key] = httpx.create_ssl_context(verify, cert, trust_env)
shuffle_ciphers(SSLCONTEXTS[key]) shuffle_ciphers(SSLCONTEXTS[key])
return SSLCONTEXTS[key] return SSLCONTEXTS[key]
@ -120,7 +120,7 @@ def get_transport_for_socks_proxy(verify, http2, local_address, proxy_url, limit
rdns = True rdns = True
proxy_type, proxy_host, proxy_port, proxy_username, proxy_password = parse_proxy_url(proxy_url) proxy_type, proxy_host, proxy_port, proxy_username, proxy_password = parse_proxy_url(proxy_url)
verify = get_sslcontexts(proxy_url, None, verify, True, http2) if verify is True else verify verify = get_sslcontexts(proxy_url, None, verify, True) if verify is True else verify
return AsyncProxyTransportFixed( return AsyncProxyTransportFixed(
proxy_type=proxy_type, proxy_type=proxy_type,
proxy_host=proxy_host, proxy_host=proxy_host,
@ -138,7 +138,7 @@ def get_transport_for_socks_proxy(verify, http2, local_address, proxy_url, limit
def get_transport(verify, http2, local_address, proxy_url, limit, retries): def get_transport(verify, http2, local_address, proxy_url, limit, retries):
verify = get_sslcontexts(None, None, verify, True, http2) if verify is True else verify verify = get_sslcontexts(None, None, verify, True) if verify is True else verify
return httpx.AsyncHTTPTransport( return httpx.AsyncHTTPTransport(
# pylint: disable=protected-access # pylint: disable=protected-access
verify=verify, verify=verify,

View file

@ -180,7 +180,7 @@ class Network:
Network._TOR_CHECK_RESULT[proxies] = result Network._TOR_CHECK_RESULT[proxies] = result
return result return result
async def get_client(self, verify=None, max_redirects=None): async def get_client(self, verify=None, max_redirects=None) -> httpx.AsyncClient:
verify = self.verify if verify is None else verify verify = self.verify if verify is None else verify
max_redirects = self.max_redirects if max_redirects is None else max_redirects max_redirects = self.max_redirects if max_redirects is None else max_redirects
local_address = next(self._local_addresses_cycle) local_address = next(self._local_addresses_cycle)
@ -269,6 +269,8 @@ class Network:
kwargs_clients = Network.extract_kwargs_clients(kwargs) kwargs_clients = Network.extract_kwargs_clients(kwargs)
while retries >= 0: # pragma: no cover while retries >= 0: # pragma: no cover
client = await self.get_client(**kwargs_clients) client = await self.get_client(**kwargs_clients)
cookies = kwargs.pop("cookies", None)
client.cookies = httpx.Cookies(cookies)
try: try:
if stream: if stream:
response = client.stream(method, url, **kwargs) response = client.stream(method, url, **kwargs)

View file

@ -8,7 +8,7 @@ class OpenMetricsFamily: # pylint: disable=too-few-public-methods
The type_hint parameter must be one of 'counter', 'gauge', 'histogram', 'summary'. The type_hint parameter must be one of 'counter', 'gauge', 'histogram', 'summary'.
The help_hint parameter is a short string explaining the metric. The help_hint parameter is a short string explaining the metric.
The data_info parameter is a dictionary of descriptionary parameters for the data point (e.g. request method/path). The data_info parameter is a dictionary of descriptionary parameters for the data point (e.g. request method/path).
The data parameter is a flat list of the actual data in shape of a primive type. The data parameter is a flat list of the actual data in shape of a primitive type.
See https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md for more information. See https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md for more information.
""" """

View file

@ -26,7 +26,7 @@ log: logging.Logger = logging.getLogger("searx.plugins")
@dataclass @dataclass
class PluginInfo: class PluginInfo:
"""Object that holds informations about a *plugin*, these infos are shown to """Object that holds information about a *plugin*, these infos are shown to
the user in the Preferences menu. the user in the Preferences menu.
To be able to translate the information into other languages, the text must To be able to translate the information into other languages, the text must
@ -85,7 +85,7 @@ class Plugin(abc.ABC):
constructor (if not already set in the subclass).""" constructor (if not already set in the subclass)."""
info: PluginInfo info: PluginInfo
"""Informations about the *plugin*, see :py:obj:`PluginInfo`.""" """Information about the *plugin*, see :py:obj:`PluginInfo`."""
fqn: str = "" fqn: str = ""
@ -129,8 +129,8 @@ class Plugin(abc.ABC):
def init(self, app: "flask.Flask") -> bool: # pylint: disable=unused-argument def init(self, app: "flask.Flask") -> bool: # pylint: disable=unused-argument
"""Initialization of the plugin, the return value decides whether this """Initialization of the plugin, the return value decides whether this
plugin is active or not. Initialization only takes place once, at the plugin is active or not. Initialization only takes place once, at the
time the WEB application is set up. The base methode always returns time the WEB application is set up. The base method always returns
``True``, the methode can be overwritten in the inheritances, ``True``, the method can be overwritten in the inheritances,
- ``True`` plugin is active - ``True`` plugin is active
- ``False`` plugin is inactive - ``False`` plugin is inactive

View file

@ -12,24 +12,13 @@ from .online import OnlineProcessor
parser_re = re.compile('.*?(\\d+(?:\\.\\d+)?) ([^.0-9]+) (?:in|to) ([^.0-9]+)', re.I) parser_re = re.compile('.*?(\\d+(?:\\.\\d+)?) ([^.0-9]+) (?:in|to) ([^.0-9]+)', re.I)
def normalize_name(name): def normalize_name(name: str):
name = name.strip()
name = name.lower().replace('-', ' ').rstrip('s') name = name.lower().replace('-', ' ').rstrip('s')
name = re.sub(' +', ' ', name) name = re.sub(' +', ' ', name)
return unicodedata.normalize('NFKD', name).lower() return unicodedata.normalize('NFKD', name).lower()
def name_to_iso4217(name):
name = normalize_name(name)
currency = CURRENCIES['names'].get(name, [name])
if isinstance(currency, str):
return currency
return currency[-1]
def iso4217_to_name(iso4217, language):
return CURRENCIES['iso4217'].get(iso4217, {}).get(language, iso4217)
class OnlineCurrencyProcessor(OnlineProcessor): class OnlineCurrencyProcessor(OnlineProcessor):
"""Processor class used by ``online_currency`` engines.""" """Processor class used by ``online_currency`` engines."""
@ -52,14 +41,15 @@ class OnlineCurrencyProcessor(OnlineProcessor):
amount = float(amount_str) amount = float(amount_str)
except ValueError: except ValueError:
return None return None
from_currency = name_to_iso4217(from_currency.strip())
to_currency = name_to_iso4217(to_currency.strip()) from_currency = CURRENCIES.name_to_iso4217(normalize_name(from_currency))
to_currency = CURRENCIES.name_to_iso4217(normalize_name(to_currency))
params['amount'] = amount params['amount'] = amount
params['from'] = from_currency params['from'] = from_currency
params['to'] = to_currency params['to'] = to_currency
params['from_name'] = iso4217_to_name(from_currency, 'en') params['from_name'] = CURRENCIES.iso4217_to_name(from_currency, "en")
params['to_name'] = iso4217_to_name(to_currency, 'en') params['to_name'] = CURRENCIES.iso4217_to_name(to_currency, "en")
return params return params
def get_default_tests(self): def get_default_tests(self):

View file

@ -34,7 +34,7 @@ search:
# Filter results. 0: None, 1: Moderate, 2: Strict # Filter results. 0: None, 1: Moderate, 2: Strict
safe_search: 0 safe_search: 0
# Existing autocomplete backends: "360search", "baidu", "brave", "dbpedia", "duckduckgo", "google", "yandex", # Existing autocomplete backends: "360search", "baidu", "brave", "dbpedia", "duckduckgo", "google", "yandex",
# "mwmbl", "seznam", "sogou", "stract", "swisscows", "quark", "qwant", "wikipedia" - # "mwmbl", "naver", "seznam", "sogou", "stract", "swisscows", "quark", "qwant", "wikipedia" -
# leave blank to turn it off by default. # leave blank to turn it off by default.
autocomplete: "" autocomplete: ""
# minimun characters to type before autocompleter starts # minimun characters to type before autocompleter starts
@ -252,8 +252,8 @@ plugins:
# #
# hostnames: # hostnames:
# replace: # replace:
# '(.*\.)?youtube\.com$': 'invidious.example.com' # '(.*\.)?youtube\.com$': 'yt.example.com'
# '(.*\.)?youtu\.be$': 'invidious.example.com' # '(.*\.)?youtu\.be$': 'yt.example.com'
# '(.*\.)?reddit\.com$': 'teddit.example.com' # '(.*\.)?reddit\.com$': 'teddit.example.com'
# '(.*\.)?redd\.it$': 'teddit.example.com' # '(.*\.)?redd\.it$': 'teddit.example.com'
# '(www\.)?twitter\.com$': 'nitter.example.com' # '(www\.)?twitter\.com$': 'nitter.example.com'
@ -270,8 +270,8 @@ plugins:
# replace: 'rewrite-hosts.yml' # replace: 'rewrite-hosts.yml'
# #
# Content of 'rewrite-hosts.yml' (place the file in the same directory as 'settings.yml'): # Content of 'rewrite-hosts.yml' (place the file in the same directory as 'settings.yml'):
# '(.*\.)?youtube\.com$': 'invidious.example.com' # '(.*\.)?youtube\.com$': 'yt.example.com'
# '(.*\.)?youtu\.be$': 'invidious.example.com' # '(.*\.)?youtu\.be$': 'yt.example.com'
# #
checker: checker:
@ -1053,7 +1053,6 @@ engines:
- name: material icons - name: material icons
engine: material_icons engine: material_icons
categories: images
shortcut: mi shortcut: mi
disabled: true disabled: true
@ -1117,6 +1116,7 @@ engines:
- name: il post - name: il post
engine: il_post engine: il_post
shortcut: pst shortcut: pst
disabled: true
- name: huggingface - name: huggingface
engine: huggingface engine: huggingface
@ -1152,16 +1152,15 @@ engines:
timeout: 6.0 timeout: 6.0
disabled: true disabled: true
- name: invidious # - name: invidious
engine: invidious # engine: invidious
# Instanes will be selected randomly, see https://api.invidious.io/ for # # if you want to use invidious with SearXNG you should setup one locally
# instances that are stable (good uptime) and close to you. # # https://github.com/searxng/searxng/issues/2722#issuecomment-2884993248
base_url: # base_url:
- https://invidious.adminforge.de # - https://invidious.example1.com
- https://inv.nadeko.net # - https://invidious.example2.com
shortcut: iv # shortcut: iv
timeout: 3.0 # timeout: 3.0
disabled: true
- name: ipernity - name: ipernity
engine: ipernity engine: ipernity
@ -1237,11 +1236,13 @@ engines:
shortcut: zlib shortcut: zlib
categories: files categories: files
timeout: 7.0 timeout: 7.0
disabled: true
- name: library of congress - name: library of congress
engine: loc engine: loc
shortcut: loc shortcut: loc
categories: images categories: images
disabled: true
- name: libretranslate - name: libretranslate
engine: libretranslate engine: libretranslate
@ -1708,6 +1709,7 @@ engines:
engine: qwant engine: qwant
shortcut: qw shortcut: qw
categories: [general, web] categories: [general, web]
disabled: true
additional_tests: additional_tests:
rosebud: *test_rosebud rosebud: *test_rosebud
@ -2359,25 +2361,31 @@ engines:
disabled: true disabled: true
- name: naver - name: naver
shortcut: nvr
categories: [general, web] categories: [general, web]
engine: xpath engine: naver
paging: true shortcut: nvr
search_url: https://search.naver.com/search.naver?where=webkr&sm=osp_hty&ie=UTF-8&query={query}&start={pageno} disabled: true
url_xpath: //a[@class="link_tit"]/@href
title_xpath: //a[@class="link_tit"] - name: naver images
content_xpath: //div[@class="total_dsc_wrap"]/a naver_category: images
first_page_num: 1 categories: [images]
page_size: 10 engine: naver
shortcut: nvri
disabled: true
- name: naver news
naver_category: news
categories: [news]
engine: naver
shortcut: nvrn
disabled: true
- name: naver videos
naver_category: videos
categories: [videos]
engine: naver
shortcut: nvrv
disabled: true disabled: true
about:
website: https://www.naver.com/
wikidata_id: Q485639
official_api_documentation: https://developers.naver.com/docs/nmt/examples/
use_official_api: false
require_api_key: false
results: HTML
language: ko
- name: rubygems - name: rubygems
shortcut: rbg shortcut: rbg
@ -2524,6 +2532,11 @@ engines:
engine: tootfinder engine: tootfinder
shortcut: toot shortcut: toot
- name: uxwing
engine: uxwing
shortcut: ux
disabled: true
- name: voidlinux - name: voidlinux
engine: voidlinux engine: voidlinux
shortcut: void shortcut: void

View file

@ -114,7 +114,7 @@ class SQLiteAppl(abc.ABC):
""" """
SQLITE_JOURNAL_MODE = "WAL" SQLITE_JOURNAL_MODE = "WAL"
"""``SQLiteAppl`` applications are optimzed for WAL_ mode, its not recommend """``SQLiteAppl`` applications are optimized for WAL_ mode, its not recommend
to change the journal mode (see :py:obj:`SQLiteAppl.tear_down`). to change the journal mode (see :py:obj:`SQLiteAppl.tear_down`).
.. _WAL: https://sqlite.org/wal.html .. _WAL: https://sqlite.org/wal.html
@ -145,7 +145,7 @@ class SQLiteAppl(abc.ABC):
- https://github.com/python/cpython/issues/118172 - https://github.com/python/cpython/issues/118172
- https://github.com/python/cpython/issues/123873 - https://github.com/python/cpython/issues/123873
The workaround for SQLite3 multithreading cache inconsistency ist to set The workaround for SQLite3 multithreading cache inconsistency is to set
option ``cached_statements`` to ``0`` by default. option ``cached_statements`` to ``0`` by default.
""" """

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -64,7 +64,7 @@
</main> </main>
<footer> <footer>
<p> <p>
{{ _('Powered by') }} <a href="{{ url_for('info', pagename='about') }}">searxng</a> - {{ searx_version }} — {{ _('a privacy-respecting, open metasearch engine') }}<br> {{ _('Powered by') }} <a href="{{ url_for('info', pagename='about') }}">SearXNG</a> - {{ searx_version }} — {{ _('a privacy-respecting, open metasearch engine') }}<br>
<a href="{{ searx_git_url }}">{{ _('Source code') }}</a> <a href="{{ searx_git_url }}">{{ _('Source code') }}</a>
| <a href="{{ get_setting('brand.issue_url') }}">{{ _('Issue tracker') }}</a> | <a href="{{ get_setting('brand.issue_url') }}">{{ _('Issue tracker') }}</a>
{% if enable_metrics %}| <a href="{{ url_for('stats') }}">{{ _('Engine stats') }}</a>{% endif %} {% if enable_metrics %}| <a href="{{ url_for('stats') }}">{{ _('Engine stats') }}</a>{% endif %}

View file

@ -9,6 +9,7 @@
<input id="q" name="q" type="text" placeholder="{{ _('Search for...') }}" tabindex="1" autocomplete="off" autocapitalize="none" spellcheck="false" autocorrect="off" dir="auto" value="{{ q or '' }}"> <input id="q" name="q" type="text" placeholder="{{ _('Search for...') }}" tabindex="1" autocomplete="off" autocapitalize="none" spellcheck="false" autocorrect="off" dir="auto" value="{{ q or '' }}">
<button id="clear_search" type="reset" aria-label="{{ _('clear') }}" class="hide_if_nojs"><span>{{ icon_big('close') }}</span><span class="show_if_nojs">{{ _('clear') }}</span></button> <button id="clear_search" type="reset" aria-label="{{ _('clear') }}" class="hide_if_nojs"><span>{{ icon_big('close') }}</span><span class="show_if_nojs">{{ _('clear') }}</span></button>
<button id="send_search" type="submit" {%- if search_on_category_select -%}name="category_{{ selected_categories[0]|replace(' ', '_') }}"{%- endif -%} aria-label="{{ _('search') }}"><span class="hide_if_nojs">{{ icon_big('search') }}</span><span class="show_if_nojs">{{ _('search') }}</span></button> <button id="send_search" type="submit" {%- if search_on_category_select -%}name="category_{{ selected_categories[0]|replace(' ', '_') }}"{%- endif -%} aria-label="{{ _('search') }}"><span class="hide_if_nojs">{{ icon_big('search') }}</span><span class="show_if_nojs">{{ _('search') }}</span></button>
<div class="autocomplete hide_if_nojs"><ul></ul></div>
</div> </div>
</div> </div>
{% set display_tooltip = true %} {% set display_tooltip = true %}

View file

@ -5,6 +5,7 @@
<input id="q" name="q" type="text" placeholder="{{ _('Search for...') }}" autocomplete="off" autocapitalize="none" spellcheck="false" autocorrect="off" dir="auto" value="{{ q or '' }}"> <input id="q" name="q" type="text" placeholder="{{ _('Search for...') }}" autocomplete="off" autocapitalize="none" spellcheck="false" autocorrect="off" dir="auto" value="{{ q or '' }}">
<button id="clear_search" type="reset" aria-label="{{ _('clear') }}"><span class="hide_if_nojs">{{ icon_big('close') }}</span><span class="show_if_nojs">{{ _('clear') }}</span></button> <button id="clear_search" type="reset" aria-label="{{ _('clear') }}"><span class="hide_if_nojs">{{ icon_big('close') }}</span><span class="show_if_nojs">{{ _('clear') }}</span></button>
<button id="send_search" type="submit" aria-label="{{ _('search') }}"><span class="hide_if_nojs">{{ icon_big('search') }}</span><span class="show_if_nojs">{{ _('search') }}</span></button> <button id="send_search" type="submit" aria-label="{{ _('search') }}"><span class="hide_if_nojs">{{ icon_big('search') }}</span><span class="show_if_nojs">{{ _('search') }}</span></button>
<div class="autocomplete hide_if_nojs"><ul></ul></div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -19,7 +19,7 @@ msgid ""
msgstr "" 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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-01-28 06:11+0000\n" "PO-Revision-Date: 2025-01-28 06:11+0000\n"
"Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>" "Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>"
"\n" "\n"
@ -73,7 +73,7 @@ msgid "videos"
msgstr "video's" msgstr "video's"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "draadloos" msgstr "draadloos"
@ -350,93 +350,93 @@ msgstr "toe"
msgid "answered" msgid "answered"
msgstr "geantwoord" msgstr "geantwoord"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Geen item gevind" msgstr "Geen item gevind"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Bron" msgstr "Bron"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Fout met die laai van die volgende bladsy" msgstr "Fout met die laai van die volgende bladsy"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Ongeldige opstellings, redigeer asb jou voorkeure" msgstr "Ongeldige opstellings, redigeer asb jou voorkeure"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Ongeldige opstellings" msgstr "Ongeldige opstellings"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "soekfout" msgstr "soekfout"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "tydsverloop" msgstr "tydsverloop"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "ontledingsfout" msgstr "ontledingsfout"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "HTTP protokol fout" msgstr "HTTP protokol fout"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "netwerk fout" msgstr "netwerk fout"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "SSL vout: Kon nie sertifikaat verifieer nie" msgstr "SSL vout: Kon nie sertifikaat verifieer nie"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "onverwagse breek" msgstr "onverwagse breek"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "HTTP fout" msgstr "HTTP fout"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "HTTP koppelingsfout" msgstr "HTTP koppelingsfout"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "proksie fout" msgstr "proksie fout"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "te veel versoeke" msgstr "te veel versoeke"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "toegang geweier" msgstr "toegang geweier"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "bediener API fout" msgstr "bediener API fout"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Opgehef" msgstr "Opgehef"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "{minutes} minute terug" msgstr "{minutes} minute terug"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "{hours} ure, {minutes} minute terug" msgstr "{hours} ure, {minutes} minute terug"
@ -467,15 +467,15 @@ msgstr "Hierdie inskrywing was vervang deur"
msgid "Channel" msgid "Channel"
msgstr "Kanaal" msgstr "Kanaal"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "bitsnelheid" msgstr "bitsnelheid"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "stemme" msgstr "stemme"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "klikke" msgstr "klikke"
@ -484,7 +484,7 @@ msgstr "klikke"
msgid "Language" msgid "Language"
msgstr "Taal" msgstr "Taal"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -711,10 +711,6 @@ msgstr "Outeur"
msgid "cached" msgid "cached"
msgstr "gekas" msgstr "gekas"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "gevolmagtig"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Begin om 'n nuwe probleem op GitHub in te dien" msgstr "Begin om 'n nuwe probleem op GitHub in te dien"
@ -1826,3 +1822,6 @@ msgstr "versteek video"
#~ "gebruik word om voorkeure oor toestelle" #~ "gebruik word om voorkeure oor toestelle"
#~ " heen te sinkroniseer." #~ " heen te sinkroniseer."
#~ msgid "proxied"
#~ msgstr "gevolmagtig"

View file

@ -28,20 +28,19 @@
# DZDevelopers <dzdevelopers@noreply.codeberg.org>, 2025. # DZDevelopers <dzdevelopers@noreply.codeberg.org>, 2025.
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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-04-15 10:37+0000\n" "PO-Revision-Date: 2025-04-15 10:37+0000\n"
"Last-Translator: DZDevelopers <dzdevelopers@noreply.codeberg.org>\n" "Last-Translator: DZDevelopers <dzdevelopers@noreply.codeberg.org>\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.10.2\n"
"Generated-By: Babel 2.17.0\n" "Generated-By: Babel 2.17.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -85,7 +84,7 @@ msgid "videos"
msgstr "ڤيديوهات" msgstr "ڤيديوهات"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "راديو" msgstr "راديو"
@ -362,93 +361,93 @@ msgstr "مغلق"
msgid "answered" msgid "answered"
msgstr "أُجيبت" msgstr "أُجيبت"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "تعذر العثور على عناصر" msgstr "تعذر العثور على عناصر"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "المصدر" msgstr "المصدر"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "حدث خلل أثناء تحميل الصفحة التالية" msgstr "حدث خلل أثناء تحميل الصفحة التالية"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "إنّ الإعدادات خاطئة، يرجى تعديل خياراتك" msgstr "إنّ الإعدادات خاطئة، يرجى تعديل خياراتك"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "إعدادات غير صالحة" msgstr "إعدادات غير صالحة"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "خطأ في البحث" msgstr "خطأ في البحث"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "نفذ الوقت" msgstr "نفذ الوقت"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "خطأ تحليل" msgstr "خطأ تحليل"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "خطأ في بروتوكول HTTP" msgstr "خطأ في بروتوكول HTTP"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "خطأ في الشبكة" msgstr "خطأ في الشبكة"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "خطأ SSL: فشل التحقق من صحة الشهادة" msgstr "خطأ SSL: فشل التحقق من صحة الشهادة"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "تعطل غير متوقع" msgstr "تعطل غير متوقع"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "خطأ HTTP" msgstr "خطأ HTTP"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "خطأ في اتصال HTTP" msgstr "خطأ في اتصال HTTP"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "خطأ في وكيل البروكسي" msgstr "خطأ في وكيل البروكسي"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "أسئلة التحقق" msgstr "أسئلة التحقق"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "الكثير من الطلبات" msgstr "الكثير من الطلبات"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "الدخول مرفوض" msgstr "الدخول مرفوض"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "خطأ في API الخادم" msgstr "خطأ في API الخادم"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "معلق" msgstr "معلق"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "{minutes} minute(s) ago" msgstr "{minutes} minute(s) ago"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "قبل {hours} ساعات، {minutes} دقائق" msgstr "قبل {hours} ساعات، {minutes} دقائق"
@ -479,15 +478,15 @@ msgstr "هذا الإدخال تم استبداله بـ"
msgid "Channel" msgid "Channel"
msgstr "القناة" msgstr "القناة"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "معدل البت" msgstr "معدل البت"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "تصويتات" msgstr "تصويتات"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "نقرات" msgstr "نقرات"
@ -496,7 +495,7 @@ msgstr "نقرات"
msgid "Language" msgid "Language"
msgstr "اللغة" msgstr "اللغة"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -724,10 +723,6 @@ msgstr "الكاتب"
msgid "cached" msgid "cached"
msgstr "النسخة المخبأة" msgstr "النسخة المخبأة"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "المخدم البروكسي"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "ابدأ بتقديم قضية جديدة على GitHub" msgstr "ابدأ بتقديم قضية جديدة على GitHub"
@ -1191,8 +1186,8 @@ msgid ""
"A URL containing your preferences. This URL can be used to restore your " "A URL containing your preferences. This URL can be used to restore your "
"settings on a different device." "settings on a different device."
msgstr "" msgstr ""
"رابط يحتوي على تفضيلاتك. يمكن استخدام هذا الرابط لاستعادة إعداداتك على جهاز " "رابط يحتوي على تفضيلاتك. يمكن استخدام هذا الرابط لاستعادة إعداداتك على "
"مختلف." "جهاز مختلف."
#: searx/templates/simple/preferences/cookies.html:46 #: searx/templates/simple/preferences/cookies.html:46
msgid "Copy preferences hash" msgid "Copy preferences hash"
@ -2084,3 +2079,7 @@ msgstr "إخفاء الفيديو"
#~ "يمكن استخدام تحديد الإعدادات المخصصة في" #~ "يمكن استخدام تحديد الإعدادات المخصصة في"
#~ " تفضيلات URL لمزامنة التفضيلات عبر " #~ " تفضيلات URL لمزامنة التفضيلات عبر "
#~ "الأجهزة." #~ "الأجهزة."
#~ msgid "proxied"
#~ msgstr "المخدم البروكسي"

View file

@ -16,20 +16,22 @@
# Anonymous <anonymous@users.noreply.translate.codeberg.org>, 2025. # Anonymous <anonymous@users.noreply.translate.codeberg.org>, 2025.
# thenack0 <thenack0@users.noreply.translate.codeberg.org>, 2025. # thenack0 <thenack0@users.noreply.translate.codeberg.org>, 2025.
# return42 <return42@noreply.codeberg.org>, 2025. # return42 <return42@noreply.codeberg.org>, 2025.
# devrimer <devrimer@noreply.codeberg.org>, 2025.
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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-03-14 07:09+0000\n" "PO-Revision-Date: 2025-05-16 04:04+0000\n"
"Last-Translator: return42 <return42@noreply.codeberg.org>\n" "Last-Translator: devrimer <devrimer@noreply.codeberg.org>\n"
"Language-Team: Bulgarian <https://translate.codeberg.org/projects/searxng/"
"searxng/bg/>\n"
"Language: bg\n" "Language: bg\n"
"Language-Team: Bulgarian "
"<https://translate.codeberg.org/projects/searxng/searxng/bg/>\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.11.4\n"
"Generated-By: Babel 2.17.0\n" "Generated-By: Babel 2.17.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -73,7 +75,7 @@ msgid "videos"
msgstr "видео" msgstr "видео"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "радио" msgstr "радио"
@ -350,93 +352,93 @@ msgstr "Затворено"
msgid "answered" msgid "answered"
msgstr "Отговорено" msgstr "Отговорено"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Не е намерен артикул" msgstr "Не е намерен артикул"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Източник" msgstr "Източник"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Грешка при зареждането на следващата страница" msgstr "Грешка при зареждането на следващата страница"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Неправилни настройки, моля редактирайте предпочитанията си" msgstr "Неправилни настройки, моля редактирайте предпочитанията си"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Невалидни настройки" msgstr "Невалидни настройки"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "Грешка при търсенето" msgstr "Грешка при търсенето"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "изчакване" msgstr "изчакване"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "грешка при анализа" msgstr "грешка при анализа"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "Грешка в протокола HTTP" msgstr "Грешка в протокола HTTP"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "мрежова грешка" msgstr "мрежова грешка"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "SSL грешка: проверката на сертификата е неуспешна" msgstr "SSL грешка: проверката на сертификата е неуспешна"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "неочакван срив" msgstr "неочакван срив"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "HTTP грешка" msgstr "HTTP грешка"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "HTTP грешка във връзката" msgstr "HTTP грешка във връзката"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "прокси грешка" msgstr "прокси грешка"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "твърде много повиквания" msgstr "твърде много повиквания"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "отказан достъп" msgstr "отказан достъп"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "грешка в API на сървъра" msgstr "грешка в API на сървъра"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "преустановен" msgstr "преустановен"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "преди {minutes} минута(минути)" msgstr "преди {minutes} минута(минути)"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "преди {hours} час(ове), {minutes} минута(минути)" msgstr "преди {hours} час(ове), {minutes} минута(минути)"
@ -448,7 +450,7 @@ msgstr "Генерирайте различни произволни стойн
#: searx/answerers/statistics.py:36 #: searx/answerers/statistics.py:36
#, python-brace-format #, python-brace-format
msgid "Compute {func} of the arguments" msgid "Compute {func} of the arguments"
msgstr "" msgstr "Изчислете {func} на аргументите"
#: searx/engines/openstreetmap.py:158 #: searx/engines/openstreetmap.py:158
msgid "Show route in map .." msgid "Show route in map .."
@ -467,15 +469,15 @@ msgstr "Този запис е заменен от"
msgid "Channel" msgid "Channel"
msgstr "Канал" msgstr "Канал"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "Скорост" msgstr "Скорост"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "Гласове" msgstr "Гласове"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "клика" msgstr "клика"
@ -484,7 +486,7 @@ msgstr "клика"
msgid "Language" msgid "Language"
msgstr "Език" msgstr "Език"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -712,10 +714,6 @@ msgstr "Автор"
msgid "cached" msgid "cached"
msgstr "кеширана" msgstr "кеширана"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "прекарана"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Предявете нов проблем в GitHub" msgstr "Предявете нов проблем в GitHub"
@ -2083,3 +2081,5 @@ msgstr "скрий видеото"
#~ "позволи синхронизация между различни " #~ "позволи синхронизация между различни "
#~ "устройства." #~ "устройства."
#~ msgid "proxied"
#~ msgstr "прекарана"

View file

@ -26,7 +26,7 @@ msgid ""
msgstr "" 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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-03-06 09:54+0000\n" "PO-Revision-Date: 2025-03-06 09:54+0000\n"
"Last-Translator: MonsoonFire <monsoonfire@noreply.codeberg.org>\n" "Last-Translator: MonsoonFire <monsoonfire@noreply.codeberg.org>\n"
"Language: bn\n" "Language: bn\n"
@ -79,7 +79,7 @@ msgid "videos"
msgstr "ভিডিও" msgstr "ভিডিও"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "বেতার" msgstr "বেতার"
@ -356,93 +356,93 @@ msgstr "বন্ধ"
msgid "answered" msgid "answered"
msgstr "উত্তরকৃত" msgstr "উত্তরকৃত"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "কোন আইটেম পাওয়া যায়নি" msgstr "কোন আইটেম পাওয়া যায়নি"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "উৎস" msgstr "উৎস"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "পরবর্তী পৃষ্ঠাটি লোড করায় ত্রুটি দেখা যাচ্ছে" msgstr "পরবর্তী পৃষ্ঠাটি লোড করায় ত্রুটি দেখা যাচ্ছে"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "অকেজো সেটিংস, অনুগ্রহ করে আপনার পছন্দগুলি সম্পাদনা করুন" msgstr "অকেজো সেটিংস, অনুগ্রহ করে আপনার পছন্দগুলি সম্পাদনা করুন"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "অকেজো সেটিংস" msgstr "অকেজো সেটিংস"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "সার্চ ত্রুটি" msgstr "সার্চ ত্রুটি"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "সময় শেষ" msgstr "সময় শেষ"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "পার্স ত্রুটি" msgstr "পার্স ত্রুটি"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "HTTP প্রোটোকল ত্রুটি" msgstr "HTTP প্রোটোকল ত্রুটি"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "নেটওয়ার্ক ত্রুটি" msgstr "নেটওয়ার্ক ত্রুটি"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "SSL ত্রুটি: সার্টিফিকেট বৈধতা ব্যর্থ হয়েছে৷" msgstr "SSL ত্রুটি: সার্টিফিকেট বৈধতা ব্যর্থ হয়েছে৷"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "অপ্রত্যাশিত ক্র্যাশ" msgstr "অপ্রত্যাশিত ক্র্যাশ"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "HTTP ত্রুটি" msgstr "HTTP ত্রুটি"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "HTTP সংযোগ ত্রুটি" msgstr "HTTP সংযোগ ত্রুটি"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "প্রক্সি ত্রুটি" msgstr "প্রক্সি ত্রুটি"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "ক্যাপচা" msgstr "ক্যাপচা"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "অনেক বেশি অনুরোধ" msgstr "অনেক বেশি অনুরোধ"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "প্রবেশ অগ্রাহ্য করা হল" msgstr "প্রবেশ অগ্রাহ্য করা হল"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "সার্ভার API ত্রুটি" msgstr "সার্ভার API ত্রুটি"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "স্থগিত" msgstr "স্থগিত"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "{minutes} মিনিট আগে" msgstr "{minutes} মিনিট আগে"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "{hours} ঘণ্টা, {minutes} মিনিট আগে" msgstr "{hours} ঘণ্টা, {minutes} মিনিট আগে"
@ -473,15 +473,15 @@ msgstr "এই এনট্রিটি দ্বারা বাতিল ক
msgid "Channel" msgid "Channel"
msgstr "চ্যানেল" msgstr "চ্যানেল"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "বিটরেট" msgstr "বিটরেট"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "ভোট" msgstr "ভোট"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "ক্লিক সংখ্যা" msgstr "ক্লিক সংখ্যা"
@ -490,7 +490,7 @@ msgstr "ক্লিক সংখ্যা"
msgid "Language" msgid "Language"
msgstr "ভাষা" msgstr "ভাষা"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -716,10 +716,6 @@ msgstr "লেখক"
msgid "cached" msgid "cached"
msgstr "ক্যাশকৃত" msgstr "ক্যাশকৃত"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "প্রক্সিকৃত"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "GitHub এ একটি নতুন সমস্যা জমা দেওয়া শুরু করুন" msgstr "GitHub এ একটি নতুন সমস্যা জমা দেওয়া শুরু করুন"
@ -1843,3 +1839,6 @@ msgstr "ভিডিও লুকিয়ে ফেলুন"
#~ "প্রেফারেন্সগুলি ডিভাইস জুড়ে সিঙ্ক করে " #~ "প্রেফারেন্সগুলি ডিভাইস জুড়ে সিঙ্ক করে "
#~ "ব্যবহার করতে পারেন।" #~ "ব্যবহার করতে পারেন।"
#~ msgid "proxied"
#~ msgstr "প্রক্সিকৃত"

View file

@ -12,7 +12,7 @@ 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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-01-06 15:52+0000\n" "PO-Revision-Date: 2025-01-06 15:52+0000\n"
"Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>" "Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>"
"\n" "\n"
@ -66,7 +66,7 @@ msgid "videos"
msgstr "བརྙན་ཟློས།" msgstr "བརྙན་ཟློས།"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "" msgstr ""
@ -343,93 +343,93 @@ msgstr ""
msgid "answered" msgid "answered"
msgstr "" msgstr ""
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "རྣམ་གྲངས་གང་ཡང་རྙེད་རྒྱུ་མ་བྱུང་།" msgstr "རྣམ་གྲངས་གང་ཡང་རྙེད་རྒྱུ་མ་བྱུང་།"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "" msgstr ""
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "" msgstr ""
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "ནུས་མེད་ཀྱི་སྒྲིག་འགོད།ཁྱེད་ཀྱིས་གདམ་ཀ་ལ་བཅོས་སྒྲིག་གཏོང་རོགས།" msgstr "ནུས་མེད་ཀྱི་སྒྲིག་འགོད།ཁྱེད་ཀྱིས་གདམ་ཀ་ལ་བཅོས་སྒྲིག་གཏོང་རོགས།"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "ནུས་མེད་ཀྱི་སྒྲིག་འགོད།" msgstr "ནུས་མེད་ཀྱི་སྒྲིག་འགོད།"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "འཚོལ་བཤེར་ལ་ནོར་འཁྲུལ་བྱུང་།" msgstr "འཚོལ་བཤེར་ལ་ནོར་འཁྲུལ་བྱུང་།"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "" msgstr ""
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "" msgstr ""
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "" msgstr ""
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "" msgstr ""
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "" msgstr ""
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "" msgstr ""
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "" msgstr ""
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "" msgstr ""
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "" msgstr ""
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "" msgstr ""
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "" msgstr ""
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "" msgstr ""
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "" msgstr ""
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "སྐར་མ་ {minutes} སྔོན་ལ།" msgstr "སྐར་མ་ {minutes} སྔོན་ལ།"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "ཆུ་ཚོད་ {hours} དང་སྐར་མ {minutes} སྔོན་ལ།" msgstr "ཆུ་ཚོད་ {hours} དང་སྐར་མ {minutes} སྔོན་ལ།"
@ -460,15 +460,15 @@ msgstr "འཚོལ་བྱང་འདི་གཞན་གྱིས་ཚབ
msgid "Channel" msgid "Channel"
msgstr "" msgstr ""
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "" msgstr ""
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "" msgstr ""
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "" msgstr ""
@ -477,7 +477,7 @@ msgstr ""
msgid "Language" msgid "Language"
msgstr "" msgstr ""
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -689,10 +689,6 @@ msgstr ""
msgid "cached" msgid "cached"
msgstr "འདྲ་བཤུས་རྒྱབ་ཚར།" msgstr "འདྲ་བཤུས་རྒྱབ་ཚར།"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "མངག་བཅོལ་བྱེད་ཟིན།"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "" msgstr ""
@ -1994,3 +1990,6 @@ msgstr "རྙན་ཟློས་སྦས།"
#~ "sync preferences across devices." #~ "sync preferences across devices."
#~ msgstr "" #~ msgstr ""
#~ msgid "proxied"
#~ msgstr "མངག་བཅོལ་བྱེད་ཟིན།"

View file

@ -26,7 +26,7 @@ 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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-01-06 15:52+0000\n" "PO-Revision-Date: 2025-01-06 15:52+0000\n"
"Last-Translator: sserra <sserra@users.noreply.translate.codeberg.org>\n" "Last-Translator: sserra <sserra@users.noreply.translate.codeberg.org>\n"
"Language: ca\n" "Language: ca\n"
@ -79,7 +79,7 @@ msgid "videos"
msgstr "vídeos" msgstr "vídeos"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "radio" msgstr "radio"
@ -356,93 +356,93 @@ msgstr "tancat"
msgid "answered" msgid "answered"
msgstr "contestat" msgstr "contestat"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "No s'ha trobat cap element" msgstr "No s'ha trobat cap element"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Origen" msgstr "Origen"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "S'ha produït un error en carregar la següent pàgina" msgstr "S'ha produït un error en carregar la següent pàgina"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "La configuració no és vàlida, editeu-la" msgstr "La configuració no és vàlida, editeu-la"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "La configuració no és vàlida" msgstr "La configuració no és vàlida"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "error de cerca" msgstr "error de cerca"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "expirat" msgstr "expirat"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "error de processament" msgstr "error de processament"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "error del protocol HTTP" msgstr "error del protocol HTTP"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "error de xarxa" msgstr "error de xarxa"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "error de SSL: la validació del certificat ha fallat" msgstr "error de SSL: la validació del certificat ha fallat"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "error inesperat" msgstr "error inesperat"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "error de HTTP" msgstr "error de HTTP"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "error de connexió HTTP" msgstr "error de connexió HTTP"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "error del servidor intermediari" msgstr "error del servidor intermediari"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "masses peticions" msgstr "masses peticions"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "accés denegat" msgstr "accés denegat"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "error en l'API del servidor" msgstr "error en l'API del servidor"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Suspès" msgstr "Suspès"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "fa {minutes} minut(s)" msgstr "fa {minutes} minut(s)"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "fa {hours} hores i {minutes} minut(s)" msgstr "fa {hours} hores i {minutes} minut(s)"
@ -473,15 +473,15 @@ msgstr "Aquesta entrada ha estat substituïda per"
msgid "Channel" msgid "Channel"
msgstr "Canal" msgstr "Canal"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "tasa de bits" msgstr "tasa de bits"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "vots" msgstr "vots"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "clics" msgstr "clics"
@ -490,7 +490,7 @@ msgstr "clics"
msgid "Language" msgid "Language"
msgstr "Llengua" msgstr "Llengua"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -716,10 +716,6 @@ msgstr "Autor"
msgid "cached" msgid "cached"
msgstr "en memòria cau" msgstr "en memòria cau"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "en servidor intermediari"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Obriu una incidència a GitHub" msgstr "Obriu una incidència a GitHub"
@ -2100,3 +2096,6 @@ msgstr "oculta el vídeo"
#~ " l'URL de preferències pot usar-se" #~ " l'URL de preferències pot usar-se"
#~ " per sincronitzar entre dispositius." #~ " per sincronitzar entre dispositius."
#~ msgid "proxied"
#~ msgstr "en servidor intermediari"

View file

@ -22,20 +22,19 @@
# Fjuro <fjuro@noreply.codeberg.org>, 2025. # Fjuro <fjuro@noreply.codeberg.org>, 2025.
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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-03-30 16:28+0000\n" "PO-Revision-Date: 2025-03-30 16:28+0000\n"
"Last-Translator: Fjuro <fjuro@noreply.codeberg.org>\n" "Last-Translator: Fjuro <fjuro@noreply.codeberg.org>\n"
"Language-Team: Czech <https://translate.codeberg.org/projects/searxng/"
"searxng/cs/>\n"
"Language: cs\n" "Language: cs\n"
"Language-Team: Czech "
"<https://translate.codeberg.org/projects/searxng/searxng/cs/>\n"
"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && "
"n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\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=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n "
"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
"X-Generator: Weblate 5.10.2\n"
"Generated-By: Babel 2.17.0\n" "Generated-By: Babel 2.17.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -79,7 +78,7 @@ msgid "videos"
msgstr "videa" msgstr "videa"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "rádio" msgstr "rádio"
@ -356,93 +355,93 @@ msgstr "zavřené"
msgid "answered" msgid "answered"
msgstr "zodpovězené" msgstr "zodpovězené"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Nic nenalezeno" msgstr "Nic nenalezeno"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "zdroj" msgstr "zdroj"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Chyba při načítání další stránky" msgstr "Chyba při načítání další stránky"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Neplatné nastavení, upravte své předvolby" msgstr "Neplatné nastavení, upravte své předvolby"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Neplatné nastavení" msgstr "Neplatné nastavení"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "chyba vyhledávání" msgstr "chyba vyhledávání"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "čas vypršel" msgstr "čas vypršel"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "chyba parsování" msgstr "chyba parsování"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "chyba HTTP protokolu" msgstr "chyba HTTP protokolu"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "síťová chyba" msgstr "síťová chyba"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "chyba SSL: ověření certifikátu selhalo" msgstr "chyba SSL: ověření certifikátu selhalo"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "nečekaná chyba" msgstr "nečekaná chyba"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "chyba HTTP" msgstr "chyba HTTP"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "Chyba spojení HTTP" msgstr "Chyba spojení HTTP"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "chyba proxy" msgstr "chyba proxy"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "příliš mnoho požadavků" msgstr "příliš mnoho požadavků"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "přístup odepřen" msgstr "přístup odepřen"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "chyba API serveru" msgstr "chyba API serveru"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Pozastaveno" msgstr "Pozastaveno"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "před {minutes} minutami" msgstr "před {minutes} minutami"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "před {hours} hodinami, {minutes} minutami" msgstr "před {hours} hodinami, {minutes} minutami"
@ -473,15 +472,15 @@ msgstr "Tato položka byla nahrazena položkou"
msgid "Channel" msgid "Channel"
msgstr "Kanál" msgstr "Kanál"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "datový tok" msgstr "datový tok"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "hlasy" msgstr "hlasy"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "kliknutí" msgstr "kliknutí"
@ -490,7 +489,7 @@ msgstr "kliknutí"
msgid "Language" msgid "Language"
msgstr "Jazyk" msgstr "Jazyk"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -608,9 +607,9 @@ msgid ""
"This plugin checks if the address of the request is a Tor exit-node, and " "This plugin checks if the address of the request is a Tor exit-node, and "
"informs the user if it is; like check.torproject.org, but from SearXNG." "informs the user if it is; like check.torproject.org, but from SearXNG."
msgstr "" msgstr ""
"Tento doplněk kontroluje, zda je adresa požadavku výstupním uzlem sítě Tor, " "Tento doplněk kontroluje, zda je adresa požadavku výstupním uzlem sítě "
"a informuje uživatele, pokud tomu tak je; jako check.torproject.org, ale od " "Tor, a informuje uživatele, pokud tomu tak je; jako check.torproject.org,"
"SearXNG." " ale od SearXNG."
#: searx/plugins/tor_check.py:65 #: searx/plugins/tor_check.py:65
msgid "Could not download the list of Tor exit-nodes from" msgid "Could not download the list of Tor exit-nodes from"
@ -718,10 +717,6 @@ msgstr "Autor"
msgid "cached" msgid "cached"
msgstr "archivovaná verze" msgstr "archivovaná verze"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "přes proxy"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Začněte přidávat novou chybu na Githubu" msgstr "Začněte přidávat novou chybu na Githubu"
@ -2089,3 +2084,7 @@ msgstr "skrýt video"
#~ "Zadání vlastních nastavení v URL " #~ "Zadání vlastních nastavení v URL "
#~ "předvoleb lze použít k synchronizaci " #~ "předvoleb lze použít k synchronizaci "
#~ "předvoleb mezi zařízeními." #~ "předvoleb mezi zařízeními."
#~ msgid "proxied"
#~ msgstr "přes proxy"

View file

@ -19,7 +19,7 @@ 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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-03-07 00:07+0000\n" "PO-Revision-Date: 2025-03-07 00:07+0000\n"
"Last-Translator: DanielBoone <danielboone@noreply.codeberg.org>\n" "Last-Translator: DanielBoone <danielboone@noreply.codeberg.org>\n"
"Language: cy\n" "Language: cy\n"
@ -73,7 +73,7 @@ msgid "videos"
msgstr "fideos" msgstr "fideos"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "radio" msgstr "radio"
@ -350,93 +350,93 @@ msgstr "ar gau"
msgid "answered" msgid "answered"
msgstr "wedi'i ateb" msgstr "wedi'i ateb"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Ni chanfuwyd eitem" msgstr "Ni chanfuwyd eitem"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Ffynhonnell" msgstr "Ffynhonnell"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Gwall wrth lwytho'r dudalen nesaf" msgstr "Gwall wrth lwytho'r dudalen nesaf"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Gosodiadau annilys, golygwch eich dewisiadau" msgstr "Gosodiadau annilys, golygwch eich dewisiadau"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Gosodiadau annilys" msgstr "Gosodiadau annilys"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "gwall chwilio" msgstr "gwall chwilio"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "terfyn amser" msgstr "terfyn amser"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "gwall dosrannu" msgstr "gwall dosrannu"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "gwall protocol HTTP" msgstr "gwall protocol HTTP"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "gwall rhwydwaith" msgstr "gwall rhwydwaith"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "Gwall SSL: dilysu tystysgrif wedi methu" msgstr "Gwall SSL: dilysu tystysgrif wedi methu"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "damwain annisgwyl" msgstr "damwain annisgwyl"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "gwall HTTP" msgstr "gwall HTTP"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "gwall cysylltiad HTTP" msgstr "gwall cysylltiad HTTP"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "gwall dirprwy" msgstr "gwall dirprwy"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "gormod o geisiadau" msgstr "gormod o geisiadau"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "mynediad wedi ei wrthod" msgstr "mynediad wedi ei wrthod"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "gwall API gweinydd" msgstr "gwall API gweinydd"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Atal" msgstr "Atal"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "{minutes} munud yn ôl" msgstr "{minutes} munud yn ôl"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "{hours} awr, {minutes} munud yn ôl" msgstr "{hours} awr, {minutes} munud yn ôl"
@ -467,15 +467,15 @@ msgstr "Mae'r cofnod hwn wedi ei ddisodli gan"
msgid "Channel" msgid "Channel"
msgstr "Sianel" msgstr "Sianel"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "cyfradd didau" msgstr "cyfradd didau"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "pleidleisiau" msgstr "pleidleisiau"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "cliciau" msgstr "cliciau"
@ -484,7 +484,7 @@ msgstr "cliciau"
msgid "Language" msgid "Language"
msgstr "Iaith" msgstr "Iaith"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -711,10 +711,6 @@ msgstr "Awdur"
msgid "cached" msgid "cached"
msgstr "wedi'i storio" msgstr "wedi'i storio"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "wedi'i ddirprwyo"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Dechrau cyflwyno problem newydd ar GitHub" msgstr "Dechrau cyflwyno problem newydd ar GitHub"
@ -2052,3 +2048,6 @@ msgstr "cuddio'r fideo"
#~ "gysoni eich dewisiadau ar draws " #~ "gysoni eich dewisiadau ar draws "
#~ "dyfeisiau." #~ "dyfeisiau."
#~ msgid "proxied"
#~ msgstr "wedi'i ddirprwyo"

View file

@ -16,19 +16,18 @@
# AndersNordh <andersnordh@noreply.codeberg.org>, 2025. # AndersNordh <andersnordh@noreply.codeberg.org>, 2025.
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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-03-31 14:03+0000\n" "PO-Revision-Date: 2025-03-31 14:03+0000\n"
"Last-Translator: AndersNordh <andersnordh@noreply.codeberg.org>\n" "Last-Translator: AndersNordh <andersnordh@noreply.codeberg.org>\n"
"Language-Team: Danish <https://translate.codeberg.org/projects/searxng/"
"searxng/da/>\n"
"Language: da\n" "Language: da\n"
"Language-Team: Danish "
"<https://translate.codeberg.org/projects/searxng/searxng/da/>\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.10.2\n"
"Generated-By: Babel 2.17.0\n" "Generated-By: Babel 2.17.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -72,7 +71,7 @@ msgid "videos"
msgstr "videoer" msgstr "videoer"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "Radio" msgstr "Radio"
@ -349,93 +348,93 @@ msgstr "lukket"
msgid "answered" msgid "answered"
msgstr "svaret" msgstr "svaret"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Intet fundet" msgstr "Intet fundet"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Kilde" msgstr "Kilde"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Fejl ved indlæsning af den næste side" msgstr "Fejl ved indlæsning af den næste side"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Ugyldige indstillinger, redigér venligst dine valg" msgstr "Ugyldige indstillinger, redigér venligst dine valg"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Ugyldig indstilling" msgstr "Ugyldig indstilling"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "søgefejl" msgstr "søgefejl"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "udløbstid" msgstr "udløbstid"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "fortolkningsfejl" msgstr "fortolkningsfejl"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "HTTP-protokolfejl" msgstr "HTTP-protokolfejl"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "netværksfejl" msgstr "netværksfejl"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "SSL-fejl: certifikatvalidering mislykkedes" msgstr "SSL-fejl: certifikatvalidering mislykkedes"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "uventet nedbrud" msgstr "uventet nedbrud"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "HTTP-fejl" msgstr "HTTP-fejl"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "HTTP-tilkoblingsfejl" msgstr "HTTP-tilkoblingsfejl"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "proxyfejl" msgstr "proxyfejl"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "for mange forespørgsler" msgstr "for mange forespørgsler"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "adgang nægtet" msgstr "adgang nægtet"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "server-API-fejl" msgstr "server-API-fejl"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Suspenderet" msgstr "Suspenderet"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "for {minutes} minut(ter) siden" msgstr "for {minutes} minut(ter) siden"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "for {hours} time(r) og {minutes} minut(ter) siden" msgstr "for {hours} time(r) og {minutes} minut(ter) siden"
@ -466,15 +465,15 @@ msgstr "Denne værdi er blevet overskrevet af"
msgid "Channel" msgid "Channel"
msgstr "Kanal" msgstr "Kanal"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "Bitrate" msgstr "Bitrate"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "Stemmer" msgstr "Stemmer"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "Klik" msgstr "Klik"
@ -483,7 +482,7 @@ msgstr "Klik"
msgid "Language" msgid "Language"
msgstr "Sprog" msgstr "Sprog"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -712,10 +711,6 @@ msgstr "Forfatter"
msgid "cached" msgid "cached"
msgstr "cachet" msgstr "cachet"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "viderestillet"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Begynd at indsende et nyt problem på GitHub" msgstr "Begynd at indsende et nyt problem på GitHub"
@ -2089,3 +2084,7 @@ msgstr "skjul video"
#~ "Specificere brugertilpassede indstillinger i " #~ "Specificere brugertilpassede indstillinger i "
#~ "præference-URL'en kan bruges til at " #~ "præference-URL'en kan bruges til at "
#~ "synkronisere præference over flere enheder." #~ "synkronisere præference over flere enheder."
#~ msgid "proxied"
#~ msgstr "viderestillet"

View file

@ -27,19 +27,18 @@
# return42 <return42@noreply.codeberg.org>, 2025. # return42 <return42@noreply.codeberg.org>, 2025.
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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-03-30 07:37+0000\n" "PO-Revision-Date: 2025-03-30 07:37+0000\n"
"Last-Translator: return42 <return42@noreply.codeberg.org>\n" "Last-Translator: return42 <return42@noreply.codeberg.org>\n"
"Language-Team: German <https://translate.codeberg.org/projects/searxng/"
"searxng/de/>\n"
"Language: de\n" "Language: de\n"
"Language-Team: German "
"<https://translate.codeberg.org/projects/searxng/searxng/de/>\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.10.2\n"
"Generated-By: Babel 2.17.0\n" "Generated-By: Babel 2.17.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -83,7 +82,7 @@ msgid "videos"
msgstr "Videos" msgstr "Videos"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "Radio" msgstr "Radio"
@ -360,93 +359,93 @@ msgstr "geschlossen"
msgid "answered" msgid "answered"
msgstr "beantwortet" msgstr "beantwortet"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Keine Einträge gefunden" msgstr "Keine Einträge gefunden"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Quelle" msgstr "Quelle"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Fehler beim Laden der nächsten Seite" msgstr "Fehler beim Laden der nächsten Seite"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Ungültige Einstellungen, bitte Einstellungen ändern" msgstr "Ungültige Einstellungen, bitte Einstellungen ändern"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Ungültige Einstellungen" msgstr "Ungültige Einstellungen"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "Suchfehler" msgstr "Suchfehler"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "Zeitüberschreitung" msgstr "Zeitüberschreitung"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "Fehler beim Parsen" msgstr "Fehler beim Parsen"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "HTTP-Protokollfehler" msgstr "HTTP-Protokollfehler"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "Netzwerkfehler" msgstr "Netzwerkfehler"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "SSL Fehler: Zertifikatsprüfung ist fehlgeschlagen" msgstr "SSL Fehler: Zertifikatsprüfung ist fehlgeschlagen"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "unerwarteter Absturz" msgstr "unerwarteter Absturz"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "HTTP-Fehler" msgstr "HTTP-Fehler"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "HTTP-Verbindungsfehler" msgstr "HTTP-Verbindungsfehler"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "Proxy-Fehler" msgstr "Proxy-Fehler"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "zu viele Anfragen" msgstr "zu viele Anfragen"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "Zugriff verweigert" msgstr "Zugriff verweigert"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "Server-API-Fehler" msgstr "Server-API-Fehler"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Ausgesetzt" msgstr "Ausgesetzt"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "vor {minutes} Minute(n)" msgstr "vor {minutes} Minute(n)"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "vor {hours} Stunde(n), {minutes} Minute(n)" msgstr "vor {hours} Stunde(n), {minutes} Minute(n)"
@ -477,15 +476,15 @@ msgstr "Dieser Eintrag wurde überschrieben von"
msgid "Channel" msgid "Channel"
msgstr "Kanal" msgstr "Kanal"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "Bitrate" msgstr "Bitrate"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "Stimmen" msgstr "Stimmen"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "Clicks" msgstr "Clicks"
@ -494,7 +493,7 @@ msgstr "Clicks"
msgid "Language" msgid "Language"
msgstr "Sprache" msgstr "Sprache"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -540,8 +539,7 @@ msgstr "Ahmia blacklist"
#: searx/plugins/ahmia_filter.py:33 #: searx/plugins/ahmia_filter.py:33
msgid "Filter out onion results that appear in Ahmia's blacklist." msgid "Filter out onion results that appear in Ahmia's blacklist."
msgstr "" msgstr "Filtern der Onion Links, die in der schwarzen Liste von Ahmia erscheinen."
"Filtern der Onion Links, die in der schwarzen Liste von Ahmia erscheinen."
#: searx/plugins/calculator.py:38 #: searx/plugins/calculator.py:38
msgid "Basic Calculator" msgid "Basic Calculator"
@ -726,10 +724,6 @@ msgstr "Autor"
msgid "cached" msgid "cached"
msgstr "Im Cache" msgstr "Im Cache"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "proxy"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Fehlerbericht auf GitHub erstellen" msgstr "Fehlerbericht auf GitHub erstellen"
@ -1200,8 +1194,8 @@ msgid ""
"A URL containing your preferences. This URL can be used to restore your " "A URL containing your preferences. This URL can be used to restore your "
"settings on a different device." "settings on a different device."
msgstr "" msgstr ""
"URL die Ihre Einstellungen enthält. Diese URL kann verwendet werden, um Ihre " "URL die Ihre Einstellungen enthält. Diese URL kann verwendet werden, um "
"Einstellungen auf einem anderen Gerät wiederherzustellen" "Ihre Einstellungen auf einem anderen Gerät wiederherzustellen"
#: searx/templates/simple/preferences/cookies.html:46 #: searx/templates/simple/preferences/cookies.html:46
msgid "Copy preferences hash" msgid "Copy preferences hash"
@ -2129,3 +2123,7 @@ msgstr "Video verstecken"
#~ "anderen Browser werden die aktuellen " #~ "anderen Browser werden die aktuellen "
#~ "Einstellungen in dem anderen Browser " #~ "Einstellungen in dem anderen Browser "
#~ "gespeichert (Cookie)." #~ "gespeichert (Cookie)."
#~ msgid "proxied"
#~ msgstr "proxy"

View file

@ -8,7 +8,7 @@ msgid ""
msgstr "" 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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-01-06 15:52+0000\n" "PO-Revision-Date: 2025-01-06 15:52+0000\n"
"Last-Translator: Anonymous " "Last-Translator: Anonymous "
"<anonymous@users.noreply.translate.codeberg.org>\n" "<anonymous@users.noreply.translate.codeberg.org>\n"
@ -62,7 +62,7 @@ msgid "videos"
msgstr "ވީޑިޔޯތައް" msgstr "ވީޑިޔޯތައް"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "" msgstr ""
@ -339,93 +339,93 @@ msgstr ""
msgid "answered" msgid "answered"
msgstr "" msgstr ""
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "" msgstr ""
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "" msgstr ""
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "" msgstr ""
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "" msgstr ""
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "" msgstr ""
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "" msgstr ""
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "" msgstr ""
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "" msgstr ""
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "" msgstr ""
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "" msgstr ""
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "" msgstr ""
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "" msgstr ""
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "" msgstr ""
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "" msgstr ""
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "" msgstr ""
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "" msgstr ""
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "" msgstr ""
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "" msgstr ""
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "" msgstr ""
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "" msgstr ""
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "" msgstr ""
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "" msgstr ""
@ -456,15 +456,15 @@ msgstr ""
msgid "Channel" msgid "Channel"
msgstr "" msgstr ""
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "" msgstr ""
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "" msgstr ""
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "" msgstr ""
@ -473,7 +473,7 @@ msgstr ""
msgid "Language" msgid "Language"
msgstr "" msgstr ""
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -685,10 +685,6 @@ msgstr ""
msgid "cached" msgid "cached"
msgstr "" msgstr ""
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr ""
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "" msgstr ""
@ -1723,3 +1719,6 @@ msgstr ""
#~ "sync preferences across devices." #~ "sync preferences across devices."
#~ msgstr "" #~ msgstr ""
#~ msgid "proxied"
#~ msgstr ""

View file

@ -22,19 +22,18 @@
# sakistzimas <sakistzimas@noreply.codeberg.org>, 2025. # sakistzimas <sakistzimas@noreply.codeberg.org>, 2025.
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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-04-03 21:59+0000\n" "PO-Revision-Date: 2025-04-03 21:59+0000\n"
"Last-Translator: sakistzimas <sakistzimas@noreply.codeberg.org>\n" "Last-Translator: sakistzimas <sakistzimas@noreply.codeberg.org>\n"
"Language-Team: Greek <https://translate.codeberg.org/projects/searxng/"
"searxng/el/>\n"
"Language: el_GR\n" "Language: el_GR\n"
"Language-Team: Greek "
"<https://translate.codeberg.org/projects/searxng/searxng/el/>\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.10.2\n"
"Generated-By: Babel 2.17.0\n" "Generated-By: Babel 2.17.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -78,7 +77,7 @@ msgid "videos"
msgstr "Βίντεο" msgstr "Βίντεο"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "ράδιο" msgstr "ράδιο"
@ -355,93 +354,93 @@ msgstr "κλειστό"
msgid "answered" msgid "answered"
msgstr "απάντησε" msgstr "απάντησε"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Δεν βρέθηκαν αντικείμενα" msgstr "Δεν βρέθηκαν αντικείμενα"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Πηγή" msgstr "Πηγή"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Σφάλμα φόρτωσης της επόμενης σελίδας" msgstr "Σφάλμα φόρτωσης της επόμενης σελίδας"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Μη έγκυρες ρυθμίσεις, παρακαλούμε ελέγξτε τις προτιμήσεις σας" msgstr "Μη έγκυρες ρυθμίσεις, παρακαλούμε ελέγξτε τις προτιμήσεις σας"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Μη έγκυρες ρυθμίσεις" msgstr "Μη έγκυρες ρυθμίσεις"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "σφάλμα αναζήτησης" msgstr "σφάλμα αναζήτησης"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "Λήξη χρόνου" msgstr "Λήξη χρόνου"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "σφάλμα ανάλυσης" msgstr "σφάλμα ανάλυσης"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "Σφάλμα πρωτοκόλλου HTTP" msgstr "Σφάλμα πρωτοκόλλου HTTP"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "Σφάλμα δικτύου" msgstr "Σφάλμα δικτύου"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "Σφάλμα SSL: η επικύρωση του πιστοποιητικού απέτυχε" msgstr "Σφάλμα SSL: η επικύρωση του πιστοποιητικού απέτυχε"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "Απροσδόκητο σφάλμα" msgstr "Απροσδόκητο σφάλμα"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "Σφάλμα HTTP" msgstr "Σφάλμα HTTP"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "Σφάλμα σύνδεσης HTTP" msgstr "Σφάλμα σύνδεσης HTTP"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "Σφάλμα διακομιστή μεσολάβησης" msgstr "Σφάλμα διακομιστή μεσολάβησης"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "υπέρβαση ορίου αιτημάτων" msgstr "υπέρβαση ορίου αιτημάτων"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "Άρνηση πρόσβασης" msgstr "Άρνηση πρόσβασης"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "Σφάλμα API διακομιστή" msgstr "Σφάλμα API διακομιστή"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Σε αναστολή" msgstr "Σε αναστολή"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "{minutes} λεπτά πριν" msgstr "{minutes} λεπτά πριν"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "{hours} ώρα(-ες), {minutes} λεπτό(-ά) πριν" msgstr "{hours} ώρα(-ες), {minutes} λεπτό(-ά) πριν"
@ -472,15 +471,15 @@ msgstr "Αυτή η καταχώριση έχει αντικατασταθεί
msgid "Channel" msgid "Channel"
msgstr "Κανάλι" msgstr "Κανάλι"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "ρυθμός μετάδοσης" msgstr "ρυθμός μετάδοσης"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "ψήφους" msgstr "ψήφους"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "κλικ" msgstr "κλικ"
@ -489,7 +488,7 @@ msgstr "κλικ"
msgid "Language" msgid "Language"
msgstr "Γλώσσα" msgstr "Γλώσσα"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -720,10 +719,6 @@ msgstr "Συγγραφέας"
msgid "cached" msgid "cached"
msgstr "προσωρινά αποθηκευμένο" msgstr "προσωρινά αποθηκευμένο"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "Διαμεσολαβημένα"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Ξεκινήστε την υποβολή ενός νέου ζητήματος στο GitHub" msgstr "Ξεκινήστε την υποβολή ενός νέου ζητήματος στο GitHub"
@ -1197,7 +1192,8 @@ msgid ""
"settings on a different device." "settings on a different device."
msgstr "" msgstr ""
"Ένα URL που περιέχει τις προτιμήσεις σας. Αυτό το URL μπορεί να " "Ένα URL που περιέχει τις προτιμήσεις σας. Αυτό το URL μπορεί να "
"χρησιμοποιηθεί για να επαναφέρει τις ρυθμίσεις σας σε διαφορετική συσκευή." "χρησιμοποιηθεί για να επαναφέρει τις ρυθμίσεις σας σε διαφορετική "
"συσκευή."
#: searx/templates/simple/preferences/cookies.html:46 #: searx/templates/simple/preferences/cookies.html:46
msgid "Copy preferences hash" msgid "Copy preferences hash"
@ -2108,3 +2104,7 @@ msgstr "απόκρυψη βίντεο"
#~ "σύνδεσμο προτιμήσεων μπορεί να χρησιμοποιηθεί" #~ "σύνδεσμο προτιμήσεων μπορεί να χρησιμοποιηθεί"
#~ " για το συγχρονισμό των προτιμήσεων " #~ " για το συγχρονισμό των προτιμήσεων "
#~ "σας σε όλες τις συσκευές." #~ "σας σε όλες τις συσκευές."
#~ msgid "proxied"
#~ msgstr "Διαμεσολαβημένα"

View file

@ -7,7 +7,7 @@ msgid ""
msgstr "" 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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2014-01-30 15:22+0100\n" "PO-Revision-Date: 2014-01-30 15:22+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language: en\n" "Language: en\n"
@ -59,7 +59,7 @@ msgid "videos"
msgstr "" msgstr ""
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "" msgstr ""
@ -336,93 +336,93 @@ msgstr ""
msgid "answered" msgid "answered"
msgstr "" msgstr ""
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "" msgstr ""
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "" msgstr ""
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "" msgstr ""
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "" msgstr ""
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "" msgstr ""
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "" msgstr ""
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "" msgstr ""
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "" msgstr ""
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "" msgstr ""
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "" msgstr ""
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "" msgstr ""
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "" msgstr ""
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "" msgstr ""
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "" msgstr ""
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "" msgstr ""
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "" msgstr ""
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "" msgstr ""
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "" msgstr ""
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "" msgstr ""
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "" msgstr ""
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "" msgstr ""
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "" msgstr ""
@ -453,15 +453,15 @@ msgstr ""
msgid "Channel" msgid "Channel"
msgstr "" msgstr ""
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "" msgstr ""
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "" msgstr ""
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "" msgstr ""
@ -470,7 +470,7 @@ msgstr ""
msgid "Language" msgid "Language"
msgstr "" msgstr ""
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -682,10 +682,6 @@ msgstr ""
msgid "cached" msgid "cached"
msgstr "" msgstr ""
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr ""
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "" msgstr ""
@ -1988,3 +1984,6 @@ msgstr ""
#~ "sync preferences across devices." #~ "sync preferences across devices."
#~ msgstr "" #~ msgstr ""
#~ msgid "proxied"
#~ msgstr ""

View file

@ -21,19 +21,18 @@
# return42 <return42@noreply.codeberg.org>, 2025. # return42 <return42@noreply.codeberg.org>, 2025.
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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-05-09 07:09+0000\n" "PO-Revision-Date: 2025-05-09 07:09+0000\n"
"Last-Translator: return42 <return42@noreply.codeberg.org>\n" "Last-Translator: return42 <return42@noreply.codeberg.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.10.2\n"
"Generated-By: Babel 2.17.0\n" "Generated-By: Babel 2.17.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -77,7 +76,7 @@ msgid "videos"
msgstr "videoj" msgstr "videoj"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "radio" msgstr "radio"
@ -354,93 +353,93 @@ msgstr ""
msgid "answered" msgid "answered"
msgstr "" msgstr ""
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Nenio trovita" msgstr "Nenio trovita"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Fonto" msgstr "Fonto"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Eraro dum la ŝarĝado de la sekvan paĝon" msgstr "Eraro dum la ŝarĝado de la sekvan paĝon"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Nevalidaj agordoj, bonvolu redaktu viajn agordojn" msgstr "Nevalidaj agordoj, bonvolu redaktu viajn agordojn"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Nevalidaj agordoj" msgstr "Nevalidaj agordoj"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "serĉa eraro" msgstr "serĉa eraro"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "eltempiĝo" msgstr "eltempiĝo"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "analiza eraro" msgstr "analiza eraro"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "HTTP-protokolo-eraro" msgstr "HTTP-protokolo-eraro"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "reta eraro" msgstr "reta eraro"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "SSL-eraro: atestila validigo malsukcesis" msgstr "SSL-eraro: atestila validigo malsukcesis"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "neatendita kraŝo" msgstr "neatendita kraŝo"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "HTTP-eraro" msgstr "HTTP-eraro"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "HTTP-konekto-eraro" msgstr "HTTP-konekto-eraro"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "prokurilo-eraro" msgstr "prokurilo-eraro"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "tro da petoj" msgstr "tro da petoj"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "aliro rifuzita" msgstr "aliro rifuzita"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "servilo-API-eraro" msgstr "servilo-API-eraro"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Suspendigita" msgstr "Suspendigita"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "antaŭ {minutes} minuto(j)" msgstr "antaŭ {minutes} minuto(j)"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "antaŭ {hours} horo(j), {minutes} minuto(j)" msgstr "antaŭ {hours} horo(j), {minutes} minuto(j)"
@ -471,15 +470,15 @@ msgstr "Tiu ĉi enigo estis anstataŭigita per"
msgid "Channel" msgid "Channel"
msgstr "Kanalo" msgstr "Kanalo"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "bito-rapido" msgstr "bito-rapido"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "voĉoj" msgstr "voĉoj"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "klakoj" msgstr "klakoj"
@ -488,7 +487,7 @@ msgstr "klakoj"
msgid "Language" msgid "Language"
msgstr "Lingvo" msgstr "Lingvo"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -712,10 +711,6 @@ msgstr "Verkisto"
msgid "cached" msgid "cached"
msgstr "kaŝmemorigita" msgstr "kaŝmemorigita"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "prokurata"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Komencu sendi novan numeron en GitHub" msgstr "Komencu sendi novan numeron en GitHub"
@ -2068,3 +2063,7 @@ msgstr "kaŝi videojn"
#~ "Specifante kutimajn agordojn en la URL" #~ "Specifante kutimajn agordojn en la URL"
#~ " de preferoj povas esti uzata por " #~ " de preferoj povas esti uzata por "
#~ "sinkronigi preferojn tra aparatoj." #~ "sinkronigi preferojn tra aparatoj."
#~ msgid "proxied"
#~ msgstr "prokurata"

View file

@ -44,13 +44,14 @@
# curtwheeler <curtwheeler@users.noreply.translate.codeberg.org>, 2025. # curtwheeler <curtwheeler@users.noreply.translate.codeberg.org>, 2025.
# return42 <return42@noreply.codeberg.org>, 2025. # return42 <return42@noreply.codeberg.org>, 2025.
# Atul_Eterno <atul_eterno@noreply.codeberg.org>, 2025. # Atul_Eterno <atul_eterno@noreply.codeberg.org>, 2025.
# realkendrick_fr <realkendrick_fr@noreply.codeberg.org>, 2025.
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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-04-24 14:06+0000\n" "PO-Revision-Date: 2025-05-27 03:58+0000\n"
"Last-Translator: Atul_Eterno <atul_eterno@noreply.codeberg.org>\n" "Last-Translator: realkendrick_fr <realkendrick_fr@noreply.codeberg.org>\n"
"Language-Team: Spanish <https://translate.codeberg.org/projects/searxng/" "Language-Team: Spanish <https://translate.codeberg.org/projects/searxng/"
"searxng/es/>\n" "searxng/es/>\n"
"Language: es\n" "Language: es\n"
@ -58,7 +59,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.10.2\n" "X-Generator: Weblate 5.11.4\n"
"Generated-By: Babel 2.17.0\n" "Generated-By: Babel 2.17.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -102,7 +103,7 @@ msgid "videos"
msgstr "vídeos" msgstr "vídeos"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "radio" msgstr "radio"
@ -379,93 +380,93 @@ msgstr "cerrar"
msgid "answered" msgid "answered"
msgstr "contestado" msgstr "contestado"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Ningún artículo encontrado" msgstr "Ningún artículo encontrado"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Fuente" msgstr "Fuente"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Error al cargar la siguiente página" msgstr "Error al cargar la siguiente página"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Ajustes inválidos, por favor, cambia tus preferencias" msgstr "Ajustes inválidos, por favor, cambia tus preferencias"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Ajustes inválidos" msgstr "Ajustes inválidos"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "error en la búsqueda" msgstr "error en la búsqueda"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "expirado" msgstr "expirado"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "error de análisis" msgstr "error de análisis"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "Error de protocolo HTTP" msgstr "Error de protocolo HTTP"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "error de red" msgstr "error de red"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "Error SSL: la validación del certificado ha fallado" msgstr "Error SSL: la validación del certificado ha fallado"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "cierre inesperado" msgstr "cierre inesperado"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "Error de HTTP" msgstr "Error de HTTP"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "Error de conexión HTTP" msgstr "Error de conexión HTTP"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "error de proxy" msgstr "error de proxy"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "demasiadas peticiones" msgstr "demasiadas peticiones"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "acceso denegado" msgstr "acceso denegado"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "error en la API del servidor" msgstr "error en la API del servidor"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Suspendido" msgstr "Suspendido"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "hace {minutes} minuto(s)" msgstr "hace {minutes} minuto(s)"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "hace {hours} hora(s) y {minutes} minuto(s)" msgstr "hace {hours} hora(s) y {minutes} minuto(s)"
@ -496,15 +497,15 @@ msgstr "Esta entrada ha sido sustituida por"
msgid "Channel" msgid "Channel"
msgstr "Canal" msgstr "Canal"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "bitrate" msgstr "bitrate"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "votos" msgstr "votos"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "clics" msgstr "clics"
@ -513,7 +514,7 @@ msgstr "clics"
msgid "Language" msgid "Language"
msgstr "Idioma" msgstr "Idioma"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -558,7 +559,7 @@ msgstr "Lista negra de Ahmia"
#: searx/plugins/ahmia_filter.py:33 #: searx/plugins/ahmia_filter.py:33
msgid "Filter out onion results that appear in Ahmia's blacklist." msgid "Filter out onion results that appear in Ahmia's blacklist."
msgstr "" msgstr "Filtrar resultados de onion que aparezcan en la lista negra de Ahmia."
#: searx/plugins/calculator.py:38 #: searx/plugins/calculator.py:38
msgid "Basic Calculator" msgid "Basic Calculator"
@ -741,10 +742,6 @@ msgstr "Autor"
msgid "cached" msgid "cached"
msgstr "en caché" msgstr "en caché"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "por un proxy"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Enviar un nuevo problema a GitHub" msgstr "Enviar un nuevo problema a GitHub"
@ -2134,3 +2131,6 @@ msgstr "ocultar video"
#~ "URL de preferencias puede usarse para" #~ "URL de preferencias puede usarse para"
#~ " sincronizar las preferencias entre " #~ " sincronizar las preferencias entre "
#~ "dispositivos." #~ "dispositivos."
#~ msgid "proxied"
#~ msgstr "por un proxy"

View file

@ -20,8 +20,8 @@ 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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-03-30 01:58+0000\n" "PO-Revision-Date: 2025-05-23 07:10+0000\n"
"Last-Translator: Priit Jõerüüt <jrtcdbrg@noreply.codeberg.org>\n" "Last-Translator: Priit Jõerüüt <jrtcdbrg@noreply.codeberg.org>\n"
"Language-Team: Estonian <https://translate.codeberg.org/projects/searxng/" "Language-Team: Estonian <https://translate.codeberg.org/projects/searxng/"
"searxng/et/>\n" "searxng/et/>\n"
@ -30,7 +30,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.10.2\n" "X-Generator: Weblate 5.11.4\n"
"Generated-By: Babel 2.17.0\n" "Generated-By: Babel 2.17.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -74,7 +74,7 @@ msgid "videos"
msgstr "videod" msgstr "videod"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "raadio" msgstr "raadio"
@ -351,93 +351,93 @@ msgstr "suletud"
msgid "answered" msgid "answered"
msgstr "vastatud" msgstr "vastatud"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Üksust ei leitud" msgstr "Üksust ei leitud"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Allikas" msgstr "Allikas"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Viga järgmise lehekülje laadimisel" msgstr "Viga järgmise lehekülje laadimisel"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Sobimatud seaded, palun muuda oma eelistusi" msgstr "Sobimatud seaded, palun muuda oma eelistusi"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Sobimatud seaded" msgstr "Sobimatud seaded"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "otsingu viga" msgstr "otsingu viga"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "päring aegus" msgstr "päring aegus"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "parsimise viga" msgstr "parsimise viga"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "HTTP-protokolli viga" msgstr "HTTP-protokolli viga"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "võrguviga" msgstr "võrguviga"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "SSL viga: sertifikaadi valideerimine ei õnnestunud" msgstr "SSL viga: sertifikaadi valideerimine ei õnnestunud"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "ootamatu krahh" msgstr "ootamatu krahh"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "HTTP-viga" msgstr "HTTP-viga"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "HTTP-ühenduse viga" msgstr "HTTP-ühenduse viga"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "proksiserveri viga" msgstr "proksiserveri viga"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "ROBOTILÕKS" msgstr "ROBOTILÕKS"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "liiga palju päringuid" msgstr "liiga palju päringuid"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "ligipääs keelatud" msgstr "ligipääs keelatud"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "serveri API viga" msgstr "serveri API viga"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Peatatud" msgstr "Peatatud"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "{minutes} minut(it) tagasi" msgstr "{minutes} minut(it) tagasi"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "{hours} tund(i), {minutes} minut(it) tagasi" msgstr "{hours} tund(i), {minutes} minut(it) tagasi"
@ -468,15 +468,15 @@ msgstr "See üksus on asendatud"
msgid "Channel" msgid "Channel"
msgstr "Kanal" msgstr "Kanal"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "bitikiirus" msgstr "bitikiirus"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "hääled" msgstr "hääled"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "klikid" msgstr "klikid"
@ -485,7 +485,7 @@ msgstr "klikid"
msgid "Language" msgid "Language"
msgstr "Keel" msgstr "Keel"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -686,7 +686,7 @@ msgstr "Avalikud serverid"
#: searx/templates/simple/base.html:75 #: searx/templates/simple/base.html:75
msgid "Privacy policy" msgid "Privacy policy"
msgstr "Privaatsuspoliitika" msgstr "Andmekaitsepõhimõtted"
#: searx/templates/simple/base.html:78 #: searx/templates/simple/base.html:78
msgid "Contact instance maintainer" msgid "Contact instance maintainer"
@ -715,10 +715,6 @@ msgstr "Autor"
msgid "cached" msgid "cached"
msgstr "vahemälus" msgstr "vahemälus"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "proksiserveris"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Alusta veateate või ettepaneku koostamist GitHubis" msgstr "Alusta veateate või ettepaneku koostamist GitHubis"
@ -2076,3 +2072,6 @@ msgstr "peida video"
#~ "Kohandatud seadete määramine eelistuste URL-i" #~ "Kohandatud seadete määramine eelistuste URL-i"
#~ " saad kasutada eelistuste sünkroniseerimiseks " #~ " saad kasutada eelistuste sünkroniseerimiseks "
#~ "eri seadmete vahel." #~ "eri seadmete vahel."
#~ msgid "proxied"
#~ msgstr "proksiserveris"

View file

@ -18,7 +18,7 @@ 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: 2025-03-29 09:21+0000\n" "POT-Creation-Date: 2025-05-13 19:13+0000\n"
"PO-Revision-Date: 2025-02-12 15:39+0000\n" "PO-Revision-Date: 2025-02-12 15:39+0000\n"
"Last-Translator: alexgabi <alexgabi@users.noreply.translate.codeberg.org>" "Last-Translator: alexgabi <alexgabi@users.noreply.translate.codeberg.org>"
"\n" "\n"
@ -72,7 +72,7 @@ msgid "videos"
msgstr "bideoak" msgstr "bideoak"
#. CATEGORY_NAMES['RADIO'] #. CATEGORY_NAMES['RADIO']
#: searx/engines/radio_browser.py:103 searx/searxng.msg #: searx/engines/radio_browser.py:151 searx/searxng.msg
msgid "radio" msgid "radio"
msgstr "irratia" msgstr "irratia"
@ -349,93 +349,93 @@ msgstr "itxita"
msgid "answered" msgid "answered"
msgstr "erantzunda" msgstr "erantzunda"
#: searx/webapp.py:312 #: searx/webapp.py:291
msgid "No item found" msgid "No item found"
msgstr "Ez da elementurik aurkitu" msgstr "Ez da elementurik aurkitu"
#: searx/engines/qwant.py:291 #: searx/engines/qwant.py:291
#: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:314 #: searx/templates/simple/result_templates/images.html:23 searx/webapp.py:293
msgid "Source" msgid "Source"
msgstr "Iturria" msgstr "Iturria"
#: searx/webapp.py:316 #: searx/webapp.py:295
msgid "Error loading the next page" msgid "Error loading the next page"
msgstr "Errorea hurrengo orrialdea kargatzean" msgstr "Errorea hurrengo orrialdea kargatzean"
#: searx/webapp.py:469 searx/webapp.py:875 #: searx/webapp.py:446 searx/webapp.py:844
msgid "Invalid settings, please edit your preferences" msgid "Invalid settings, please edit your preferences"
msgstr "Ezarpen baliogabeak, editatu zure hobespenak" msgstr "Ezarpen baliogabeak, editatu zure hobespenak"
#: searx/webapp.py:485 #: searx/webapp.py:462
msgid "Invalid settings" msgid "Invalid settings"
msgstr "Ezarpen baliogabeak" msgstr "Ezarpen baliogabeak"
#: searx/webapp.py:562 searx/webapp.py:652 #: searx/webapp.py:539 searx/webapp.py:629
msgid "search error" msgid "search error"
msgstr "bilaketa akatsa" msgstr "bilaketa akatsa"
#: searx/webutils.py:36 #: searx/webutils.py:35
msgid "timeout" msgid "timeout"
msgstr "itxarote-denbora" msgstr "itxarote-denbora"
#: searx/webutils.py:37 #: searx/webutils.py:36
msgid "parsing error" msgid "parsing error"
msgstr "analizatze errorea" msgstr "analizatze errorea"
#: searx/webutils.py:38 #: searx/webutils.py:37
msgid "HTTP protocol error" msgid "HTTP protocol error"
msgstr "HTTP protokoloaren errorea" msgstr "HTTP protokoloaren errorea"
#: searx/webutils.py:39 #: searx/webutils.py:38
msgid "network error" msgid "network error"
msgstr "sareko errorea" msgstr "sareko errorea"
#: searx/webutils.py:40 #: searx/webutils.py:39
msgid "SSL error: certificate validation has failed" msgid "SSL error: certificate validation has failed"
msgstr "SSL errorea: ziurtagiria baliozkotzeak huts egin du" msgstr "SSL errorea: ziurtagiria baliozkotzeak huts egin du"
#: searx/webutils.py:42 #: searx/webutils.py:41
msgid "unexpected crash" msgid "unexpected crash"
msgstr "ustekabeko kraskatzea" msgstr "ustekabeko kraskatzea"
#: searx/webutils.py:49 #: searx/webutils.py:48
msgid "HTTP error" msgid "HTTP error"
msgstr "HTTP errorea" msgstr "HTTP errorea"
#: searx/webutils.py:50 #: searx/webutils.py:49
msgid "HTTP connection error" msgid "HTTP connection error"
msgstr "HTTP konexioaren errorea" msgstr "HTTP konexioaren errorea"
#: searx/webutils.py:56 #: searx/webutils.py:55
msgid "proxy error" msgid "proxy error"
msgstr "proxy-aren errorea" msgstr "proxy-aren errorea"
#: searx/webutils.py:57 #: searx/webutils.py:56
msgid "CAPTCHA" msgid "CAPTCHA"
msgstr "CAPTCHA" msgstr "CAPTCHA"
#: searx/webutils.py:58 #: searx/webutils.py:57
msgid "too many requests" msgid "too many requests"
msgstr "eskaera gehiegi" msgstr "eskaera gehiegi"
#: searx/webutils.py:59 #: searx/webutils.py:58
msgid "access denied" msgid "access denied"
msgstr "sarbidea ukatua" msgstr "sarbidea ukatua"
#: searx/webutils.py:60 #: searx/webutils.py:59
msgid "server API error" msgid "server API error"
msgstr "API zerbitzariaren errorea" msgstr "API zerbitzariaren errorea"
#: searx/webutils.py:79 #: searx/webutils.py:78
msgid "Suspended" msgid "Suspended"
msgstr "Etenda" msgstr "Etenda"
#: searx/webutils.py:314 #: searx/webutils.py:313
#, python-brace-format #, python-brace-format
msgid "{minutes} minute(s) ago" msgid "{minutes} minute(s) ago"
msgstr "duela {minutes} minutu" msgstr "duela {minutes} minutu"
#: searx/webutils.py:315 #: searx/webutils.py:314
#, python-brace-format #, python-brace-format
msgid "{hours} hour(s), {minutes} minute(s) ago" msgid "{hours} hour(s), {minutes} minute(s) ago"
msgstr "duela {hours} ordu eta {minutes} minutu" msgstr "duela {hours} ordu eta {minutes} minutu"
@ -466,15 +466,15 @@ msgstr "Sarrera hau hurrengoarekin ordezkatu da"
msgid "Channel" msgid "Channel"
msgstr "Kanala" msgstr "Kanala"
#: searx/engines/radio_browser.py:105 #: searx/engines/radio_browser.py:153
msgid "bitrate" msgid "bitrate"
msgstr "bit emaria" msgstr "bit emaria"
#: searx/engines/radio_browser.py:106 #: searx/engines/radio_browser.py:154
msgid "votes" msgid "votes"
msgstr "botoak" msgstr "botoak"
#: searx/engines/radio_browser.py:107 #: searx/engines/radio_browser.py:155
msgid "clicks" msgid "clicks"
msgstr "klikak" msgstr "klikak"
@ -483,7 +483,7 @@ msgstr "klikak"
msgid "Language" msgid "Language"
msgstr "Hizkuntza" msgstr "Hizkuntza"
#: searx/engines/semantic_scholar.py:79 #: searx/engines/semantic_scholar.py:101
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"{numCitations} citations from the year {firstCitationVelocityYear} to " "{numCitations} citations from the year {firstCitationVelocityYear} to "
@ -711,10 +711,6 @@ msgstr "Egilea"
msgid "cached" msgid "cached"
msgstr "cachean gordeta" msgstr "cachean gordeta"
#: searx/templates/simple/macros.html:50
msgid "proxied"
msgstr "proxyan gordeta"
#: searx/templates/simple/new_issue.html:64 #: searx/templates/simple/new_issue.html:64
msgid "Start submitting a new issue on GitHub" msgid "Start submitting a new issue on GitHub"
msgstr "Hasi gai -issue- berri bat bidaltzen GitHub-en" msgstr "Hasi gai -issue- berri bat bidaltzen GitHub-en"
@ -2072,3 +2068,6 @@ msgstr "ezkutatu bideoa"
#~ "zehaztea erabil daiteke gailuen hobespenak " #~ "zehaztea erabil daiteke gailuen hobespenak "
#~ "sinkronizatzeko." #~ "sinkronizatzeko."
#~ msgid "proxied"
#~ msgstr "proxyan gordeta"

Some files were not shown because too many files have changed in this diff Show more