Compare commits

...

17 Commits

Author SHA1 Message Date
Grant Lanham Jr 35c74b0829
Merge 81f0cb01e8 into b07c0ae39f 2024-11-05 08:58:56 +01:00
Bnyro b07c0ae39f [fix] annas archive: crash when no thumbnail, differing results, paging 2024-11-01 12:49:33 +01:00
Markus Heiser 56e3d72a76 [fix] CI: remove target test.coverage from python's test matrix
The test.coverage cause a lot of failed CI jobs for reasons that cannot be
explained.  As we do not monitor the coverage anyway, it is superfluous to run
this job, especially as it only has a disruptive effect on the CI.

BTW and the CI action upload-artifact@v3 is deprecated [1]

[1] https://github.com/actions/upload-artifact?tab=readme-ov-file#actionsupload-artifact

Related: https://github.com/searxng/searxng/issues/3983
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2024-11-01 10:14:57 +01:00
searxng-bot cc148a76b0 [l10n] update translations from Weblate
a4cdaaa26 - 2024-10-30 - Juno Takano <jutty@users.noreply.translate.codeberg.org>
46bad3a79 - 2024-10-29 - saltsnorter <saltsnorter@users.noreply.translate.codeberg.org>
6a4096da9 - 2024-10-27 - Eryk Michalak <gnu.ewm@protonmail.com>
64815d956 - 2024-10-28 - ljansen <ljansen@users.noreply.translate.codeberg.org>
851ae554d - 2024-10-26 - return42 <return42@users.noreply.translate.codeberg.org>
24f16d5e3 - 2024-10-26 - return42 <return42@users.noreply.translate.codeberg.org>
8278d1cb9 - 2024-10-26 - Atul_Eterno <Atul_Eterno@users.noreply.translate.codeberg.org>
2024-11-01 08:30:38 +01:00
uply23333 fa108c140f [fix] google: display every result when keyword is contained in content field 2024-10-31 13:21:32 +01:00
Markus Heiser fa4dfd4efe [fix] favicons: msgspec.ValidationError: Expected `Path`, got `str` - at `$.favicons.cache.db_url`
Closes: https://github.com/searxng/searxng/issues/3975
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2024-10-29 18:22:22 +01:00
Markus Heiser b183e620d8 [refactor] engine: duckduckgo - https://html.duckduckgo.com/html
The entire source code of the duckduckgo engine has been reengineered and
purified.

1. DDG used the URL https://html.duckduckgo.com/html for no-JS requests whose
   response is also easier to parse than the previous
   https://lite.duckduckgo.com/lite/ URL

2. the bot detection of DDG has so far caused problems and often led to a
   CAPTCHA, this can be circumvented using `'Sec-Fetch-Mode'] = “navigate”`

Closes: https://github.com/searxng/searxng/issues/3927
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2024-10-29 14:56:27 +01:00
Markus Heiser f63f97c56c Revert "Fix for broken docker builds"
This reverts commit 4ef1c706f8.
2024-10-29 13:50:38 +01:00
Markus Heiser 163031c394 Revert "[fix] typo in Dockerfile"
This reverts commit 038a2ff6bd.
2024-10-29 13:50:38 +01:00
Markus Heiser 3e5621e1af [refactor] replace pydantic by msgspec
Signed-off-by: Markus Heiser <markus.heiser@darmarit.de>
2024-10-29 13:50:38 +01:00
return42 e392892578 [data] update searx.data - update_firefox_version.py 2024-10-29 09:30:40 +01:00
return42 68ed8245da [data] update searx.data - update_ahmia_blacklist.py 2024-10-29 09:29:58 +01:00
return42 2d748d1d74 [data] update searx.data - update_currencies.py 2024-10-29 09:29:18 +01:00
return42 2985ece0ca [data] update searx.data - update_wikidata_units.py 2024-10-29 09:28:58 +01:00
return42 adc38c5800 [data] update searx.data - update_engine_traits.py 2024-10-29 09:28:28 +01:00
return42 a084436ff4 [data] update searx.data - update_engine_descriptions.py 2024-10-29 09:17:30 +01:00
Grant Lanham 81f0cb01e8 Remove RawTextQuery.changeQuery in favor of getNewFullQuery
Also includes the following:
- Introduce typing in RawTextQuery
- Remove an outdated description based on the change
- Refactor setting the autocomplete_location, its more clear to set the
variable in the construct instead of within the method
- Update unit tests to reflect the new method

rephrasing

format

undo change
2024-06-16 14:18:31 -04:00
33 changed files with 3631 additions and 515 deletions

View File

@ -45,14 +45,6 @@ jobs:
make V=1 gecko.driver make V=1 gecko.driver
- name: Run tests - name: Run tests
run: make V=1 ci.test run: make V=1 ci.test
- name: Test coverage
run: make V=1 test.coverage
- name: Store coverage result
uses: actions/upload-artifact@v3
with:
name: coverage-${{ matrix.python-version }}
path: coverage/
retention-days: 60
themes: themes:
name: Themes name: Themes

View File

@ -43,16 +43,9 @@ RUN apk add --no-cache -t build-dependencies \
tini \ tini \
uwsgi \ uwsgi \
uwsgi-python3 \ uwsgi-python3 \
brotli brotli \
&& pip3 install --break-system-packages --no-cache -r requirements.txt \
# For 32bit arm architecture install pydantic from the alpine repos instead of requirements.txt && apk del build-dependencies \
ARG TARGETARCH
RUN if [ "$TARGETARCH" = "arm" ]; then \
apk add --no-cache py3-pydantic && pip install --no-cache --break-system-packages -r <(grep -v '^pydantic' requirements.txt); \
else \
pip install --no-cache --break-system-packages -r requirements.txt; \
fi
RUN apk del build-dependencies \
&& rm -rf /root/.cache && rm -rf /root/.cache
COPY --chown=searxng:searxng dockerfiles ./dockerfiles COPY --chown=searxng:searxng dockerfiles ./dockerfiles

View File

@ -16,6 +16,6 @@ redis==5.0.8
markdown-it-py==3.0.0 markdown-it-py==3.0.0
fasttext-predict==0.9.2.2 fasttext-predict==0.9.2.2
tomli==2.0.2; python_version < '3.11' tomli==2.0.2; python_version < '3.11'
pydantic==2.9.2 msgspec==0.18.6
eval_type_backport; python_version < '3.9' eval_type_backport; python_version < '3.9'
typer-slim==0.12.5 typer-slim==0.12.5

File diff suppressed because it is too large Load Diff

View File

@ -82,7 +82,7 @@
"af": "Albanese lek", "af": "Albanese lek",
"ar": "ليك ألباني", "ar": "ليك ألباني",
"bg": "Албански лек", "bg": "Албански лек",
"ca": "lek", "ca": "Lek (moneda)",
"cs": "Albánský lek", "cs": "Albánský lek",
"cy": "Lek", "cy": "Lek",
"da": "Lek", "da": "Lek",
@ -383,6 +383,7 @@
"nl": "Azerbeidzjaanse manat", "nl": "Azerbeidzjaanse manat",
"oc": "Manat", "oc": "Manat",
"pa": "ਅਜ਼ਰਬਾਈਜਾਨੀ ਮਨਾਤ", "pa": "ਅਜ਼ਰਬਾਈਜਾਨੀ ਮਨਾਤ",
"pap": "Manat Azerbaijano",
"pl": "Manat azerski", "pl": "Manat azerski",
"pt": "Manat azeri", "pt": "Manat azeri",
"ro": "Manat azer", "ro": "Manat azer",
@ -606,6 +607,7 @@
"pt": "Franco do Burúndi", "pt": "Franco do Burúndi",
"ro": "franc burundez", "ro": "franc burundez",
"ru": "бурундийский франк", "ru": "бурундийский франк",
"sk": "Burundský frank",
"sl": "burundijski frank", "sl": "burundijski frank",
"sr": "бурундски франак", "sr": "бурундски франак",
"sv": "Burundisk franc", "sv": "Burundisk franc",
@ -1327,6 +1329,7 @@
"pl": "escudo Zielonego Przylądka", "pl": "escudo Zielonego Przylądka",
"pt": "escudo cabo-verdiano", "pt": "escudo cabo-verdiano",
"ru": "Эскудо Кабо-Верде", "ru": "Эскудо Кабо-Верде",
"sk": "Kapverdské escudo",
"sl": "zelenortski eskudo", "sl": "zelenortski eskudo",
"sr": "зеленортски ескудо", "sr": "зеленортски ескудо",
"sv": "Kapverdisk escudo", "sv": "Kapverdisk escudo",
@ -1405,6 +1408,7 @@
"pl": "frank Dżibuti", "pl": "frank Dżibuti",
"pt": "franco do Jibuti", "pt": "franco do Jibuti",
"ru": "Франк Джибути", "ru": "Франк Джибути",
"sk": "Džibutský frank",
"sr": "џибутски франак", "sr": "џибутски франак",
"sv": "Djiboutisk franc", "sv": "Djiboutisk franc",
"tr": "Cibuti frangı", "tr": "Cibuti frangı",
@ -1518,6 +1522,7 @@
"pt": "dinar argelino", "pt": "dinar argelino",
"ro": "Dinar algerian", "ro": "Dinar algerian",
"ru": "алжирский динар", "ru": "алжирский динар",
"sk": "Alžírský dinár",
"sl": "alžirski dinar", "sl": "alžirski dinar",
"sr": "алжирски динар", "sr": "алжирски динар",
"sv": "Algerisk dinar", "sv": "Algerisk dinar",
@ -1969,6 +1974,7 @@
"pl": "frank gwinejski", "pl": "frank gwinejski",
"pt": "Franco da Guiné", "pt": "Franco da Guiné",
"ru": "Гвинейский франк", "ru": "Гвинейский франк",
"sk": "Guinejský frank",
"sl": "gvinejski frank", "sl": "gvinejski frank",
"sr": "гвинејски франак", "sr": "гвинејски франак",
"sv": "Guinesisk franc", "sv": "Guinesisk franc",
@ -2689,6 +2695,7 @@
"pt": "Franco comoriano", "pt": "Franco comoriano",
"ro": "Franc comorian", "ro": "Franc comorian",
"ru": "Франк Комор", "ru": "Франк Комор",
"sk": "Komorský frank",
"sr": "коморски франак", "sr": "коморски франак",
"sv": "Komoransk franc", "sv": "Komoransk franc",
"tr": "Komor frangı", "tr": "Komor frangı",
@ -2986,6 +2993,7 @@
"pt": "rúpia do Sri Lanka", "pt": "rúpia do Sri Lanka",
"ru": "ланкийская рупия", "ru": "ланкийская рупия",
"si": "ශ්රී ලංකා රුපියල", "si": "ශ්රී ලංකා රුපියල",
"sk": "Srílanská rupia",
"sl": "šrilanška rupija", "sl": "šrilanška rupija",
"sr": "шриланчанска рупија", "sr": "шриланчанска рупија",
"sv": "Lankesisk rupie", "sv": "Lankesisk rupie",
@ -3059,7 +3067,7 @@
"uk": "Лоті" "uk": "Лоті"
}, },
"LYD": { "LYD": {
"ar": "دينار ليبي", "ar": "دينار ذهبي",
"bg": "Либийски динар", "bg": "Либийски динар",
"ca": "dinar libi", "ca": "dinar libi",
"cs": "Libyjský dinár", "cs": "Libyjský dinár",
@ -3121,6 +3129,7 @@
"pt": "Dirham marroquino", "pt": "Dirham marroquino",
"ro": "Dirham marocan", "ro": "Dirham marocan",
"ru": "марокканский дирхам", "ru": "марокканский дирхам",
"sk": "Marocký dirham",
"sl": "maroški dirham", "sl": "maroški dirham",
"sr": "марокански дирхам", "sr": "марокански дирхам",
"sv": "Marockansk dirham", "sv": "Marockansk dirham",
@ -3140,6 +3149,7 @@
"et": "Moldova leu", "et": "Moldova leu",
"fi": "Moldovan leu", "fi": "Moldovan leu",
"fr": "leu moldave", "fr": "leu moldave",
"gl": "leu moldovo",
"he": "לאו מולדובני", "he": "לאו מולדובני",
"hr": "moldavski lej", "hr": "moldavski lej",
"hu": "moldován lej", "hu": "moldován lej",
@ -3371,6 +3381,7 @@
"pl": "Ugija", "pl": "Ugija",
"pt": "Uguia", "pt": "Uguia",
"ru": "Мавританская угия", "ru": "Мавританская угия",
"sk": "Mauritánska ukíjá",
"sr": "мауританска огија", "sr": "мауританска огија",
"sv": "Mauretansk ouguiya", "sv": "Mauretansk ouguiya",
"tr": "Ugiya", "tr": "Ugiya",
@ -3816,6 +3827,7 @@
"sl": "novozelandski dolar", "sl": "novozelandski dolar",
"sr": "новозеландски долар", "sr": "новозеландски долар",
"sv": "Nyzeeländsk dollar", "sv": "Nyzeeländsk dollar",
"th": "ดอลลาร์นิวซีแลนด์",
"tr": "Yeni Zelanda doları", "tr": "Yeni Zelanda doları",
"uk": "новозеландський долар", "uk": "новозеландський долар",
"vi": "Đô la New Zealand" "vi": "Đô la New Zealand"
@ -5386,12 +5398,14 @@
"ja": "スム", "ja": "スム",
"ko": "우즈베키스탄 숨", "ko": "우즈베키스탄 숨",
"lt": "Uzbekijos sumas", "lt": "Uzbekijos sumas",
"lv": "Uzbekistānas soms",
"nl": "Oezbeekse sum", "nl": "Oezbeekse sum",
"pa": "ਉਜ਼ਬੇਕਿਸਤਾਨੀ ਸੋਮ", "pa": "ਉਜ਼ਬੇਕਿਸਤਾਨੀ ਸੋਮ",
"pl": "Sum", "pl": "Sum",
"pt": "som usbeque", "pt": "som usbeque",
"ro": "Som uzbec", "ro": "Som uzbec",
"ru": "узбекский сум", "ru": "узбекский сум",
"sk": "Uzbecký som",
"sr": "узбекистански сом", "sr": "узбекистански сом",
"sv": "Uzbekistansk som", "sv": "Uzbekistansk som",
"tr": "Özbekistan somu", "tr": "Özbekistan somu",
@ -5645,7 +5659,7 @@
"eo": "specialaj rajtoj de enspezo", "eo": "specialaj rajtoj de enspezo",
"es": "Derechos Especiales de Giro", "es": "Derechos Especiales de Giro",
"eu": "igorpen eskubide bereziak", "eu": "igorpen eskubide bereziak",
"fi": "Erityisnosto-oikeus", "fi": "erityisnosto-oikeus",
"fr": "droits de tirage spéciaux", "fr": "droits de tirage spéciaux",
"hr": "Posebna prava vučenja", "hr": "Posebna prava vučenja",
"hu": "különleges lehívási jog", "hu": "különleges lehívási jog",
@ -5655,6 +5669,7 @@
"ko": "특별인출권", "ko": "특별인출권",
"lt": "Specialiosios skolinimosi teisės", "lt": "Specialiosios skolinimosi teisės",
"lv": "Speciālās aizņēmuma tiesības", "lv": "Speciālās aizņēmuma tiesības",
"ms": "hak pengeluaran khas",
"nl": "speciale trekkingsrechten", "nl": "speciale trekkingsrechten",
"oc": "Drechs de tiratge Especials", "oc": "Drechs de tiratge Especials",
"pl": "specjalne prawa ciągnienia", "pl": "specjalne prawa ciągnienia",
@ -5837,7 +5852,7 @@
"lt": "Randas", "lt": "Randas",
"lv": "Dienvidāfrikas rands", "lv": "Dienvidāfrikas rands",
"ml": "സൗത്ത് ആഫ്രിക്കൻ റാൻഡ്", "ml": "സൗത്ത് ആഫ്രിക്കൻ റാൻഡ്",
"ms": "Rand", "ms": "Rand Afrika Selatan",
"nl": "Zuid-Afrikaanse rand", "nl": "Zuid-Afrikaanse rand",
"oc": "Rand sudafrican", "oc": "Rand sudafrican",
"pl": "Rand", "pl": "Rand",
@ -5900,6 +5915,7 @@
"ko": "짐바브웨 골드", "ko": "짐바브웨 골드",
"nl": "Zimbabwe Gold", "nl": "Zimbabwe Gold",
"pl": "Złoto Zimbabwe", "pl": "Złoto Zimbabwe",
"pt": "Ouro do Zimbábue",
"ru": "зимбабвийский золотой", "ru": "зимбабвийский золотой",
"sk": "zimbabwiansky zlatý", "sk": "zimbabwiansky zlatý",
"sl": "zimbabvejski gold", "sl": "zimbabvejski gold",
@ -7817,6 +7833,7 @@
"eritrese nakfa": "ERN", "eritrese nakfa": "ERN",
"erityinen nosto oikeus": "XDR", "erityinen nosto oikeus": "XDR",
"erityiset nosto oikeudet": "XDR", "erityiset nosto oikeudet": "XDR",
"erityisnosto oikeudet": "XDR",
"erityisnosto oikeus": "XDR", "erityisnosto oikeus": "XDR",
"ermeni dramı": "AMD", "ermeni dramı": "AMD",
"ermenistan dramı": "AMD", "ermenistan dramı": "AMD",
@ -8372,6 +8389,8 @@
"haitský gourde": "HTG", "haitský gourde": "HTG",
"haïtiaanse gourde": "HTG", "haïtiaanse gourde": "HTG",
"hak penarikan khusus": "XDR", "hak penarikan khusus": "XDR",
"hak pengeluaran khas": "XDR",
"hak pengeluaran khusus": "XDR",
"halalas": "SAR", "halalas": "SAR",
"hegoafrikar rand": "ZAR", "hegoafrikar rand": "ZAR",
"heller": "CZK", "heller": "CZK",
@ -9115,6 +9134,7 @@
"leu da roménia": "RON", "leu da roménia": "RON",
"leu da romênia": "RON", "leu da romênia": "RON",
"leu de moldàvia": "MDL", "leu de moldàvia": "MDL",
"leu de moldova": "MDL",
"leu moldau": "MDL", "leu moldau": "MDL",
"leu moldave": "MDL", "leu moldave": "MDL",
"leu moldavo": "MDL", "leu moldavo": "MDL",
@ -9122,6 +9142,7 @@
"leu moldofa": "MDL", "leu moldofa": "MDL",
"leu moldova": "MDL", "leu moldova": "MDL",
"leu moldovenesc": "MDL", "leu moldovenesc": "MDL",
"leu moldovo": "MDL",
"leu romanès": "RON", "leu romanès": "RON",
"leu romanés": "RON", "leu romanés": "RON",
"leu romanian": "RON", "leu romanian": "RON",
@ -9437,6 +9458,7 @@
"manat azerbaijandar": "AZN", "manat azerbaijandar": "AZN",
"manat azerbaijanês": "AZN", "manat azerbaijanês": "AZN",
"manat azerbaijano": "AZN", "manat azerbaijano": "AZN",
"manat azerbaitjanés": "AZN",
"manat azerbaiyano": "AZN", "manat azerbaiyano": "AZN",
"manat azerbaïdjanais": "AZN", "manat azerbaïdjanais": "AZN",
"manat azerbejdżański": "AZN", "manat azerbejdżański": "AZN",
@ -9520,6 +9542,7 @@
"mauritanijska ouguja": "MRU", "mauritanijska ouguja": "MRU",
"mauritanijska uguija": "MRU", "mauritanijska uguija": "MRU",
"mauritániai ouguiya": "MRU", "mauritániai ouguiya": "MRU",
"mauritánska ukíjá": "MRU",
"mauritánská ukíjá": "MRU", "mauritánská ukíjá": "MRU",
"mauritānijas oguja": "MRU", "mauritānijas oguja": "MRU",
"mauritiaanse roepee": "MUR", "mauritiaanse roepee": "MUR",
@ -9985,6 +10008,7 @@
"ouguiya mauritana": "MRU", "ouguiya mauritana": "MRU",
"ouguiya mauritanien": "MRU", "ouguiya mauritanien": "MRU",
"ouguiya mawritania": "MRU", "ouguiya mawritania": "MRU",
"ouro do zimbábue": "ZWG",
"örmény dram": "AMD", "örmény dram": "AMD",
"östkaribisk dollar": "XCD", "östkaribisk dollar": "XCD",
"özbekistan somu": "UZS", "özbekistan somu": "UZS",
@ -10796,6 +10820,7 @@
"salomona dolaro": "SBD", "salomona dolaro": "SBD",
"salomondollar": "SBD", "salomondollar": "SBD",
"salomonen dollar": "SBD", "salomonen dollar": "SBD",
"salomoninsaarten dollari": "SBD",
"salomonsaarten dollari": "SBD", "salomonsaarten dollari": "SBD",
"salomonskootočni dolar": "SBD", "salomonskootočni dolar": "SBD",
"salüng": "THB", "salüng": "THB",
@ -11152,6 +11177,7 @@
"srilankansk rupee": "LKR", "srilankansk rupee": "LKR",
"srilankanske rupee": "LKR", "srilankanske rupee": "LKR",
"srí lanka i rúpia": "LKR", "srí lanka i rúpia": "LKR",
"srílanská rupia": "LKR",
"srílanská rupie": "LKR", "srílanská rupie": "LKR",
"srpski dinar": "RSD", "srpski dinar": "RSD",
"ssp": "SSP", "ssp": "SSP",
@ -11415,6 +11441,7 @@
"tengue": "KZT", "tengue": "KZT",
"tengue cazaque": "KZT", "tengue cazaque": "KZT",
"teňňe": "TMT", "teňňe": "TMT",
"tetri": "GEL",
"thai baht": "THB", "thai baht": "THB",
"thai bát": "THB", "thai bát": "THB",
"thailandiar baht": "THB", "thailandiar baht": "THB",
@ -11539,10 +11566,10 @@
"turkisk lira": "TRY", "turkisk lira": "TRY",
"turkiska lira": "TRY", "turkiska lira": "TRY",
"turkmeense manat": "TMT", "turkmeense manat": "TMT",
"turkmen manat": "TMT",
"turkmena manato": "TMT", "turkmena manato": "TMT",
"turkmenistan manat": "TMT", "turkmenistan manat": "TMT",
"turkmenistan new manat": "TMT", "turkmenistan new manat": "TMT",
"turkmenistani manat": "TMT",
"turkmenistani new manat": "TMT", "turkmenistani new manat": "TMT",
"turkmenistanin manat": "TMT", "turkmenistanin manat": "TMT",
"turkmenistansk manat": "TMT", "turkmenistansk manat": "TMT",
@ -11708,6 +11735,7 @@
"uzbekistano sumas": "UZS", "uzbekistano sumas": "UZS",
"uzbekistansk som": "UZS", "uzbekistansk som": "UZS",
"uzbekistanski som": "UZS", "uzbekistanski som": "UZS",
"uzbekistānas soms": "UZS",
"uzs": "UZS", "uzs": "UZS",
"új zélandi dollár": "NZD", "új zélandi dollár": "NZD",
"ürdün dinarı": "JOD", "ürdün dinarı": "JOD",
@ -11861,6 +11889,7 @@
"yuan cinese": "CNY", "yuan cinese": "CNY",
"yuan renmimbi": "CNY", "yuan renmimbi": "CNY",
"yuan renminbi": "CNY", "yuan renminbi": "CNY",
"yuan rmb": "CNY",
"yuans": "CNY", "yuans": "CNY",
"yuán chino": "CNY", "yuán chino": "CNY",
"z$": "ZWL", "z$": "ZWL",
@ -13734,6 +13763,7 @@
"دينار بحريني": "BHD", "دينار بحريني": "BHD",
"دينار تونسي": "TND", "دينار تونسي": "TND",
"دينار جزائري": "DZD", "دينار جزائري": "DZD",
"دينار ذهبي": "LYD",
"دينار سوداني": "SDG", "دينار سوداني": "SDG",
"دينار صربي": "RSD", "دينار صربي": "RSD",
"دينار عراقي": "IQD", "دينار عراقي": "IQD",
@ -14326,6 +14356,7 @@
"USD", "USD",
"TWD" "TWD"
], ],
"ดอลลาร์นิวซีแลนด์": "NZD",
"ดอลลาร์บรูไน": "BND", "ดอลลาร์บรูไน": "BND",
"ดอลลาร์สหรัฐ": "USD", "ดอลลาร์สหรัฐ": "USD",
"ดอลลาร์สิงคโปร์": "SGD", "ดอลลาร์สิงคโปร์": "SGD",
@ -14998,6 +15029,7 @@
"ボツワナ・プラ": "BWP", "ボツワナ・プラ": "BWP",
"ボリバル・ソベラノ": "VES", "ボリバル・ソベラノ": "VES",
"ボリビアーノ": "BOB", "ボリビアーノ": "BOB",
"ポンド・スターリング": "GBP",
"ポーランド・ズウォティ": [ "ポーランド・ズウォティ": [
"PLZ", "PLZ",
"PLN" "PLN"
@ -15063,7 +15095,6 @@
"中華人民共和国の通貨": "CNY", "中華人民共和国の通貨": "CNY",
"中部アフリカcfaフラン": "XAF", "中部アフリカcfaフラン": "XAF",
"人民元": "CNY", "人民元": "CNY",
"人民币": "CNY",
"人民幣": "CNY", "人民幣": "CNY",
"元": [ "元": [
"HKD", "HKD",

File diff suppressed because one or more lines are too long

View File

@ -180,7 +180,7 @@
"es": "es-es", "es": "es-es",
"et": "et-et", "et": "et-et",
"eu": "eu-eu", "eu": "eu-eu",
"fa": "prs-prs", "fa": "fa-fa",
"fi": "fi-fi", "fi": "fi-fi",
"fil": "fil-fil", "fil": "fil-fil",
"fr": "fr-fr", "fr": "fr-fr",
@ -188,14 +188,12 @@
"gd": "gd-gd", "gd": "gd-gd",
"gl": "gl-gl", "gl": "gl-gl",
"gu": "gu-gu", "gu": "gu-gu",
"ha": "ha-latn",
"he": "he-he", "he": "he-he",
"hi": "hi-hi", "hi": "hi-hi",
"hr": "hr-hr", "hr": "hr-hr",
"hu": "hu-hu", "hu": "hu-hu",
"hy": "hy-hy", "hy": "hy-hy",
"id": "id-id", "id": "id-id",
"ig": "ig-ig",
"is": "is-is", "is": "is-is",
"it": "it-it", "it": "it-it",
"ja": "ja-ja", "ja": "ja-ja",
@ -205,8 +203,6 @@
"kn": "kn-kn", "kn": "kn-kn",
"ko": "ko-ko", "ko": "ko-ko",
"kok": "kok-kok", "kok": "kok-kok",
"ku": "ku-arab",
"ky": "ky-ky",
"lb": "lb-lb", "lb": "lb-lb",
"lo": "lo-lo", "lo": "lo-lo",
"lt": "lt-lt", "lt": "lt-lt",
@ -214,7 +210,6 @@
"mi": "mi-mi", "mi": "mi-mi",
"mk": "mk-mk", "mk": "mk-mk",
"ml": "ml-ml", "ml": "ml-ml",
"mn": "mn-cyrl-mn",
"mr": "mr-mr", "mr": "mr-mr",
"ms": "ms-ms", "ms": "ms-ms",
"mt": "mt-mt", "mt": "mt-mt",
@ -222,33 +217,22 @@
"ne": "ne-ne", "ne": "ne-ne",
"nl": "nl-nl", "nl": "nl-nl",
"nn": "nn-nn", "nn": "nn-nn",
"nso": "nso-nso",
"or": "or-or", "or": "or-or",
"pa_Arab": "pa-arab",
"pa_Guru": "pa-guru", "pa_Guru": "pa-guru",
"pl": "pl-pl", "pl": "pl-pl",
"pt": "pt-br", "pt": "pt-br",
"qu": "quz-quz", "qu": "quz-quz",
"quc": "quc-quc",
"ro": "ro-ro", "ro": "ro-ro",
"ru": "ru-ru", "ru": "ru-ru",
"rw": "rw-rw",
"sd_Arab": "sd-arab",
"si": "si-si",
"sk": "sk-sk", "sk": "sk-sk",
"sl": "sl-sl", "sl": "sl-sl",
"sq": "sq-sq", "sq": "sq-sq",
"sr_Cyrl": "sr-cyrl", "sr_Cyrl": "sr-cyrl",
"sr_Latn": "sr-latn", "sr_Latn": "sr-latn",
"sv": "sv-sv", "sv": "sv-sv",
"sw": "sw-sw",
"ta": "ta-ta", "ta": "ta-ta",
"te": "te-te", "te": "te-te",
"tg": "tg-cyrl",
"th": "th-th", "th": "th-th",
"ti": "ti-ti",
"tk": "tk-tk",
"tn": "tn-tn",
"tr": "tr-tr", "tr": "tr-tr",
"tt": "tt-tt", "tt": "tt-tt",
"ug": "ug-ug", "ug": "ug-ug",
@ -256,13 +240,9 @@
"ur": "ur-ur", "ur": "ur-ur",
"uz_Latn": "uz-latn", "uz_Latn": "uz-latn",
"vi": "vi-vi", "vi": "vi-vi",
"wo": "wo-wo",
"xh": "xh-xh",
"yo": "yo-yo",
"zh": "zh-hans", "zh": "zh-hans",
"zh_Hans": "zh-hans", "zh_Hans": "zh-hans",
"zh_Hant": "zh-hant", "zh_Hant": "zh-hant"
"zu": "zu-zu"
}, },
"regions": { "regions": {
"am-ET": "am-et", "am-ET": "am-et",
@ -478,14 +458,12 @@
"kk-KZ": "kk-kz", "kk-KZ": "kk-kz",
"km-KH": "km-kh", "km-KH": "km-kh",
"ko-KR": "ko-kr", "ko-KR": "ko-kr",
"ky-KG": "ky-kg",
"lb-LU": "lb-lu", "lb-LU": "lb-lu",
"lo-LA": "lo-la", "lo-LA": "lo-la",
"lt-LT": "lt-lt", "lt-LT": "lt-lt",
"lv-LV": "lv-lv", "lv-LV": "lv-lv",
"mi-NZ": "mi-nz", "mi-NZ": "mi-nz",
"mk-MK": "mk-mk", "mk-MK": "mk-mk",
"mn-MN": "mn-mn",
"ms-BN": "ms-bn", "ms-BN": "ms-bn",
"ms-MY": "ms-my", "ms-MY": "ms-my",
"ms-SG": "ms-sg", "ms-SG": "ms-sg",
@ -519,8 +497,6 @@
"ru-KZ": "ru-kz", "ru-KZ": "ru-kz",
"ru-RU": "ru-ru", "ru-RU": "ru-ru",
"ru-UA": "ru-ua", "ru-UA": "ru-ua",
"rw-RW": "rw-rw",
"si-LK": "si-lk",
"sk-SK": "sk-sk", "sk-SK": "sk-sk",
"sl-SI": "sl-si", "sl-SI": "sl-si",
"sq-AL": "sq-al", "sq-AL": "sq-al",
@ -529,23 +505,14 @@
"sr-RS": "sr-rs", "sr-RS": "sr-rs",
"sv-FI": "sv-fi", "sv-FI": "sv-fi",
"sv-SE": "sv-se", "sv-SE": "sv-se",
"sw-KE": "sw-ke",
"sw-TZ": "sw-tz",
"sw-UG": "sw-ug",
"ta-LK": "ta-lk", "ta-LK": "ta-lk",
"ta-SG": "ta-sg", "ta-SG": "ta-sg",
"tg-TJ": "tg-tj",
"th-TH": "th-th", "th-TH": "th-th",
"ti-ER": "ti-er",
"tk-TM": "tk-tm",
"tn-BW": "tn-bw",
"tr-CY": "tr-cy", "tr-CY": "tr-cy",
"tr-TR": "tr-tr", "tr-TR": "tr-tr",
"uk-UA": "uk-ua", "uk-UA": "uk-ua",
"ur-PK": "ur-pk", "ur-PK": "ur-pk",
"vi-VN": "vi-vn", "vi-VN": "vi-vn",
"wo-SN": "wo-sn",
"yo-NG": "yo-ng",
"zh-CN": "zh-cn", "zh-CN": "zh-cn",
"zh-HK": "en-hk", "zh-HK": "en-hk",
"zh-MO": "zh-mo", "zh-MO": "zh-mo",
@ -578,7 +545,7 @@
"es": "es-es", "es": "es-es",
"et": "et-et", "et": "et-et",
"eu": "eu-eu", "eu": "eu-eu",
"fa": "prs-prs", "fa": "fa-fa",
"fi": "fi-fi", "fi": "fi-fi",
"fil": "fil-fil", "fil": "fil-fil",
"fr": "fr-fr", "fr": "fr-fr",
@ -586,14 +553,12 @@
"gd": "gd-gd", "gd": "gd-gd",
"gl": "gl-gl", "gl": "gl-gl",
"gu": "gu-gu", "gu": "gu-gu",
"ha": "ha-latn",
"he": "he-he", "he": "he-he",
"hi": "hi-hi", "hi": "hi-hi",
"hr": "hr-hr", "hr": "hr-hr",
"hu": "hu-hu", "hu": "hu-hu",
"hy": "hy-hy", "hy": "hy-hy",
"id": "id-id", "id": "id-id",
"ig": "ig-ig",
"is": "is-is", "is": "is-is",
"it": "it-it", "it": "it-it",
"ja": "ja-ja", "ja": "ja-ja",
@ -603,8 +568,6 @@
"kn": "kn-kn", "kn": "kn-kn",
"ko": "ko-ko", "ko": "ko-ko",
"kok": "kok-kok", "kok": "kok-kok",
"ku": "ku-arab",
"ky": "ky-ky",
"lb": "lb-lb", "lb": "lb-lb",
"lo": "lo-lo", "lo": "lo-lo",
"lt": "lt-lt", "lt": "lt-lt",
@ -612,7 +575,6 @@
"mi": "mi-mi", "mi": "mi-mi",
"mk": "mk-mk", "mk": "mk-mk",
"ml": "ml-ml", "ml": "ml-ml",
"mn": "mn-cyrl-mn",
"mr": "mr-mr", "mr": "mr-mr",
"ms": "ms-ms", "ms": "ms-ms",
"mt": "mt-mt", "mt": "mt-mt",
@ -620,33 +582,22 @@
"ne": "ne-ne", "ne": "ne-ne",
"nl": "nl-nl", "nl": "nl-nl",
"nn": "nn-nn", "nn": "nn-nn",
"nso": "nso-nso",
"or": "or-or", "or": "or-or",
"pa_Arab": "pa-arab",
"pa_Guru": "pa-guru", "pa_Guru": "pa-guru",
"pl": "pl-pl", "pl": "pl-pl",
"pt": "pt-br", "pt": "pt-br",
"qu": "quz-quz", "qu": "quz-quz",
"quc": "quc-quc",
"ro": "ro-ro", "ro": "ro-ro",
"ru": "ru-ru", "ru": "ru-ru",
"rw": "rw-rw",
"sd_Arab": "sd-arab",
"si": "si-si",
"sk": "sk-sk", "sk": "sk-sk",
"sl": "sl-sl", "sl": "sl-sl",
"sq": "sq-sq", "sq": "sq-sq",
"sr_Cyrl": "sr-cyrl", "sr_Cyrl": "sr-cyrl",
"sr_Latn": "sr-latn", "sr_Latn": "sr-latn",
"sv": "sv-sv", "sv": "sv-sv",
"sw": "sw-sw",
"ta": "ta-ta", "ta": "ta-ta",
"te": "te-te", "te": "te-te",
"tg": "tg-cyrl",
"th": "th-th", "th": "th-th",
"ti": "ti-ti",
"tk": "tk-tk",
"tn": "tn-tn",
"tr": "tr-tr", "tr": "tr-tr",
"tt": "tt-tt", "tt": "tt-tt",
"ug": "ug-ug", "ug": "ug-ug",
@ -654,13 +605,9 @@
"ur": "ur-ur", "ur": "ur-ur",
"uz_Latn": "uz-latn", "uz_Latn": "uz-latn",
"vi": "vi-vi", "vi": "vi-vi",
"wo": "wo-wo",
"xh": "xh-xh",
"yo": "yo-yo",
"zh": "zh-hans", "zh": "zh-hans",
"zh_Hans": "zh-hans", "zh_Hans": "zh-hans",
"zh_Hant": "zh-hant", "zh_Hant": "zh-hant"
"zu": "zu-zu"
}, },
"regions": { "regions": {
"am-ET": "am-et", "am-ET": "am-et",
@ -876,14 +823,12 @@
"kk-KZ": "kk-kz", "kk-KZ": "kk-kz",
"km-KH": "km-kh", "km-KH": "km-kh",
"ko-KR": "ko-kr", "ko-KR": "ko-kr",
"ky-KG": "ky-kg",
"lb-LU": "lb-lu", "lb-LU": "lb-lu",
"lo-LA": "lo-la", "lo-LA": "lo-la",
"lt-LT": "lt-lt", "lt-LT": "lt-lt",
"lv-LV": "lv-lv", "lv-LV": "lv-lv",
"mi-NZ": "mi-nz", "mi-NZ": "mi-nz",
"mk-MK": "mk-mk", "mk-MK": "mk-mk",
"mn-MN": "mn-mn",
"ms-BN": "ms-bn", "ms-BN": "ms-bn",
"ms-MY": "ms-my", "ms-MY": "ms-my",
"ms-SG": "ms-sg", "ms-SG": "ms-sg",
@ -917,8 +862,6 @@
"ru-KZ": "ru-kz", "ru-KZ": "ru-kz",
"ru-RU": "ru-ru", "ru-RU": "ru-ru",
"ru-UA": "ru-ua", "ru-UA": "ru-ua",
"rw-RW": "rw-rw",
"si-LK": "si-lk",
"sk-SK": "sk-sk", "sk-SK": "sk-sk",
"sl-SI": "sl-si", "sl-SI": "sl-si",
"sq-AL": "sq-al", "sq-AL": "sq-al",
@ -927,23 +870,14 @@
"sr-RS": "sr-rs", "sr-RS": "sr-rs",
"sv-FI": "sv-fi", "sv-FI": "sv-fi",
"sv-SE": "sv-se", "sv-SE": "sv-se",
"sw-KE": "sw-ke",
"sw-TZ": "sw-tz",
"sw-UG": "sw-ug",
"ta-LK": "ta-lk", "ta-LK": "ta-lk",
"ta-SG": "ta-sg", "ta-SG": "ta-sg",
"tg-TJ": "tg-tj",
"th-TH": "th-th", "th-TH": "th-th",
"ti-ER": "ti-er",
"tk-TM": "tk-tm",
"tn-BW": "tn-bw",
"tr-CY": "tr-cy", "tr-CY": "tr-cy",
"tr-TR": "tr-tr", "tr-TR": "tr-tr",
"uk-UA": "uk-ua", "uk-UA": "uk-ua",
"ur-PK": "ur-pk", "ur-PK": "ur-pk",
"vi-VN": "vi-vn", "vi-VN": "vi-vn",
"wo-SN": "wo-sn",
"yo-NG": "yo-ng",
"zh-CN": "zh-cn", "zh-CN": "zh-cn",
"zh-HK": "en-hk", "zh-HK": "en-hk",
"zh-MO": "zh-mo", "zh-MO": "zh-mo",
@ -976,7 +910,7 @@
"es": "es-es", "es": "es-es",
"et": "et-et", "et": "et-et",
"eu": "eu-eu", "eu": "eu-eu",
"fa": "prs-prs", "fa": "fa-fa",
"fi": "fi-fi", "fi": "fi-fi",
"fil": "fil-fil", "fil": "fil-fil",
"fr": "fr-fr", "fr": "fr-fr",
@ -984,14 +918,12 @@
"gd": "gd-gd", "gd": "gd-gd",
"gl": "gl-gl", "gl": "gl-gl",
"gu": "gu-gu", "gu": "gu-gu",
"ha": "ha-latn",
"he": "he-he", "he": "he-he",
"hi": "hi-hi", "hi": "hi-hi",
"hr": "hr-hr", "hr": "hr-hr",
"hu": "hu-hu", "hu": "hu-hu",
"hy": "hy-hy", "hy": "hy-hy",
"id": "id-id", "id": "id-id",
"ig": "ig-ig",
"is": "is-is", "is": "is-is",
"it": "it-it", "it": "it-it",
"ja": "ja-ja", "ja": "ja-ja",
@ -1001,8 +933,6 @@
"kn": "kn-kn", "kn": "kn-kn",
"ko": "ko-ko", "ko": "ko-ko",
"kok": "kok-kok", "kok": "kok-kok",
"ku": "ku-arab",
"ky": "ky-ky",
"lb": "lb-lb", "lb": "lb-lb",
"lo": "lo-lo", "lo": "lo-lo",
"lt": "lt-lt", "lt": "lt-lt",
@ -1010,7 +940,6 @@
"mi": "mi-mi", "mi": "mi-mi",
"mk": "mk-mk", "mk": "mk-mk",
"ml": "ml-ml", "ml": "ml-ml",
"mn": "mn-cyrl-mn",
"mr": "mr-mr", "mr": "mr-mr",
"ms": "ms-ms", "ms": "ms-ms",
"mt": "mt-mt", "mt": "mt-mt",
@ -1018,33 +947,22 @@
"ne": "ne-ne", "ne": "ne-ne",
"nl": "nl-nl", "nl": "nl-nl",
"nn": "nn-nn", "nn": "nn-nn",
"nso": "nso-nso",
"or": "or-or", "or": "or-or",
"pa_Arab": "pa-arab",
"pa_Guru": "pa-guru", "pa_Guru": "pa-guru",
"pl": "pl-pl", "pl": "pl-pl",
"pt": "pt-br", "pt": "pt-br",
"qu": "quz-quz", "qu": "quz-quz",
"quc": "quc-quc",
"ro": "ro-ro", "ro": "ro-ro",
"ru": "ru-ru", "ru": "ru-ru",
"rw": "rw-rw",
"sd_Arab": "sd-arab",
"si": "si-si",
"sk": "sk-sk", "sk": "sk-sk",
"sl": "sl-sl", "sl": "sl-sl",
"sq": "sq-sq", "sq": "sq-sq",
"sr_Cyrl": "sr-cyrl", "sr_Cyrl": "sr-cyrl",
"sr_Latn": "sr-latn", "sr_Latn": "sr-latn",
"sv": "sv-sv", "sv": "sv-sv",
"sw": "sw-sw",
"ta": "ta-ta", "ta": "ta-ta",
"te": "te-te", "te": "te-te",
"tg": "tg-cyrl",
"th": "th-th", "th": "th-th",
"ti": "ti-ti",
"tk": "tk-tk",
"tn": "tn-tn",
"tr": "tr-tr", "tr": "tr-tr",
"tt": "tt-tt", "tt": "tt-tt",
"ug": "ug-ug", "ug": "ug-ug",
@ -1052,13 +970,9 @@
"ur": "ur-ur", "ur": "ur-ur",
"uz_Latn": "uz-latn", "uz_Latn": "uz-latn",
"vi": "vi-vi", "vi": "vi-vi",
"wo": "wo-wo",
"xh": "xh-xh",
"yo": "yo-yo",
"zh": "zh-hans", "zh": "zh-hans",
"zh_Hans": "zh-hans", "zh_Hans": "zh-hans",
"zh_Hant": "zh-hant", "zh_Hant": "zh-hant"
"zu": "zu-zu"
}, },
"regions": { "regions": {
"am-ET": "am-et", "am-ET": "am-et",
@ -1274,14 +1188,12 @@
"kk-KZ": "kk-kz", "kk-KZ": "kk-kz",
"km-KH": "km-kh", "km-KH": "km-kh",
"ko-KR": "ko-kr", "ko-KR": "ko-kr",
"ky-KG": "ky-kg",
"lb-LU": "lb-lu", "lb-LU": "lb-lu",
"lo-LA": "lo-la", "lo-LA": "lo-la",
"lt-LT": "lt-lt", "lt-LT": "lt-lt",
"lv-LV": "lv-lv", "lv-LV": "lv-lv",
"mi-NZ": "mi-nz", "mi-NZ": "mi-nz",
"mk-MK": "mk-mk", "mk-MK": "mk-mk",
"mn-MN": "mn-mn",
"ms-BN": "ms-bn", "ms-BN": "ms-bn",
"ms-MY": "ms-my", "ms-MY": "ms-my",
"ms-SG": "ms-sg", "ms-SG": "ms-sg",
@ -1315,8 +1227,6 @@
"ru-KZ": "ru-kz", "ru-KZ": "ru-kz",
"ru-RU": "ru-ru", "ru-RU": "ru-ru",
"ru-UA": "ru-ua", "ru-UA": "ru-ua",
"rw-RW": "rw-rw",
"si-LK": "si-lk",
"sk-SK": "sk-sk", "sk-SK": "sk-sk",
"sl-SI": "sl-si", "sl-SI": "sl-si",
"sq-AL": "sq-al", "sq-AL": "sq-al",
@ -1325,23 +1235,14 @@
"sr-RS": "sr-rs", "sr-RS": "sr-rs",
"sv-FI": "sv-fi", "sv-FI": "sv-fi",
"sv-SE": "sv-se", "sv-SE": "sv-se",
"sw-KE": "sw-ke",
"sw-TZ": "sw-tz",
"sw-UG": "sw-ug",
"ta-LK": "ta-lk", "ta-LK": "ta-lk",
"ta-SG": "ta-sg", "ta-SG": "ta-sg",
"tg-TJ": "tg-tj",
"th-TH": "th-th", "th-TH": "th-th",
"ti-ER": "ti-er",
"tk-TM": "tk-tm",
"tn-BW": "tn-bw",
"tr-CY": "tr-cy", "tr-CY": "tr-cy",
"tr-TR": "tr-tr", "tr-TR": "tr-tr",
"uk-UA": "uk-ua", "uk-UA": "uk-ua",
"ur-PK": "ur-pk", "ur-PK": "ur-pk",
"vi-VN": "vi-vn", "vi-VN": "vi-vn",
"wo-SN": "wo-sn",
"yo-NG": "yo-ng",
"zh-CN": "en-hk", "zh-CN": "en-hk",
"zh-HK": "en-hk", "zh-HK": "en-hk",
"zh-MO": "zh-mo", "zh-MO": "zh-mo",
@ -1374,7 +1275,7 @@
"es": "es-es", "es": "es-es",
"et": "et-et", "et": "et-et",
"eu": "eu-eu", "eu": "eu-eu",
"fa": "prs-prs", "fa": "fa-fa",
"fi": "fi-fi", "fi": "fi-fi",
"fil": "fil-fil", "fil": "fil-fil",
"fr": "fr-fr", "fr": "fr-fr",
@ -1382,14 +1283,12 @@
"gd": "gd-gd", "gd": "gd-gd",
"gl": "gl-gl", "gl": "gl-gl",
"gu": "gu-gu", "gu": "gu-gu",
"ha": "ha-latn",
"he": "he-he", "he": "he-he",
"hi": "hi-hi", "hi": "hi-hi",
"hr": "hr-hr", "hr": "hr-hr",
"hu": "hu-hu", "hu": "hu-hu",
"hy": "hy-hy", "hy": "hy-hy",
"id": "id-id", "id": "id-id",
"ig": "ig-ig",
"is": "is-is", "is": "is-is",
"it": "it-it", "it": "it-it",
"ja": "ja-ja", "ja": "ja-ja",
@ -1399,8 +1298,6 @@
"kn": "kn-kn", "kn": "kn-kn",
"ko": "ko-ko", "ko": "ko-ko",
"kok": "kok-kok", "kok": "kok-kok",
"ku": "ku-arab",
"ky": "ky-ky",
"lb": "lb-lb", "lb": "lb-lb",
"lo": "lo-lo", "lo": "lo-lo",
"lt": "lt-lt", "lt": "lt-lt",
@ -1408,7 +1305,6 @@
"mi": "mi-mi", "mi": "mi-mi",
"mk": "mk-mk", "mk": "mk-mk",
"ml": "ml-ml", "ml": "ml-ml",
"mn": "mn-cyrl-mn",
"mr": "mr-mr", "mr": "mr-mr",
"ms": "ms-ms", "ms": "ms-ms",
"mt": "mt-mt", "mt": "mt-mt",
@ -1416,33 +1312,22 @@
"ne": "ne-ne", "ne": "ne-ne",
"nl": "nl-nl", "nl": "nl-nl",
"nn": "nn-nn", "nn": "nn-nn",
"nso": "nso-nso",
"or": "or-or", "or": "or-or",
"pa_Arab": "pa-arab",
"pa_Guru": "pa-guru", "pa_Guru": "pa-guru",
"pl": "pl-pl", "pl": "pl-pl",
"pt": "pt-br", "pt": "pt-br",
"qu": "quz-quz", "qu": "quz-quz",
"quc": "quc-quc",
"ro": "ro-ro", "ro": "ro-ro",
"ru": "ru-ru", "ru": "ru-ru",
"rw": "rw-rw",
"sd_Arab": "sd-arab",
"si": "si-si",
"sk": "sk-sk", "sk": "sk-sk",
"sl": "sl-sl", "sl": "sl-sl",
"sq": "sq-sq", "sq": "sq-sq",
"sr_Cyrl": "sr-cyrl", "sr_Cyrl": "sr-cyrl",
"sr_Latn": "sr-latn", "sr_Latn": "sr-latn",
"sv": "sv-sv", "sv": "sv-sv",
"sw": "sw-sw",
"ta": "ta-ta", "ta": "ta-ta",
"te": "te-te", "te": "te-te",
"tg": "tg-cyrl",
"th": "th-th", "th": "th-th",
"ti": "ti-ti",
"tk": "tk-tk",
"tn": "tn-tn",
"tr": "tr-tr", "tr": "tr-tr",
"tt": "tt-tt", "tt": "tt-tt",
"ug": "ug-ug", "ug": "ug-ug",
@ -1450,13 +1335,9 @@
"ur": "ur-ur", "ur": "ur-ur",
"uz_Latn": "uz-latn", "uz_Latn": "uz-latn",
"vi": "vi-vi", "vi": "vi-vi",
"wo": "wo-wo",
"xh": "xh-xh",
"yo": "yo-yo",
"zh": "zh-hans", "zh": "zh-hans",
"zh_Hans": "zh-hans", "zh_Hans": "zh-hans",
"zh_Hant": "zh-hant", "zh_Hant": "zh-hant"
"zu": "zu-zu"
}, },
"regions": { "regions": {
"am-ET": "am-et", "am-ET": "am-et",
@ -1672,14 +1553,12 @@
"kk-KZ": "kk-kz", "kk-KZ": "kk-kz",
"km-KH": "km-kh", "km-KH": "km-kh",
"ko-KR": "ko-kr", "ko-KR": "ko-kr",
"ky-KG": "ky-kg",
"lb-LU": "lb-lu", "lb-LU": "lb-lu",
"lo-LA": "lo-la", "lo-LA": "lo-la",
"lt-LT": "lt-lt", "lt-LT": "lt-lt",
"lv-LV": "lv-lv", "lv-LV": "lv-lv",
"mi-NZ": "mi-nz", "mi-NZ": "mi-nz",
"mk-MK": "mk-mk", "mk-MK": "mk-mk",
"mn-MN": "mn-mn",
"ms-BN": "ms-bn", "ms-BN": "ms-bn",
"ms-MY": "ms-my", "ms-MY": "ms-my",
"ms-SG": "ms-sg", "ms-SG": "ms-sg",
@ -1713,8 +1592,6 @@
"ru-KZ": "ru-kz", "ru-KZ": "ru-kz",
"ru-RU": "ru-ru", "ru-RU": "ru-ru",
"ru-UA": "ru-ua", "ru-UA": "ru-ua",
"rw-RW": "rw-rw",
"si-LK": "si-lk",
"sk-SK": "sk-sk", "sk-SK": "sk-sk",
"sl-SI": "sl-si", "sl-SI": "sl-si",
"sq-AL": "sq-al", "sq-AL": "sq-al",
@ -1723,23 +1600,14 @@
"sr-RS": "sr-rs", "sr-RS": "sr-rs",
"sv-FI": "sv-fi", "sv-FI": "sv-fi",
"sv-SE": "sv-se", "sv-SE": "sv-se",
"sw-KE": "sw-ke",
"sw-TZ": "sw-tz",
"sw-UG": "sw-ug",
"ta-LK": "ta-lk", "ta-LK": "ta-lk",
"ta-SG": "ta-sg", "ta-SG": "ta-sg",
"tg-TJ": "tg-tj",
"th-TH": "th-th", "th-TH": "th-th",
"ti-ER": "ti-er",
"tk-TM": "tk-tm",
"tn-BW": "tn-bw",
"tr-CY": "tr-cy", "tr-CY": "tr-cy",
"tr-TR": "tr-tr", "tr-TR": "tr-tr",
"uk-UA": "uk-ua", "uk-UA": "uk-ua",
"ur-PK": "ur-pk", "ur-PK": "ur-pk",
"vi-VN": "vi-vn", "vi-VN": "vi-vn",
"wo-SN": "wo-sn",
"yo-NG": "yo-ng",
"zh-CN": "zh-cn", "zh-CN": "zh-cn",
"zh-HK": "en-hk", "zh-HK": "en-hk",
"zh-MO": "zh-mo", "zh-MO": "zh-mo",
@ -1759,6 +1627,7 @@
"el": "el", "el": "el",
"en-CA": "en-ca", "en-CA": "en-ca",
"en-GB": "en-gb", "en-GB": "en-gb",
"en-IN": "en-in",
"en-US": "en-us", "en-US": "en-us",
"es": "es", "es": "es",
"et": "et", "et": "et",
@ -1769,7 +1638,6 @@
"hu": "hu", "hu": "hu",
"id": "id", "id": "id",
"it": "it", "it": "it",
"ja-JP": "ja-jp",
"ko": "ko", "ko": "ko",
"lt": "lt", "lt": "lt",
"lv": "lv", "lv": "lv",
@ -1860,6 +1728,7 @@
"el": "el", "el": "el",
"en-CA": "en-ca", "en-CA": "en-ca",
"en-GB": "en-gb", "en-GB": "en-gb",
"en-IN": "en-in",
"en-US": "en-us", "en-US": "en-us",
"es": "es", "es": "es",
"et": "et", "et": "et",
@ -1870,7 +1739,6 @@
"hu": "hu", "hu": "hu",
"id": "id", "id": "id",
"it": "it", "it": "it",
"ja-JP": "ja-jp",
"ko": "ko", "ko": "ko",
"lt": "lt", "lt": "lt",
"lv": "lv", "lv": "lv",
@ -1961,6 +1829,7 @@
"el": "el", "el": "el",
"en-CA": "en-ca", "en-CA": "en-ca",
"en-GB": "en-gb", "en-GB": "en-gb",
"en-IN": "en-in",
"en-US": "en-us", "en-US": "en-us",
"es": "es", "es": "es",
"et": "et", "et": "et",
@ -1971,7 +1840,6 @@
"hu": "hu", "hu": "hu",
"id": "id", "id": "id",
"it": "it", "it": "it",
"ja-JP": "ja-jp",
"ko": "ko", "ko": "ko",
"lt": "lt", "lt": "lt",
"lv": "lv", "lv": "lv",
@ -2062,6 +1930,7 @@
"el": "el", "el": "el",
"en-CA": "en-ca", "en-CA": "en-ca",
"en-GB": "en-gb", "en-GB": "en-gb",
"en-IN": "en-in",
"en-US": "en-us", "en-US": "en-us",
"es": "es", "es": "es",
"et": "et", "et": "et",
@ -2072,7 +1941,6 @@
"hu": "hu", "hu": "hu",
"id": "id", "id": "id",
"it": "it", "it": "it",
"ja-JP": "ja-jp",
"ko": "ko", "ko": "ko",
"lt": "lt", "lt": "lt",
"lv": "lv", "lv": "lv",
@ -7609,6 +7477,7 @@
"ami", "ami",
"an", "an",
"ang", "ang",
"ann",
"anp", "anp",
"ar", "ar",
"arc", "arc",
@ -7727,6 +7596,7 @@
"hy", "hy",
"hyw", "hyw",
"ia", "ia",
"iba",
"id", "id",
"ie", "ie",
"ig", "ig",
@ -7815,6 +7685,7 @@
"no", "no",
"nov", "nov",
"nqo", "nqo",
"nr",
"nrm", "nrm",
"nso", "nso",
"nv", "nv",
@ -7848,6 +7719,7 @@
"ro", "ro",
"roa-rup", "roa-rup",
"roa-tara", "roa-tara",
"rsk",
"ru", "ru",
"rue", "rue",
"rw", "rw",
@ -7886,6 +7758,7 @@
"ta", "ta",
"tay", "tay",
"tcy", "tcy",
"tdd",
"te", "te",
"tet", "tet",
"tg", "tg",

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": [
"130.0", "132.0",
"129.0" "131.0"
] ]
} }

View File

@ -832,7 +832,7 @@
"Q104907390": { "Q104907390": {
"si_name": "Q182429", "si_name": "Q182429",
"symbol": "nmi/h", "symbol": "nmi/h",
"to_si_factor": 0.514444 "to_si_factor": 0.5144444444444445
}, },
"Q104907398": { "Q104907398": {
"si_name": "Q215571", "si_name": "Q215571",
@ -1336,7 +1336,7 @@
}, },
"Q106636307": { "Q106636307": {
"si_name": "Q80842107", "si_name": "Q80842107",
"symbol": "μS/cm", "symbol": "μS/cm-1",
"to_si_factor": 0.0001 "to_si_factor": 0.0001
}, },
"Q106639711": { "Q106639711": {
@ -4142,7 +4142,7 @@
"Q23931103": { "Q23931103": {
"si_name": "Q25343", "si_name": "Q25343",
"symbol": "nmi²", "symbol": "nmi²",
"to_si_factor": 3434290.0120544 "to_si_factor": 3429904.0
}, },
"Q239830": { "Q239830": {
"si_name": "Q3395194", "si_name": "Q3395194",

View File

@ -34,10 +34,10 @@ Implementations
""" """
from typing import List, Dict, Any, Optional from typing import List, Dict, Any, Optional
from urllib.parse import quote from urllib.parse import urlencode
from lxml import html from lxml import html
from searx.utils import extract_text, eval_xpath, eval_xpath_list from searx.utils import extract_text, eval_xpath, eval_xpath_getindex, eval_xpath_list
from searx.enginelib.traits import EngineTraits from searx.enginelib.traits import EngineTraits
from searx.data import ENGINE_TRAITS from searx.data import ENGINE_TRAITS
@ -53,7 +53,7 @@ about: Dict[str, Any] = {
# engine dependent config # engine dependent config
categories: List[str] = ["files"] categories: List[str] = ["files"]
paging: bool = False paging: bool = True
# search-url # search-url
base_url: str = "https://annas-archive.org" base_url: str = "https://annas-archive.org"
@ -99,9 +99,18 @@ def init(engine_settings=None): # pylint: disable=unused-argument
def request(query, params: Dict[str, Any]) -> Dict[str, Any]: def request(query, params: Dict[str, Any]) -> Dict[str, Any]:
q = quote(query)
lang = traits.get_language(params["language"], traits.all_locale) # type: ignore lang = traits.get_language(params["language"], traits.all_locale) # type: ignore
params["url"] = base_url + f"/search?lang={lang or ''}&content={aa_content}&ext={aa_ext}&sort={aa_sort}&q={q}" args = {
'lang': lang,
'content': aa_content,
'ext': aa_ext,
'sort': aa_sort,
'q': query,
'page': params['pageno'],
}
# filter out None and empty values
filtered_args = dict((k, v) for k, v in args.items() if v)
params["url"] = f"{base_url}/search?{urlencode(filtered_args)}"
return params return params
@ -128,12 +137,12 @@ def response(resp) -> List[Dict[str, Optional[str]]]:
def _get_result(item): def _get_result(item):
return { return {
'template': 'paper.html', 'template': 'paper.html',
'url': base_url + item.xpath('./@href')[0], 'url': base_url + extract_text(eval_xpath_getindex(item, './@href', 0)),
'title': extract_text(eval_xpath(item, './/h3/text()[1]')), 'title': extract_text(eval_xpath(item, './/h3/text()[1]')),
'publisher': extract_text(eval_xpath(item, './/div[contains(@class, "text-sm")]')), 'publisher': extract_text(eval_xpath(item, './/div[contains(@class, "text-sm")]')),
'authors': [extract_text(eval_xpath(item, './/div[contains(@class, "italic")]'))], 'authors': [extract_text(eval_xpath(item, './/div[contains(@class, "italic")]'))],
'content': extract_text(eval_xpath(item, './/div[contains(@class, "text-xs")]')), 'content': extract_text(eval_xpath(item, './/div[contains(@class, "text-xs")]')),
'thumbnail': item.xpath('.//img/@src')[0], 'thumbnail': extract_text(eval_xpath_getindex(item, './/img/@src', 0, default=None), allow_none=True),
} }

View File

@ -18,7 +18,6 @@ from searx import (
) )
from searx.utils import ( from searx.utils import (
eval_xpath, eval_xpath,
eval_xpath_getindex,
extract_text, extract_text,
) )
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
@ -54,31 +53,33 @@ 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://lite.duckduckgo.com/lite/' url = "https://html.duckduckgo.com/html"
# url_ping = 'https://duckduckgo.com/t/sl_l'
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 = []
def cache_vqd(query, value): def _cache_key(data: dict):
return 'SearXNG_ddg_web_vqd' + redislib.secret_hash(f"{data['q']}//{data['kl']}")
def cache_vqd(data: dict, value):
"""Caches a ``vqd`` value from a query.""" """Caches a ``vqd`` value from a query."""
c = redisdb.client() c = redisdb.client()
if c: if c:
logger.debug("cache vqd value: %s", value) logger.debug("cache vqd value: %s", value)
key = 'SearXNG_ddg_web_vqd' + redislib.secret_hash(query) c.set(_cache_key(data), value, ex=600)
c.set(key, value, ex=600)
else:
logger.debug("MEM cache vqd value: %s", value)
if len(__CACHE) > 100: # cache vqd from last 100 queries
__CACHE.pop(0)
__CACHE.append((_cache_key(data), value))
def get_vqd(query): def get_vqd(data):
"""Returns the ``vqd`` that fits to the *query*. If there is no ``vqd`` cached """Returns the ``vqd`` that fits to the *query* (``data`` from HTTP POST).
(:py:obj:`cache_vqd`) the query is sent to DDG to get a vqd value from the
response.
.. hint::
If an empty string is returned there are no results for the ``query`` and
therefore no ``vqd`` value.
DDG's bot detection is sensitive to the ``vqd`` value. For some search terms DDG's bot detection is sensitive to the ``vqd`` value. For some search terms
(such as extremely long search terms that are often sent by bots), no ``vqd`` (such as extremely long search terms that are often sent by bots), no ``vqd``
@ -106,28 +107,23 @@ def get_vqd(query):
- DuckDuckGo News: ``https://duckduckgo.com/news.js??q=...&vqd=...`` - DuckDuckGo News: ``https://duckduckgo.com/news.js??q=...&vqd=...``
""" """
key = _cache_key(data)
value = None value = None
c = redisdb.client() c = redisdb.client()
if c: if c:
key = 'SearXNG_ddg_web_vqd' + redislib.secret_hash(query)
value = c.get(key) value = c.get(key)
if value or value == b'': if value or value == b'':
value = value.decode('utf-8') value = value.decode('utf-8')
logger.debug("re-use cached vqd value: %s", value) logger.debug("re-use CACHED vqd value: %s", value)
return value return value
query_url = 'https://duckduckgo.com/?' + urlencode({'q': query}) else:
res = get(query_url) for k, value in __CACHE:
doc = lxml.html.fromstring(res.text) if k == key:
for script in doc.xpath("//script[@type='text/javascript']"): logger.debug("MEM re-use CACHED vqd value: %s", value)
script = script.text return value
if 'vqd="' in script: return None
value = extr(script, 'vqd="', '"')
break
logger.debug("new vqd value: '%s'", value)
if value is not None:
cache_vqd(query, value)
return value
def get_ddg_lang(eng_traits: EngineTraits, sxng_locale, default='en_US'): def get_ddg_lang(eng_traits: EngineTraits, sxng_locale, default='en_US'):
@ -155,9 +151,10 @@ def get_ddg_lang(eng_traits: EngineTraits, sxng_locale, default='en_US'):
.. hint:: .. hint::
`DDG-lite <https://lite.duckduckgo.com/lite>`__ does not offer a language `DDG-lite <https://lite.duckduckgo.com/lite>`__ and the *no Javascript*
selection to the user, only a region can be selected by the user page https://html.duckduckgo.com/html do not offer a language selection
(``eng_region`` from the example above). DDG-lite stores the selected to the user, only a region can be selected by the user (``eng_region``
from the example above). DDG-lite and *no Javascript* store the selected
region in a cookie:: region in a cookie::
params['cookies']['kl'] = eng_region # 'ar-es' params['cookies']['kl'] = eng_region # 'ar-es'
@ -241,10 +238,25 @@ def request(query, params):
query = quote_ddg_bangs(query) query = quote_ddg_bangs(query)
# request needs a vqd argument if len(query) >= 500:
vqd = get_vqd(query) # DDG does not accept queries with more than 499 chars
params["url"] = None
return
# Advanced search syntax ends in CAPTCHA
# https://duckduckgo.com/duckduckgo-help-pages/results/syntax/
query = [
x.removeprefix("site:").removeprefix("intitle:").removeprefix("inurl:").removeprefix("filetype:")
for x in query.split()
]
eng_region = traits.get_region(params['searxng_locale'], traits.all_locale) eng_region = traits.get_region(params['searxng_locale'], traits.all_locale)
if eng_region == "wt-wt":
# https://html.duckduckgo.com/html sets an empty value for "all".
eng_region = ""
params['data']['kl'] = eng_region
params['cookies']['kl'] = eng_region
# eng_lang = get_ddg_lang(traits, params['searxng_locale']) # eng_lang = get_ddg_lang(traits, params['searxng_locale'])
params['url'] = url params['url'] = url
@ -252,54 +264,82 @@ def request(query, params):
params['data']['q'] = query params['data']['q'] = query
# The API is not documented, so we do some reverse engineering and emulate # The API is not documented, so we do some reverse engineering and emulate
# what https://lite.duckduckgo.com/lite/ does when you press "next Page" # what https://html.duckduckgo.com/html does when you press "next Page" link
# link again and again .. # again and again ..
params['headers']['Content-Type'] = 'application/x-www-form-urlencoded' params['headers']['Content-Type'] = 'application/x-www-form-urlencoded'
params['data']['vqd'] = vqd
# initial page does not have an offset 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:
params['data']['b'] = ""
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']]
if params['pageno'] == 2: if params['pageno'] == 2:
# second page does have an offset of 20 # second page does have an offset of 20
offset = (params['pageno'] - 1) * 20 offset = (params['pageno'] - 1) * 20
params['data']['s'] = offset params['data']['s'] = offset
params['data']['dc'] = offset + 1 params['data']['dc'] = offset + 1
elif params['pageno'] > 2: elif params['pageno'] > 2:
# third and following pages do have an offset of 20 + n*50 # third and following pages do have an offset of 20 + n*50
offset = 20 + (params['pageno'] - 2) * 50 offset = 20 + (params['pageno'] - 2) * 50
params['data']['s'] = offset params['data']['s'] = offset
params['data']['dc'] = offset + 1 params['data']['dc'] = offset + 1
# initial page does not have additional data in the input form
if params['pageno'] > 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']['o'] = form_data.get('o', 'json')
params['data']['api'] = form_data.get('api', 'd.js') 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'] = 'https://lite.duckduckgo.com/' params['headers']['Referer'] = url
params['data']['kl'] = eng_region # from here on no more params['data'] shuld be set, since this dict is
params['cookies']['kl'] = eng_region # needed to get a vqd value from the cache ..
params['data']['df'] = '' vqd = get_vqd(params['data'])
if params['time_range'] in time_range_dict:
params['data']['df'] = time_range_dict[params['time_range']] # Certain conditions must be met in order to call up one of the
params['cookies']['df'] = time_range_dict[params['time_range']] # following pages ...
if vqd:
params['data']['vqd'] = vqd # follow up pages / requests needs a vqd argument
else:
# Don't try to call follow up pages without a vqd value. DDG
# recognizes this as a request from a bot. This lowers the
# reputation of the SearXNG IP and DDG starts to activate CAPTCHAs.
params["url"] = None
return
if params['searxng_locale'].startswith("zh"):
# 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.
params["url"] = None
return
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'])
return params
def detect_ddg_captcha(dom): def is_ddg_captcha(dom):
"""In case of CAPTCHA ddg open its own *not a Robot* dialog and is """In case of CAPTCHA ddg response its own *not a Robot* dialog and is not
not redirected to CAPTCHA page. redirected to a CAPTCHA page."""
"""
if eval_xpath(dom, "//form[@id='challenge-form']"): return bool(eval_xpath(dom, "//form[@id='challenge-form']"))
# set suspend time to zero is OK --> ddg does not block the IP
raise SearxEngineCaptchaException(suspended_time=0)
def response(resp): def response(resp):
@ -309,37 +349,34 @@ def response(resp):
results = [] results = []
doc = lxml.html.fromstring(resp.text) doc = lxml.html.fromstring(resp.text)
detect_ddg_captcha(doc)
result_table = eval_xpath(doc, '//html/body/form/div[@class="filters"]/table') if is_ddg_captcha(doc):
# set suspend time to zero is OK --> ddg does not block the IP
raise SearxEngineCaptchaException(suspended_time=0, message=f"CAPTCHA ({resp.search_params['data'].get('kl')})")
if len(result_table) == 2: form = eval_xpath(doc, '//input[@name="vqd"]/..')
# some locales (at least China) does not have a "next page" button and if len(form):
# the layout of the HTML tables is different. # some locales (at least China) does not have a "next page" button
result_table = result_table[1] form = form[0]
elif not len(result_table) >= 3: form_vqd = eval_xpath(form, '//input[@name="vqd"]/@value')[0]
# no more results
return []
else:
result_table = result_table[2]
# update form data from response
form = eval_xpath(doc, '//html/body/form/div[@class="filters"]/table//input/..')
if len(form):
form = form[0] cache_vqd(resp.search_params["data"], form_vqd)
form_data['v'] = eval_xpath(form, '//input[@name="v"]/@value')[0]
form_data['api'] = eval_xpath(form, '//input[@name="api"]/@value')[0]
form_data['o'] = eval_xpath(form, '//input[@name="o"]/@value')[0]
logger.debug('form_data: %s', form_data)
tr_rows = eval_xpath(result_table, './/tr') # just select "web-result" and ignore results of class "result--ad result--ad--small"
# In the last <tr> is the form of the 'previous/next page' links for div_result in eval_xpath(doc, '//div[@id="links"]/div[contains(@class, "web-result")]'):
tr_rows = tr_rows[:-1]
len_tr_rows = len(tr_rows) item = {}
offset = 0 title = eval_xpath(div_result, './/h2/a')
if not title:
# this is the "No results." item in the result list
continue
item["title"] = extract_text(title)
item["url"] = eval_xpath(div_result, './/h2/a/@href')[0]
item["content"] = extract_text(eval_xpath(div_result, './/a[contains(@class, "result__snippet")]')[0])
zero_click_info_xpath = '//html/body/form/div/table[2]/tr[2]/td/text()' results.append(item)
zero_click_info_xpath = '//div[@id="zero_click_abstract"]'
zero_click = extract_text(eval_xpath(doc, zero_click_info_xpath)).strip() zero_click = extract_text(eval_xpath(doc, zero_click_info_xpath)).strip()
if zero_click and "Your IP address is" not in zero_click and "Your user agent:" not in zero_click: if zero_click and "Your IP address is" not in zero_click and "Your user agent:" not in zero_click:
@ -352,33 +389,6 @@ def response(resp):
} }
) )
while len_tr_rows >= offset + 4:
# assemble table rows we need to scrap
tr_title = tr_rows[offset]
tr_content = tr_rows[offset + 1]
offset += 4
# ignore sponsored Adds <tr class="result-sponsored">
if tr_content.get('class') == 'result-sponsored':
continue
a_tag = eval_xpath_getindex(tr_title, './/td//a[@class="result-link"]', 0, None)
if a_tag is None:
continue
td_content = eval_xpath_getindex(tr_content, './/td[@class="result-snippet"]', 0, None)
if td_content is None:
continue
results.append(
{
'title': a_tag.text_content(),
'content': extract_text(td_content),
'url': a_tag.get('href'),
}
)
return results return results

View File

@ -62,7 +62,7 @@ filter_mapping = {0: 'off', 1: 'medium', 2: 'high'}
results_xpath = './/div[contains(@jscontroller, "SC7lYd")]' results_xpath = './/div[contains(@jscontroller, "SC7lYd")]'
title_xpath = './/a/h3[1]' title_xpath = './/a/h3[1]'
href_xpath = './/a[h3]/@href' href_xpath = './/a[h3]/@href'
content_xpath = './/div[@data-sncf="1"]' content_xpath = './/div[contains(@data-sncf, "1")]'
# Suggestions are links placed in a *card-section*, we extract only the text # Suggestions are links placed in a *card-section*, we extract only the text
# from the links not the links itself. # from the links not the links itself.

View File

@ -20,17 +20,17 @@
from __future__ import annotations from __future__ import annotations
from typing import Literal from typing import Literal
import os
import abc import abc
import dataclasses import dataclasses
import hashlib import hashlib
import logging import logging
import pathlib
import sqlite3 import sqlite3
import tempfile import tempfile
import time import time
import typer import typer
from pydantic import BaseModel import msgspec
from searx import sqlitedb from searx import sqlitedb
from searx import logger from searx import logger
@ -90,7 +90,7 @@ def init(cfg: "FaviconCacheConfig"):
raise NotImplementedError(f"favicons db_type '{cfg.db_type}' is unknown") raise NotImplementedError(f"favicons db_type '{cfg.db_type}' is unknown")
class FaviconCacheConfig(BaseModel): class FaviconCacheConfig(msgspec.Struct): # pylint: disable=too-few-public-methods
"""Configuration of the favicon cache.""" """Configuration of the favicon cache."""
db_type: Literal["sqlite", "mem"] = "sqlite" db_type: Literal["sqlite", "mem"] = "sqlite"
@ -103,7 +103,7 @@ class FaviconCacheConfig(BaseModel):
:py:obj:`.cache.FaviconCacheMEM` (not recommended) :py:obj:`.cache.FaviconCacheMEM` (not recommended)
""" """
db_url: pathlib.Path = pathlib.Path(tempfile.gettempdir()) / "faviconcache.db" db_url: str = tempfile.gettempdir() + os.sep + "faviconcache.db"
"""URL of the SQLite DB, the path to the database file.""" """URL of the SQLite DB, the path to the database file."""
HOLD_TIME: int = 60 * 60 * 24 * 30 # 30 days HOLD_TIME: int = 60 * 60 * 24 * 30 # 30 days

View File

@ -4,9 +4,8 @@
from __future__ import annotations from __future__ import annotations
import pathlib import pathlib
from pydantic import BaseModel import msgspec
from searx.compat import tomllib
from .cache import FaviconCacheConfig from .cache import FaviconCacheConfig
from .proxy import FaviconProxyConfig from .proxy import FaviconProxyConfig
@ -19,7 +18,7 @@ TOML_CACHE_CFG: dict[str, "FaviconConfig"] = {}
DEFAULT_CFG_TOML_PATH = pathlib.Path(__file__).parent / "favicons.toml" DEFAULT_CFG_TOML_PATH = pathlib.Path(__file__).parent / "favicons.toml"
class FaviconConfig(BaseModel): class FaviconConfig(msgspec.Struct): # pylint: disable=too-few-public-methods
"""The class aggregates configurations of the favicon tools""" """The class aggregates configurations of the favicon tools"""
cfg_schema: int cfg_schema: int
@ -28,10 +27,10 @@ class FaviconConfig(BaseModel):
By specifying a version, it is possible to ensure downward compatibility in By specifying a version, it is possible to ensure downward compatibility in
the event of future changes to the configuration schema""" the event of future changes to the configuration schema"""
cache: FaviconCacheConfig = FaviconCacheConfig() cache: FaviconCacheConfig = msgspec.field(default_factory=FaviconCacheConfig)
"""Setup of the :py:obj:`.cache.FaviconCacheConfig`.""" """Setup of the :py:obj:`.cache.FaviconCacheConfig`."""
proxy: FaviconProxyConfig = FaviconProxyConfig() proxy: FaviconProxyConfig = msgspec.field(default_factory=FaviconProxyConfig)
"""Setup of the :py:obj:`.proxy.FaviconProxyConfig`.""" """Setup of the :py:obj:`.proxy.FaviconProxyConfig`."""
@classmethod @classmethod
@ -45,18 +44,22 @@ class FaviconConfig(BaseModel):
return cached return cached
with cfg_file.open("rb") as f: with cfg_file.open("rb") as f:
data = f.read()
cfg = tomllib.load(f) cfg = msgspec.toml.decode(data, type=_FaviconConfig)
cfg = cfg.get("favicons", cfg) schema = cfg.favicons.cfg_schema
if schema != CONFIG_SCHEMA:
raise ValueError(
f"config schema version {CONFIG_SCHEMA} is needed, version {schema} is given in {cfg_file}"
)
schema = cfg.get("cfg_schema") cfg = cfg.favicons
if schema != CONFIG_SCHEMA: if use_cache and cached:
raise ValueError( TOML_CACHE_CFG[str(cfg_file.resolve())] = cfg
f"config schema version {CONFIG_SCHEMA} is needed, version {schema} is given in {cfg_file}"
)
cfg = cls(**cfg) return cfg
if use_cache and cached:
TOML_CACHE_CFG[str(cfg_file.resolve())] = cfg
return cfg
class _FaviconConfig(msgspec.Struct): # pylint: disable=too-few-public-methods
# wrapper struct for root object "favicons."
favicons: FaviconConfig

View File

@ -12,7 +12,7 @@ import urllib.parse
import flask import flask
from httpx import HTTPError from httpx import HTTPError
from pydantic import BaseModel import msgspec
from searx import get_setting from searx import get_setting
@ -41,7 +41,7 @@ def _initial_resolver_map():
return d return d
class FaviconProxyConfig(BaseModel): class FaviconProxyConfig(msgspec.Struct):
"""Configuration of the favicon proxy.""" """Configuration of the favicon proxy."""
max_age: int = 60 * 60 * 24 * 7 # seven days max_age: int = 60 * 60 * 24 * 7 # seven days
@ -59,7 +59,7 @@ class FaviconProxyConfig(BaseModel):
outgoing request of the resolver. By default, the value from outgoing request of the resolver. By default, the value from
:ref:`outgoing.request_timeout <settings outgoing>` setting is used.""" :ref:`outgoing.request_timeout <settings outgoing>` setting is used."""
resolver_map: dict[str, str] = _initial_resolver_map() resolver_map: dict[str, str] = msgspec.field(default_factory=_initial_resolver_map)
"""The resolver_map is a key / value dictionary where the key is the name of """The resolver_map is a key / value dictionary where the key is the name of
the resolver and the value is the fully qualifying name (fqn) of resolver's the resolver and the value is the fully qualifying name (fqn) of resolver's
function (the callable). The resolvers from the python module function (the callable). The resolvers from the python module

View File

@ -1,10 +1,10 @@
# SPDX-License-Identifier: AGPL-3.0-or-later # SPDX-License-Identifier: AGPL-3.0-or-later
# pylint: disable=invalid-name, missing-module-docstring, missing-class-docstring # pylint: disable=invalid-name, missing-module-docstring, missing-class-docstring
from __future__ import annotations
from __future__ import annotations from __future__ import annotations
from abc import abstractmethod, ABC from abc import abstractmethod, ABC
import re import re
from searx import settings from searx import settings
from searx.sxng_locales import sxng_locales from searx.sxng_locales import sxng_locales
from searx.engines import categories, engines, engine_shortcuts from searx.engines import categories, engines, engine_shortcuts
@ -272,16 +272,19 @@ class RawTextQuery:
self.specific = False self.specific = False
self.autocomplete_list = [] self.autocomplete_list = []
# internal properties # internal properties
self.query_parts = [] # use self.getFullQuery() self.query_parts = [] # use self.getFullQuery() or self.getNewFullQuery(query)
self.user_query_parts = [] # use self.getQuery() self.user_query_parts = [] # use self.getQuery()
self.autocomplete_location = None
self.redirect_to_first_result = False self.redirect_to_first_result = False
self._parse_query() self.autocomplete_location = self._parse_query()
def _parse_query(self): def _parse_query(self):
""" """
parse self.query, if tags are set, which parse self.query, if tags are set, which
change the search engine or search-language change the search engine or search-language
Returns a tuple:
[0] The query parts as a list
[1] The indexor into the above list
""" """
# split query, including whitespaces # split query, including whitespaces
@ -307,28 +310,33 @@ class RawTextQuery:
qlist.append(query_part) qlist.append(query_part)
last_index_location = (qlist, len(qlist) - 1) last_index_location = (qlist, len(qlist) - 1)
self.autocomplete_location = last_index_location return last_index_location
def get_autocomplete_full_query(self, text): def get_autocomplete_full_query(self, text: str) -> str:
assert self.autocomplete_location is not None
qlist, position = self.autocomplete_location qlist, position = self.autocomplete_location
qlist[position] = text qlist[position] = text
return self.getFullQuery() return self.getFullQuery()
def changeQuery(self, query): def getNewFullQuery(self, query: str):
self.user_query_parts = query.strip().split() """
self.query = self.getFullQuery() Generate a new FullQuery based on the input query rather than the internal
self.autocomplete_location = (self.user_query_parts, len(self.user_query_parts) - 1) user_query_parts
self.autocomplete_list = [] """
return self return RawTextQuery._getFullQuery(self.query_parts, query.strip())
def getQuery(self): def getQuery(self) -> str:
return ' '.join(self.user_query_parts) return ' '.join(self.user_query_parts)
def getFullQuery(self): def getFullQuery(self) -> str:
""" """
get full query including whitespaces Get full query including whitespaces
""" """
return '{0} {1}'.format(' '.join(self.query_parts), self.getQuery()).strip() return RawTextQuery._getFullQuery(self.query_parts, self.getQuery())
@staticmethod
def _getFullQuery(query_parts: list[str], query: str) -> str:
return '{0} {1}'.format(' '.join(query_parts), query).strip()
def __str__(self): def __str__(self):
return self.getFullQuery() return self.getFullQuery()

View File

@ -144,6 +144,7 @@ class EngineProcessor(ABC):
- A page-number > 1 when engine does not support paging. - A page-number > 1 when engine does not support paging.
- A time range when the engine does not support time range. - A time range when the engine does not support time range.
""" """
# if paging is not supported, skip # if paging is not supported, skip
if search_query.pageno > 1 and not self.engine.paging: if search_query.pageno > 1 and not self.engine.paging:
return None return None

View File

@ -39,7 +39,7 @@ msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-10-06 14:31+0000\n" "PO-Revision-Date: 2024-10-26 21:13+0000\n"
"Last-Translator: Atul_Eterno <Atul_Eterno@users.noreply.translate.codeberg." "Last-Translator: Atul_Eterno <Atul_Eterno@users.noreply.translate.codeberg."
"org>\n" "org>\n"
"Language-Team: Spanish <https://translate.codeberg.org/projects/searxng/" "Language-Team: Spanish <https://translate.codeberg.org/projects/searxng/"
@ -49,7 +49,7 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.7.2\n" "X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -155,7 +155,7 @@ msgstr "preguntas y respuestas"
#. CATEGORY_GROUPS['REPOS'] #. CATEGORY_GROUPS['REPOS']
#: searx/searxng.msg #: searx/searxng.msg
msgid "repos" msgid "repos"
msgstr "repos" msgstr "repositorios"
#. CATEGORY_GROUPS['SOFTWARE_WIKIS'] #. CATEGORY_GROUPS['SOFTWARE_WIKIS']
#: searx/searxng.msg #: searx/searxng.msg

View File

@ -22,13 +22,14 @@
# MVDW-Java <MVDW-Java@users.noreply.translate.codeberg.org>, 2024. # MVDW-Java <MVDW-Java@users.noreply.translate.codeberg.org>, 2024.
# notlmutsaers <notlmutsaers@users.noreply.translate.codeberg.org>, 2024. # notlmutsaers <notlmutsaers@users.noreply.translate.codeberg.org>, 2024.
# return42 <return42@users.noreply.translate.codeberg.org>, 2024. # return42 <return42@users.noreply.translate.codeberg.org>, 2024.
# ljansen <ljansen@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-10-15 12:18+0000\n" "PO-Revision-Date: 2024-10-28 21:07+0000\n"
"Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>\n" "Last-Translator: ljansen <ljansen@users.noreply.translate.codeberg.org>\n"
"Language-Team: Dutch <https://translate.codeberg.org/projects/searxng/" "Language-Team: Dutch <https://translate.codeberg.org/projects/searxng/"
"searxng/nl/>\n" "searxng/nl/>\n"
"Language: nl\n" "Language: nl\n"
@ -36,7 +37,7 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n" "Plural-Forms: nplurals=2; plural=n != 1;\n"
"X-Generator: Weblate 5.7.2\n" "X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -464,7 +465,7 @@ msgstr "Bereken {functions} van de opties"
#: searx/engines/mozhi.py:57 #: searx/engines/mozhi.py:57
msgid "Synonyms" msgid "Synonyms"
msgstr "" msgstr "Synoniemen"
#: searx/engines/openstreetmap.py:159 #: searx/engines/openstreetmap.py:159
msgid "Get directions" msgid "Get directions"
@ -1234,12 +1235,13 @@ msgid "Max time"
msgstr "Max. duur" msgstr "Max. duur"
#: searx/templates/simple/preferences/favicon.html:2 #: searx/templates/simple/preferences/favicon.html:2
#, fuzzy
msgid "Favicon Resolver" msgid "Favicon Resolver"
msgstr "" msgstr "favicon-resolver"
#: searx/templates/simple/preferences/favicon.html:15 #: searx/templates/simple/preferences/favicon.html:15
msgid "Display favicons near search results" msgid "Display favicons near search results"
msgstr "" msgstr "Vertoon zoekresultaten naast favicons"
#: searx/templates/simple/preferences/footer.html:2 #: searx/templates/simple/preferences/footer.html:2
msgid "" msgid ""

View File

@ -23,8 +23,8 @@ msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-10-15 12:18+0000\n" "PO-Revision-Date: 2024-10-28 21:07+0000\n"
"Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>\n" "Last-Translator: Eryk Michalak <gnu.ewm@protonmail.com>\n"
"Language-Team: Polish <https://translate.codeberg.org/projects/searxng/" "Language-Team: Polish <https://translate.codeberg.org/projects/searxng/"
"searxng/pl/>\n" "searxng/pl/>\n"
"Language: pl\n" "Language: pl\n"
@ -34,7 +34,7 @@ msgstr ""
"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (" "Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && ("
"n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && " "n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && "
"n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n" "n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
"X-Generator: Weblate 5.7.2\n" "X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -1230,7 +1230,7 @@ msgstr "Maksymalny czas"
#: searx/templates/simple/preferences/favicon.html:2 #: searx/templates/simple/preferences/favicon.html:2
msgid "Favicon Resolver" msgid "Favicon Resolver"
msgstr "" msgstr "Pobieranie favikony"
#: searx/templates/simple/preferences/favicon.html:15 #: searx/templates/simple/preferences/favicon.html:15
msgid "Display favicons near search results" msgid "Display favicons near search results"

View File

@ -19,13 +19,14 @@
# gvlx <gvlx@users.noreply.translate.codeberg.org>, 2024. # gvlx <gvlx@users.noreply.translate.codeberg.org>, 2024.
# ds451 <ds451@users.noreply.translate.codeberg.org>, 2024. # ds451 <ds451@users.noreply.translate.codeberg.org>, 2024.
# Pedro_Tresp <Pedro_Tresp@users.noreply.translate.codeberg.org>, 2024. # Pedro_Tresp <Pedro_Tresp@users.noreply.translate.codeberg.org>, 2024.
# saltsnorter <saltsnorter@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-10-13 23:26+0000\n" "PO-Revision-Date: 2024-10-29 05:54+0000\n"
"Last-Translator: Pedro_Tresp <Pedro_Tresp@users.noreply.translate.codeberg." "Last-Translator: saltsnorter <saltsnorter@users.noreply.translate.codeberg."
"org>\n" "org>\n"
"Language-Team: Portuguese <https://translate.codeberg.org/projects/searxng/" "Language-Team: Portuguese <https://translate.codeberg.org/projects/searxng/"
"searxng/pt/>\n" "searxng/pt/>\n"
@ -34,7 +35,7 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Weblate 5.7.2\n" "X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -175,7 +176,7 @@ msgstr "escuro"
#. STYLE_NAMES['BLACK'] #. STYLE_NAMES['BLACK']
#: searx/searxng.msg #: searx/searxng.msg
msgid "black" msgid "black"
msgstr "" msgstr "preto"
#. BRAND_CUSTOM_LINKS['UPTIME'] #. BRAND_CUSTOM_LINKS['UPTIME']
#: searx/searxng.msg #: searx/searxng.msg
@ -1228,11 +1229,11 @@ msgstr "Tempo máximo"
#: searx/templates/simple/preferences/favicon.html:2 #: searx/templates/simple/preferences/favicon.html:2
msgid "Favicon Resolver" msgid "Favicon Resolver"
msgstr "" msgstr "Solucionador do Favicon"
#: searx/templates/simple/preferences/favicon.html:15 #: searx/templates/simple/preferences/favicon.html:15
msgid "Display favicons near search results" msgid "Display favicons near search results"
msgstr "" msgstr "Monstra os favicons nos proximos os resultados"
#: searx/templates/simple/preferences/footer.html:2 #: searx/templates/simple/preferences/footer.html:2
msgid "" msgid ""

View File

@ -30,13 +30,14 @@
# Pyrbor <Pyrbor@users.noreply.translate.codeberg.org>, 2024. # Pyrbor <Pyrbor@users.noreply.translate.codeberg.org>, 2024.
# rodgui <rodgui@users.noreply.translate.codeberg.org>, 2024. # rodgui <rodgui@users.noreply.translate.codeberg.org>, 2024.
# rafablog77 <rafablog77@users.noreply.translate.codeberg.org>, 2024. # rafablog77 <rafablog77@users.noreply.translate.codeberg.org>, 2024.
# Juno Takano <jutty@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-10-15 12:18+0000\n" "PO-Revision-Date: 2024-10-31 12:16+0000\n"
"Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>\n" "Last-Translator: Juno Takano <jutty@users.noreply.translate.codeberg.org>\n"
"Language-Team: Portuguese (Brazil) <https://translate.codeberg.org/projects/" "Language-Team: Portuguese (Brazil) <https://translate.codeberg.org/projects/"
"searxng/searxng/pt_BR/>\n" "searxng/searxng/pt_BR/>\n"
"Language: pt_BR\n" "Language: pt_BR\n"
@ -44,7 +45,7 @@ msgstr ""
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n" "Plural-Forms: nplurals=2; plural=n > 1;\n"
"X-Generator: Weblate 5.7.2\n" "X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -185,7 +186,7 @@ msgstr "escuro"
#. STYLE_NAMES['BLACK'] #. STYLE_NAMES['BLACK']
#: searx/searxng.msg #: searx/searxng.msg
msgid "black" msgid "black"
msgstr "" msgstr "preto"
#. BRAND_CUSTOM_LINKS['UPTIME'] #. BRAND_CUSTOM_LINKS['UPTIME']
#: searx/searxng.msg #: searx/searxng.msg
@ -472,7 +473,7 @@ msgstr "Computar {functions} dos argumentos"
#: searx/engines/mozhi.py:57 #: searx/engines/mozhi.py:57
msgid "Synonyms" msgid "Synonyms"
msgstr "" msgstr "Sinônimos"
#: searx/engines/openstreetmap.py:159 #: searx/engines/openstreetmap.py:159
msgid "Get directions" msgid "Get directions"
@ -1243,7 +1244,7 @@ msgstr "Tempo máximo"
#: searx/templates/simple/preferences/favicon.html:2 #: searx/templates/simple/preferences/favicon.html:2
msgid "Favicon Resolver" msgid "Favicon Resolver"
msgstr "" msgstr "Resolvedor de Favicons"
#: searx/templates/simple/preferences/favicon.html:15 #: searx/templates/simple/preferences/favicon.html:15
msgid "Display favicons near search results" msgid "Display favicons near search results"

View File

@ -12,19 +12,19 @@
# tvminh19 <tvminh19@users.noreply.translate.codeberg.org>, 2024. # tvminh19 <tvminh19@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-08-07 01:02+0000\n" "PO-Revision-Date: 2024-10-26 21:13+0000\n"
"Last-Translator: tvminh19 <tvminh19@users.noreply.translate.codeberg.org>" "Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>\n"
"\n" "Language-Team: Vietnamese <https://translate.codeberg.org/projects/searxng/"
"searxng/vi/>\n"
"Language: vi\n" "Language: vi\n"
"Language-Team: Vietnamese "
"<https://translate.codeberg.org/projects/searxng/searxng/vi/>\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -186,7 +186,7 @@ msgstr "Nhiệt độ trung bình."
#. WEATHER_TERMS['CLOUD COVER'] #. WEATHER_TERMS['CLOUD COVER']
#: searx/engines/open_meteo.py:91 searx/searxng.msg #: searx/engines/open_meteo.py:91 searx/searxng.msg
msgid "Cloud cover" msgid "Cloud cover"
msgstr "" msgstr "Mây che phủ"
#. WEATHER_TERMS['CONDITION'] #. WEATHER_TERMS['CONDITION']
#: searx/engines/duckduckgo_weather.py:45 searx/engines/wttr.py:51 #: searx/engines/duckduckgo_weather.py:45 searx/engines/wttr.py:51
@ -283,7 +283,7 @@ msgstr ""
#: searx/engines/duckduckgo_weather.py:58 searx/engines/open_meteo.py:86 #: searx/engines/duckduckgo_weather.py:58 searx/engines/open_meteo.py:86
#: searx/engines/wttr.py:62 searx/searxng.msg #: searx/engines/wttr.py:62 searx/searxng.msg
msgid "Wind" msgid "Wind"
msgstr "" msgstr "Gió"
#. SOCIAL_MEDIA_TERMS['SUBSCRIBERS'] #. SOCIAL_MEDIA_TERMS['SUBSCRIBERS']
#: searx/engines/lemmy.py:85 searx/searxng.msg #: searx/engines/lemmy.py:85 searx/searxng.msg
@ -1990,4 +1990,3 @@ msgstr "ẩn phim"
#~ msgid "Engines cannot retrieve results" #~ msgid "Engines cannot retrieve results"
#~ msgstr "Các trình tìm kiếm không nhận được kết quả" #~ msgstr "Các trình tìm kiếm không nhận được kết quả"

View File

@ -28,18 +28,19 @@
# hugoalh <hugoalh@users.noreply.translate.codeberg.org>, 2024. # hugoalh <hugoalh@users.noreply.translate.codeberg.org>, 2024.
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: searx\n" "Project-Id-Version: searx\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-10-05 06:24+0000\n" "POT-Creation-Date: 2024-10-05 06:24+0000\n"
"PO-Revision-Date: 2024-08-12 04:00+0000\n" "PO-Revision-Date: 2024-10-26 21:13+0000\n"
"Last-Translator: hugoalh <hugoalh@users.noreply.translate.codeberg.org>\n" "Last-Translator: return42 <return42@users.noreply.translate.codeberg.org>\n"
"Language-Team: Chinese (Traditional Han script) <https://translate.codeberg."
"org/projects/searxng/searxng/zh_Hant/>\n"
"Language: zh_Hant_TW\n" "Language: zh_Hant_TW\n"
"Language-Team: Chinese (Traditional) "
"<https://translate.codeberg.org/projects/searxng/searxng/zh_Hant/>\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n" "Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 5.8.1\n"
"Generated-By: Babel 2.16.0\n" "Generated-By: Babel 2.16.0\n"
#. CONSTANT_NAMES['NO_SUBGROUPING'] #. CONSTANT_NAMES['NO_SUBGROUPING']
@ -180,7 +181,7 @@ msgstr "黑暗"
#. STYLE_NAMES['BLACK'] #. STYLE_NAMES['BLACK']
#: searx/searxng.msg #: searx/searxng.msg
msgid "black" msgid "black"
msgstr "" msgstr "黑色"
#. BRAND_CUSTOM_LINKS['UPTIME'] #. BRAND_CUSTOM_LINKS['UPTIME']
#: searx/searxng.msg #: searx/searxng.msg
@ -467,7 +468,7 @@ msgstr "計算 {functions} 參數"
#: searx/engines/mozhi.py:57 #: searx/engines/mozhi.py:57
msgid "Synonyms" msgid "Synonyms"
msgstr "" msgstr "同義詞"
#: searx/engines/openstreetmap.py:159 #: searx/engines/openstreetmap.py:159
msgid "Get directions" msgid "Get directions"
@ -942,7 +943,7 @@ msgstr "來自搜尋引擎的訊息"
#: searx/templates/simple/elements/engines_msg.html:7 #: searx/templates/simple/elements/engines_msg.html:7
msgid "seconds" msgid "seconds"
msgstr "" msgstr ""
#: searx/templates/simple/elements/search_url.html:3 #: searx/templates/simple/elements/search_url.html:3
msgid "Search URL" msgid "Search URL"
@ -1206,11 +1207,11 @@ msgstr "最大時間"
#: searx/templates/simple/preferences/favicon.html:2 #: searx/templates/simple/preferences/favicon.html:2
msgid "Favicon Resolver" msgid "Favicon Resolver"
msgstr "" msgstr "網站圖標搜索器"
#: searx/templates/simple/preferences/favicon.html:15 #: searx/templates/simple/preferences/favicon.html:15
msgid "Display favicons near search results" msgid "Display favicons near search results"
msgstr "" msgstr "在搜尋結果旁顯示網站圖標"
#: searx/templates/simple/preferences/footer.html:2 #: searx/templates/simple/preferences/footer.html:2
msgid "" msgid ""
@ -1911,4 +1912,3 @@ msgstr "隱藏影片"
#~ msgid "Engines cannot retrieve results" #~ msgid "Engines cannot retrieve results"
#~ msgstr "引擎無法擷取結果" #~ msgstr "引擎無法擷取結果"

View File

@ -753,14 +753,14 @@ def search():
# suggestions: use RawTextQuery to get the suggestion URLs with the same bang # suggestions: use RawTextQuery to get the suggestion URLs with the same bang
suggestion_urls = list( suggestion_urls = list(
map( map(
lambda suggestion: {'url': raw_text_query.changeQuery(suggestion).getFullQuery(), 'title': suggestion}, lambda suggestion: {'url': raw_text_query.getNewFullQuery(suggestion), 'title': suggestion},
result_container.suggestions, result_container.suggestions,
) )
) )
correction_urls = list( correction_urls = list(
map( map(
lambda correction: {'url': raw_text_query.changeQuery(correction).getFullQuery(), 'title': correction}, lambda correction: {'url': raw_text_query.getNewFullQuery(correction), 'title': correction},
result_container.corrections, result_container.corrections,
) )
) )
@ -851,10 +851,8 @@ def autocompleter():
backend_name = request.preferences.get_value('autocomplete') backend_name = request.preferences.get_value('autocomplete')
for result in search_autocomplete(backend_name, sug_prefix, sxng_locale): for result in search_autocomplete(backend_name, sug_prefix, sxng_locale):
# attention: this loop will change raw_text_query object and this is
# the reason why the sug_prefix was stored before (see above)
if result != sug_prefix: if result != sug_prefix:
results.append(raw_text_query.changeQuery(result).getFullQuery()) results.append(raw_text_query.getNewFullQuery(result))
if len(raw_text_query.autocomplete_list) > 0: if len(raw_text_query.autocomplete_list) > 0:
for autocomplete_text in raw_text_query.autocomplete_list: for autocomplete_text in raw_text_query.autocomplete_list:

View File

@ -51,12 +51,19 @@ class TestQuery(SearxTestCase): # pylint:disable=missing-class-docstring
r = repr(query) r = repr(query)
self.assertTrue(r.startswith(f"<RawTextQuery query='{query_text}' ")) self.assertTrue(r.startswith(f"<RawTextQuery query='{query_text}' "))
def test_change_query(self): def test_get_new_full_query(self):
query_text = '<8 the query' query_text = '<8 the query'
query = RawTextQuery(query_text, []) query = RawTextQuery(query_text, [])
another_query = query.changeQuery('another text') full_query = query.getFullQuery()
self.assertEqual(query, another_query) new_full_query = query.getNewFullQuery('another text')
self.assertEqual(query.getFullQuery(), '<8 another text') self.assertNotEqual(full_query, new_full_query)
def test_get_new_full_query_trim(self):
query_text = 'foo bar'
query = RawTextQuery(query_text, [])
new_query = 'bizz bazz'
new_full_query = query.getNewFullQuery(" " + new_query + " ")
self.assertEqual(new_query, new_full_query)
class TestLanguageParser(SearxTestCase): # pylint:disable=missing-class-docstring class TestLanguageParser(SearxTestCase): # pylint:disable=missing-class-docstring